@swell/cli 2.0.1-alpha.0 → 2.0.1-alpha.11

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.
package/README.md CHANGED
@@ -1,141 +1,3 @@
1
- # @swell/cli
1
+ # @swell/cli 2 alpha
2
2
 
3
- #We're in beta: commands and arguments can still change.#
4
-
5
- Install with:
6
-
7
- ```sh
8
- npm install -g @swell/cli
9
- ```
10
-
11
- If you are using tools for version managing like [asdf](https://asdf-vm.com/), make sure you [reshim](https://asdf-vm.com/manage/core.html#reshim) after install:
12
-
13
- ```sh
14
- asdf reshim
15
- ```
16
-
17
- # Commands
18
-
19
- ## General options
20
-
21
- Commands tend to support the following helper options:
22
-
23
- - --quiet (-q): Boolean, quiets the progress indicator and output of intermediary commands
24
- - --verbose (-v): Boolean, outputs all commands
25
- - --dry-run: Boolean, dry runs requests that delete data, but doesn't run them
26
- - --yes (-y): Boolean, answers all confirmation questions with **yes**.
27
-
28
- ## Login
29
-
30
- The `admin login` command authenticates and stores a user's session locally. Saved sessions can/will be used by other commands, unless a secret key is specified.
31
-
32
- ```sh
33
- swell login [--username (-u) String] [--password (-p) String] [--set-default Boolean]
34
- ```
35
-
36
- ### Examples
37
-
38
- ```sh
39
- swell login
40
- swell login --set-default
41
- ```
42
-
43
- ## Storefronts
44
-
45
- List all storefronts associated to logged in user:
46
-
47
- ```sh
48
- swell storefronts list
49
- ```
50
-
51
- Retrieves storefront configuration data from the server and writes it to a file if specified or stdout by default. It requires a type to run. Configuration types allowed are "editor", "menus" and "settings":
52
- ```sh
53
- swell storefronts pull --id String --type (-t) String [--file (-f) String]
54
- ```
55
-
56
- Send storefront configuration data to the server. Configuration types allowed are "editor", "menus" and "settings":
57
- ```sh
58
- swell storefronts push --id String --type (-t) String [--file (-f) String] [--strategy (-i) String]
59
- ```
60
-
61
- ### Examples
62
-
63
- ```sh
64
- swell storefronts pull --id P5OzfzLD -t editor
65
- swell storefronts pull --id P5OzfzLD -t menus -f menus.json
66
- swell storefronts push --id P5OzfzLD -t editor -s set -f ../origin-storefront/config/editor.json
67
- ```
68
-
69
- ### Without logging in
70
-
71
- ```sh
72
- swell storefronts pull --id P5OzfzLD -t editor --store my-test-store --secret-key my-dev-secret-key
73
- swell storefronts pull --id P5OzfzLD -t menus -f menus.json --store my-test-store --secret-key my-dev-secret-key
74
- swell storefronts push --id P5OzfzLD -t editor -s set -f ../origin-storefront/config/editor.json --store my-test-store --secret-key my-dev-secret-key
75
- ```
76
-
77
- ## Model
78
-
79
- Push or pull model definitions, including namespaced models (e.g. content models), abstract content models and content fields.
80
-
81
- ```sh
82
- # pull => retrieves a model from the server and tries to merge and/or write to a specified JSON file or stdout (by default)
83
- # --content flag toggles between base models and abstract content models or content fields
84
- swell model pull -m MODEL_ID [--file (-f) String] [--strategy (-s) String] [--content Boolean]
85
-
86
- # push => send a model definition from a JSON file or stdin to the server
87
- swell model push [--file (-f) String] [--input (-i) stdin] [--content Boolean]
88
- ```
89
-
90
- It is important that the model definition includes some fields depending on the type/source of the model.
91
-
92
- #### Basic model
93
-
94
- ```json
95
- {
96
- "name": "Test", // slug will be assumed from this field
97
- "slug": "test_model", // or you can define one explicitly
98
- "fields": { ... }
99
- }
100
- ```
101
-
102
- #### Namespaced model
103
-
104
- ```json
105
- {
106
- "name": "Page", // slug will be assumed from this field
107
- "namespace": "content",
108
- "fields": { ... }
109
- }
110
- ```
111
-
112
- #### Theme content (abstract) model/fields (use with --content flag)
113
-
114
- ```json
115
- {
116
- "name": "Test", // slug will be assumed from this field
117
- "fields": { ... },
118
- "source_type": "theme",
119
- "source_id": "origin"
120
- }
121
- ```
122
-
123
- ### Examples
124
-
125
- ```sh
126
- swell model pull -m products # pull products model and display in stdout
127
- swell model pull -m theme.origin.page --content -f models/page.json # pull a content model and save it to a file
128
-
129
- swell model push -f models/orders.json
130
- swell model push -c -f models/page.json # push a content model
131
- ```
132
-
133
- ### Without logging in
134
-
135
- ```sh
136
- swell model pull -m products --store my-test-store --secret-key my-dev-secret-key
137
- swell model pull -m theme.origin.page --content -f models/page.json --store my-test-store --secret-key my-dev-secret-key
138
-
139
- swell model push -f models/orders.json --store my-test-store --secret-key my-dev-secret-key
140
- swell model push -c -f models/page.json --store my-test-store --secret-key my-dev-secret-key
141
- ```
3
+ Find the alpha docs at https://www.notion.so/swellcorp/CLI-reference-c3553ebb3de24d94becbedf95a5a25d8?pvs=4
@@ -1,9 +1,9 @@
1
1
  import { Args } from '@oclif/core';
2
2
  import { dasherize, pluralize, underscore } from 'inflection';
3
- import snakeCase from 'lodash/snakeCase.js';
4
3
  import * as path from 'node:path';
5
4
  import { newConfig } from '../../lib/app-config.js';
6
5
  import { ConfigPaths, writeJsonFile, } from '../../lib/apps/index.js';
6
+ import { toAppId } from '../../lib/create/index.js';
7
7
  import style from '../../lib/style.js';
8
8
  import { RemoteAppCommand } from '../../remote-app-command.js';
9
9
  export default class AppPull extends RemoteAppCommand {
@@ -25,7 +25,7 @@ export default class AppPull extends RemoteAppCommand {
25
25
  const config = newConfig();
26
26
  const appConfigJson = {
27
27
  description: this.app.description || '',
28
- id: snakeCase(this.app.name),
28
+ id: toAppId(this.app.name),
29
29
  name: this.app.name,
30
30
  version: this.app.version,
31
31
  };
@@ -47,7 +47,7 @@ it will output all versions of the app instead.`;
47
47
  const spinner = ora();
48
48
  spinner.start('Retrieving app info...');
49
49
  this.app = await this.getAppWithConfig().catch((error) => {
50
- spinner.fail(`Error fetching app info: ${JSON.stringify(this.app)}`);
50
+ spinner.fail(`Error fetching app info:`);
51
51
  throw error;
52
52
  });
53
53
  if (spinner.isSpinning) {
@@ -93,7 +93,8 @@ Without a store specified, install the app in the Live environment of the curren
93
93
  else {
94
94
  extraMessage = ` ${style.appConfigValue(this.app.name)} v${versionToInstall} on ${style.storeId(storeToInstall)} [${envToInstall ? envToInstall : 'live'}]`;
95
95
  }
96
- const shouldContinue = await this.confirmRemoveDevelopmentApp(storeToInstall);
96
+ const shouldContinue = existingVersion ||
97
+ (await this.confirmRemoveDevelopmentApp(storeToInstall));
97
98
  if (!shouldContinue) {
98
99
  return;
99
100
  }
@@ -148,6 +149,7 @@ Without a store specified, install the app in the Live environment of the curren
148
149
  query: { source_id: this.app.id },
149
150
  });
150
151
  if (existingSourcedApps.results[0]?.id) {
152
+ console.log(existingSourcedApps.results[0]);
151
153
  const continueInstall = await confirm({
152
154
  message: `${style.storeId(storeToInstall)} has a development version of ${style.appConfigValue(this.app.name)}. Do you want to replace it with an installed instance?`,
153
155
  default: false,
@@ -2,6 +2,9 @@ import { RemoteAppCommand } from '../../remote-app-command.js';
2
2
  export default class AppPush extends RemoteAppCommand {
3
3
  static description: string;
4
4
  static examples: string[];
5
+ static args: {
6
+ file: import("@oclif/core/lib/interfaces/parser.js").Arg<string | undefined, Record<string, unknown>>;
7
+ };
5
8
  static flags: {
6
9
  file: import("@oclif/core/lib/interfaces/parser.js").OptionFlag<string | undefined, import("@oclif/core/lib/interfaces/parser.js").CustomOptions>;
7
10
  };
@@ -1,5 +1,5 @@
1
1
  import { confirm } from '@inquirer/prompts';
2
- import { Flags } from '@oclif/core';
2
+ import { Flags, Args } from '@oclif/core';
3
3
  import * as path from 'node:path';
4
4
  import ora from 'ora';
5
5
  import { appConfigFileExists } from '../../lib/app-config.js';
@@ -26,6 +26,13 @@ ${Object.values(ConfigPaths)
26
26
  'swell app push -f content',
27
27
  'swell app push -f models/products.json',
28
28
  ];
29
+ static args = {
30
+ file: Args.string({
31
+ char: 'f',
32
+ description: 'relative path to a configuration file or directory to push',
33
+ }),
34
+ };
35
+ // Deprecating the flags in favor of args
29
36
  static flags = {
30
37
  file: Flags.string({
31
38
  char: 'f',
@@ -37,20 +44,25 @@ ${Object.values(ConfigPaths)
37
44
  };
38
45
  static summary = 'Push configuration files to your Swell app.';
39
46
  async run() {
40
- const { flags } = await this.parse(AppPush);
41
- const { file } = flags;
47
+ const { args, flags } = await this.parse(AppPush);
48
+ const { file: fileArg } = args;
49
+ const { file: fileFlag } = flags;
50
+ const file = fileArg || fileFlag;
42
51
  const currentStore = swellConfig.getDefaultStore();
43
52
  this.api.setStoreEnv(currentStore, 'test');
44
- this.app = await this.getAppWithConfig(undefined, false);
53
+ this.app = await this.getAppWithConfig('', false);
45
54
  const confirmExistingApp = await this.confirmRemoveInstalledApp(currentStore);
46
55
  if (confirmExistingApp === false) {
47
56
  return;
48
57
  }
49
58
  // If app exists but owned by another client, offer to create a new instance
50
- if (this.app.client_id !== currentStore) {
59
+ if (this.app.client_id && this.app.client_id !== currentStore) {
51
60
  if (!confirmExistingApp?.id) {
61
+ const otherAppName = this.app.name || this.appConfig.get('name');
52
62
  const confirmPushNew = await confirm({
53
- message: `${style.appConfigValue(this.app.name)} has a dev version in another store (${style.storeId(this.app.client_id)}). Do you want to create a new development instance in ${style.storeId(currentStore)}?`,
63
+ message: `${style.appConfigValue(otherAppName)} has a dev version in another ${this.app.client_id
64
+ ? `store ${style.dim(`(${this.app.client_id})`)}`
65
+ : 'environment'}. Do you want to create a new development instance in ${style.storeId(currentStore)}?`,
54
66
  default: false,
55
67
  });
56
68
  if (!confirmPushNew) {
@@ -18,6 +18,7 @@ export default class Logs extends SwellCommand {
18
18
  static summary: string;
19
19
  private output;
20
20
  run(): Promise<void>;
21
+ __run(): Promise<void>;
21
22
  private getLogs;
22
23
  private getLogsAndWriteToStream;
23
24
  }
@@ -1,4 +1,5 @@
1
1
  import { Flags } from '@oclif/core';
2
+ import ora from 'ora';
2
3
  import { LineOutput, LoggedItem, TableOutput } from '../lib/logs/index.js';
3
4
  import { SwellCommand } from '../swell-command.js';
4
5
  // the columns available to display in the table
@@ -162,6 +163,10 @@ export default class Logs extends SwellCommand {
162
163
  static summary = 'Output or stream store logs to the terminal.';
163
164
  output;
164
165
  async run() {
166
+ const spinner = ora();
167
+ spinner.fail('This command is temporarily disabled. Check back soon.');
168
+ }
169
+ async __run() {
165
170
  const { flags } = await this.parse(Logs);
166
171
  // indentify the columns to display
167
172
  const columns = flags.columns.split(',');
package/dist/lib/api.js CHANGED
@@ -65,8 +65,17 @@ export default class Api {
65
65
  throw new Error('Operation not supported.');
66
66
  const resp = await fetch(path, fetchOptions);
67
67
  const respData = await resp.text();
68
- if (!resp.ok)
69
- throw new Error(respData);
68
+ if (!resp.ok) {
69
+ // Try to parse error message
70
+ let errorJson;
71
+ try {
72
+ errorJson = JSON.parse(respData);
73
+ }
74
+ catch {
75
+ // ignore
76
+ }
77
+ throw new Error(errorJson?.error?.message || errorJson?.error || respData);
78
+ }
70
79
  try {
71
80
  return JSON.parse(respData);
72
81
  }
@@ -68,9 +68,12 @@ class AppConfig {
68
68
  }
69
69
  }
70
70
  async postData() {
71
- if (!this.localPath || !this.fileData) {
71
+ if (!this.localPath) {
72
72
  throw new Error('Missing local config path');
73
73
  }
74
+ if (!this.fileData) {
75
+ return;
76
+ }
74
77
  if (this.localPath.endsWith('.json')) {
75
78
  try {
76
79
  this.values = JSON.parse(this.fileData);
@@ -22,6 +22,9 @@ export async function bundleFunction(filePath) {
22
22
  ? line.replace('module.exports', 'var moduleExports')
23
23
  : line)
24
24
  .join('\n');
25
+ // Remove comments with to get a unique hash in the API
26
+ // Because esbuild puts the file name as a comment
27
+ code = code.replace(/^[\n]?\/\/.*/gm, '');
25
28
  // eslint-disable-next-line no-new-func
26
29
  const evalFn = new Function(`${code}\nreturn { ...moduleExports }`);
27
30
  const { config, ...moduleExports } = evalFn();
@@ -13,5 +13,5 @@ export function getAdminApiBaseUrl(storeId) {
13
13
  return ADMIN_API_BASE_URL.replace('${STORE_ID}', storeId);
14
14
  }
15
15
  export function getLoginHost(storeId) {
16
- return LOGIN_HOST.replace('${STORE_ID}', storeId || 'app');
16
+ return LOGIN_HOST.replace('${STORE_ID}', storeId || 'login');
17
17
  }
@@ -5,7 +5,7 @@ interface CreateFileParams {
5
5
  }
6
6
  declare const toFileName: (value: string) => string;
7
7
  declare const toAppName: (value: string) => string;
8
- declare const toAppId: (value: string) => string;
8
+ declare const toAppId: (value: string | undefined) => string;
9
9
  declare const toFunctionFileName: (value: string) => string;
10
10
  declare const toCollectionName: (value: string) => string;
11
11
  declare const toCollectionLabel: (value: string) => string;
@@ -4,9 +4,11 @@ const toFileName = (value) => dasherize(underscore(value.split('.')[0].replace('
4
4
  // Example: 'my-things' => 'My Things'
5
5
  const toAppName = (value) => pluralize(titleize(value).replace('-', ' '));
6
6
  // Example: 'My App' => 'my_app'
7
- const toAppId = (value) => value
8
- .replace(/[^a-z0-9]+/gi, '_')
9
- .replace(/^\_|\_$/g, '')
7
+ const toAppId = (value) => String(value || '')
8
+ .replace(/[^a-zA-Z0-9\-_\s:\.\/]/g, '')
9
+ .replace(/[_\s-:\.\/]+/g, '_')
10
+ .replace(/^[_]+|[_]+$/g, '')
11
+ .replace(/([a-z])([A-Z])/g, '$1_$2')
10
12
  .toLowerCase();
11
13
  // Example: 'My Thing' => 'my-thing'
12
14
  // And: 'myThing' => 'myThing'
@@ -1,11 +1,11 @@
1
1
  import { inflect } from 'inflection';
2
- import snakeCase from 'lodash/snakeCase.js';
3
2
  import * as fs from 'node:fs';
4
3
  import * as path from 'node:path';
5
4
  import ora from 'ora';
6
5
  import { AppCommand } from './app-command.js';
7
6
  import { appConfigFileExists, readRcFile, writeRcFile, } from './lib/app-config.js';
8
7
  import { FunctionProcessingError, IgnoringFileError, allConfigFilesPaths, appConfigFromFile, appLogoIcon, batchAppConfigsByType, configFilePath, isAppLogoIcon, } from './lib/apps/index.js';
8
+ import { toAppId } from './lib/create/index.js';
9
9
  import { default as swellConfig } from './lib/config.js';
10
10
  import { getLoginHost } from './lib/constants.js';
11
11
  import style from './lib/style.js';
@@ -64,7 +64,7 @@ export class RemoteAppCommand extends AppCommand {
64
64
  this.error(`App ${style.appConfigName('id')} is not defined in swell.json.`);
65
65
  }
66
66
  if (privateId !== appConfigId) {
67
- this.error(`App ${style.appConfigName('id')} must be defined in snake_case: ${style.appConfigValue(appConfigId)}.`);
67
+ this.error(`App ${style.appConfigName('id')} must be declared in snake_case: ${style.appConfigValue(appConfigId)}.`);
68
68
  }
69
69
  appId = privateId;
70
70
  }
@@ -97,7 +97,7 @@ export class RemoteAppCommand extends AppCommand {
97
97
  : errorJson.error.message;
98
98
  this.error(errorMessage);
99
99
  }
100
- if (swellId) {
100
+ if (swellId && swellId !== id && swellId !== this.app?.id) {
101
101
  app = await this.getAppWithConfig(swellId);
102
102
  }
103
103
  }
@@ -105,7 +105,15 @@ export class RemoteAppCommand extends AppCommand {
105
105
  }
106
106
  async getCreateUpdateApp(updateApp) {
107
107
  const spinner = ora();
108
- const remoteApp = await readRcFile(this.swellRcPath());
108
+ let remoteApp;
109
+ try {
110
+ remoteApp = await readRcFile(this.swellRcPath());
111
+ }
112
+ catch (error) {
113
+ if (error.code !== 'ENOENT') {
114
+ throw error;
115
+ }
116
+ }
109
117
  /* eslint-disable camelcase */
110
118
  const body = {
111
119
  ...this.appConfig.store,
@@ -113,7 +121,9 @@ export class RemoteAppCommand extends AppCommand {
113
121
  // when posting to the API
114
122
  id: undefined,
115
123
  logo_icon: null,
116
- private_id: this.app?.private_id,
124
+ ...(this.appConfig.store.id
125
+ ? { private_id: this.appConfig.store.id }
126
+ : undefined),
117
127
  ...(remoteApp?.id ? { source_id: remoteApp.id } : undefined),
118
128
  };
119
129
  const logoIcon = appLogoIcon(this.appPath);
@@ -126,17 +136,23 @@ export class RemoteAppCommand extends AppCommand {
126
136
  let appCreated = false;
127
137
  if (!app.id) {
128
138
  // May already have a dev instance
129
- const existingDevApp = await this.api.get({
130
- adminPath: `/apps/${this.app?.private_id}`,
131
- });
139
+ let existingDevApp;
140
+ try {
141
+ existingDevApp = await this.api.get({
142
+ adminPath: `/apps/${this.appConfig.store.id}`,
143
+ });
144
+ }
145
+ catch (err) {
146
+ // noop
147
+ }
132
148
  spinner.start(`Creating app...`);
133
149
  if (existingDevApp) {
134
150
  app = await this.handleRequestErrors(async () => this.api.put({ adminPath: `/apps/${existingDevApp.id}` }, { body }), () => spinner.fail('Error creating app'));
135
151
  }
136
152
  else {
137
153
  app = await this.handleRequestErrors(async () => this.api.post({ adminPath: '/apps' }, { body }), () => spinner.fail('Error creating app'));
154
+ appCreated = true;
138
155
  }
139
- appCreated = true;
140
156
  }
141
157
  else if (app.id) {
142
158
  spinner.start(`Updating app...`);
@@ -220,6 +236,10 @@ export class RemoteAppCommand extends AppCommand {
220
236
  spinner.start(`Pushing ${pathDesc}`);
221
237
  try {
222
238
  postData = await appConfig.postData();
239
+ if (!postData) {
240
+ spinner.stop();
241
+ return;
242
+ }
223
243
  }
224
244
  catch (error) {
225
245
  if (error instanceof IgnoringFileError) {
@@ -327,8 +347,9 @@ export class RemoteAppCommand extends AppCommand {
327
347
  }
328
348
  }
329
349
  if (this.appConfig.get('id')) {
350
+ // use the same formula as the backend api
330
351
  // eslint-disable-next-line camelcase
331
- remoteApp.private_id = snakeCase(this.appConfig.get('id'));
352
+ remoteApp.private_id = toAppId(this.appConfig.get('id'));
332
353
  }
333
354
  return remoteApp;
334
355
  }
@@ -452,7 +452,12 @@
452
452
  },
453
453
  "app:push": {
454
454
  "aliases": [],
455
- "args": {},
455
+ "args": {
456
+ "file": {
457
+ "description": "relative path to a configuration file or directory to push",
458
+ "name": "file"
459
+ }
460
+ },
456
461
  "description": "Push all app configurations, a specific file, or a specific configuration\ntype to an app in your store's test environment. If the app does not exist yet,\nit will be created and its global ID saved to a .swellrc file.\n\n- If no file is specified, all configuration files will be pushed to the store.\n This includes the app icon (assets/icon.png) and swell.json.\n- If a file is specified, only that file will be pushed to the store.\n- If a directory is specified, only files in that directory will be pushed.\n\nApp configuration directories:\nassets/\ncontent/\nfunctions/\nmodels/\nnotifications/\nsettings/\nwebhooks/",
457
462
  "examples": [
458
463
  "swell app push",
@@ -1081,5 +1086,5 @@
1081
1086
  ]
1082
1087
  }
1083
1088
  },
1084
- "version": "2.0.1-alpha.0"
1089
+ "version": "2.0.1-alpha.11"
1085
1090
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@swell/cli",
3
- "version": "2.0.1-alpha.0",
3
+ "version": "2.0.1-alpha.11",
4
4
  "type": "module",
5
5
  "description": "Swell's command line interface/utility",
6
6
  "keywords": [
@@ -26,27 +26,28 @@
26
26
  "/oclif.manifest.json"
27
27
  ],
28
28
  "dependencies": {
29
+ "@inquirer/prompts": "3.2.0",
29
30
  "@npmcli/git": "5.0.3",
30
31
  "@oclif/core": "3.7.1",
32
+ "@oclif/errors": "1.3.6",
31
33
  "@oclif/plugin-help": "6.0.4",
32
34
  "@oclif/plugin-plugins": "3.9.4",
35
+ "chalk": "5.3.0",
33
36
  "conf": "11.0.2",
34
37
  "configstore": "6.0.0",
38
+ "esbuild": "0.19.5",
35
39
  "inflection": "3.0.0",
40
+ "lodash": "4.17.21",
36
41
  "node-fetch": "3.3.2",
37
42
  "oclif": "4.0.3",
38
43
  "open": "9.1.0",
44
+ "ora": "7.0.1",
39
45
  "semver": "7.5.4",
40
46
  "table": "6.8.1"
41
47
  },
42
48
  "devDependencies": {
43
- "@inquirer/prompts": "3.2.0",
44
49
  "@inquirer/testing": "2.1.8",
45
- "@oclif/errors": "1.3.6",
46
50
  "@oclif/test": "3.0.3",
47
- "@rollup/plugin-commonjs": "25.0.7",
48
- "@rollup/plugin-json": "6.0.1",
49
- "@rollup/plugin-node-resolve": "15.2.3",
50
51
  "@types/chai": "4.3.9",
51
52
  "@types/configstore": "6.0.1",
52
53
  "@types/inquirer": "9.0.6",
@@ -54,30 +55,20 @@
54
55
  "@types/node": "20.8.8",
55
56
  "@typescript-eslint/eslint-plugin": "6.9.0",
56
57
  "chai": "4.3.10",
57
- "chalk": "5.3.0",
58
- "configstore": "6.0.0",
59
58
  "dotenv": "16.3.1",
60
- "esbuild": "0.19.5",
61
59
  "eslint": "8.52.0",
62
60
  "eslint-config-oclif": "5.0.0",
63
61
  "eslint-config-oclif-typescript": "3.0.8",
64
62
  "eslint-config-prettier": "9.0.0",
65
63
  "eslint-plugin-prettier": "5.0.1",
66
64
  "eslint-plugin-unicorn": "48.0.1",
67
- "list-it": "1.3.12",
68
- "lodash": "4.17.21",
69
65
  "mocha": "10.2.0",
70
66
  "nock": "13.3.6",
71
- "npm-decode": "1.4.2",
72
67
  "oclif": "4.0.3",
73
- "ora": "7.0.1",
74
- "rollup": "4.1.4",
75
68
  "shx": "0.3.4",
76
69
  "testdouble": "3.20.0",
77
70
  "ts-node": "10.9.1",
78
- "tslib": "2.6.2",
79
- "typescript": "5.2.2",
80
- "uvu": "0.5.6"
71
+ "typescript": "5.2.2"
81
72
  },
82
73
  "oclif": {
83
74
  "bin": "swell",
@@ -103,7 +94,7 @@
103
94
  "posttest": "npm run lint",
104
95
  "prepack": "npm run build && oclif manifest && oclif readme",
105
96
  "test": "mocha --forbid-only \"test/**/*.test.ts\"",
106
- "version": "oclif readme && git add README.md"
97
+ "publish-alpha": "npm version prerelease --preid=alpha && npm publish --tag alpha"
107
98
  },
108
99
  "engines": {
109
100
  "node": ">= 18.16.1"