puter-cli 1.5.3 → 1.5.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/.env.example ADDED
@@ -0,0 +1,3 @@
1
+ # Default Puter's API
2
+ PUTER_API_BASE='https://api.puter.com'
3
+ PUTER_BASE_URL='https://puter.com'
package/CHANGELOG.md CHANGED
@@ -4,8 +4,24 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
+ #### [v1.5.5](https://github.com/HeyPuter/puter-cli/compare/v1.5.4...v1.5.5)
8
+
9
+ - fix: improve error handling [`d1fa91d`](https://github.com/HeyPuter/puter-cli/commit/d1fa91db09f08238c6be684ffe4688a0064f06cd)
10
+
11
+ #### [v1.5.4](https://github.com/HeyPuter/puter-cli/compare/v1.5.3...v1.5.4)
12
+
13
+ > 13 February 2025
14
+
15
+ - Remove "subdomain deletion" under Known Issues in README.md [`#8`](https://github.com/HeyPuter/puter-cli/pull/8)
16
+ - dev: add last-error command, context, and modules [`#7`](https://github.com/HeyPuter/puter-cli/pull/7)
17
+ - fix: delete a subdomain error message [`ed676dc`](https://github.com/HeyPuter/puter-cli/commit/ed676dc9d1364fabf242098e142a84c305dff177)
18
+ - ci: fix timezone issue [`8ee6a66`](https://github.com/HeyPuter/puter-cli/commit/8ee6a66db36f7ca00eb81a12c8bac094e057f534)
19
+ - ci: simplify timezone check [`ecf3bb9`](https://github.com/HeyPuter/puter-cli/commit/ecf3bb98bec5c093c23772280e3ee52aab8f3e8f)
20
+
7
21
  #### [v1.5.3](https://github.com/HeyPuter/puter-cli/compare/v1.5.2...v1.5.3)
8
22
 
23
+ > 7 February 2025
24
+
9
25
  - refactor: early return in fallback behavior [`#6`](https://github.com/HeyPuter/puter-cli/pull/6)
10
26
  - fix: ignore undefined appDir when listing sites [`#5`](https://github.com/HeyPuter/puter-cli/pull/5)
11
27
  - fix: use array args when calling DeleteSubdomain [`#4`](https://github.com/HeyPuter/puter-cli/pull/4)
package/README.md CHANGED
@@ -273,7 +273,12 @@ If you want to customize this tool you can follow these steps:
273
273
  ```bash
274
274
  npm install
275
275
  ```
276
- 3. Link the CLI globally:
276
+ 3. Set your own variable environnements:
277
+ ```
278
+ cp .env.example .env
279
+ # update your own values in .env file
280
+ ```
281
+ 4. Link the CLI globally:
277
282
  ```bash
278
283
  npm link
279
284
  ```
@@ -282,15 +287,7 @@ If you want to customize this tool you can follow these steps:
282
287
 
283
288
  ## Known issues:
284
289
 
285
- Most of the functionalities are just working fine, however, some APIs related to Puter's SDK have some known issues. We tried to fix most of them but some of them are not related to us, so we let you about that in case it'll be fixed by Puter's in the future:
286
-
287
- ## Delete a subdomain
288
- When you try to delete a subdomain which you own, you'll get `Permission denied`:
289
- ```bash
290
- Failed to delete subdomain: Permission denied.
291
- Site ID: "sd-b019b654-e06f-48a8-917e-ae1e83825ab7" may already be deleted!
292
- ```
293
- However, the query is executed successfully in the cloud and the subdomain is actually deleted.
290
+ Most features are working fine. If you have any issues with this project or the Puter SDK, please let us know:
294
291
 
295
292
  ## Interactive Shell prompt:
296
293
  If you want to stay in the interactive shell you should provide "-f" (aka: force delete) argument, when want to delete any object:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "puter-cli",
3
- "version": "1.5.3",
3
+ "version": "1.5.5",
4
4
  "description": "Command line interface for Puter cloud platform",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -10,10 +10,10 @@
10
10
  "type": "module",
11
11
  "scripts": {
12
12
  "start": "node bin/index.js",
13
- "test": "vitest run tests/*",
14
- "test:watch": "vitest --watch tests/*",
13
+ "test": "TZ=UTC vitest run tests/*",
14
+ "test:watch": "TZ=UTC vitest --watch tests/*",
15
15
  "version": "auto-changelog -p && git add CHANGELOG.md",
16
- "coverage": "vitest run --coverage"
16
+ "coverage": "TZ=UTC vitest run --coverage"
17
17
  },
18
18
  "engines": {
19
19
  "node": ">=18.0.0"
@@ -26,11 +26,13 @@
26
26
  "author": "Ibrahim.H",
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
+ "@heyputer/putility": "^1.0.2",
29
30
  "chalk": "^5.3.0",
30
31
  "cli-table3": "^0.6.5",
31
32
  "commander": "^13.0.0",
32
33
  "conf": "^12.0.0",
33
34
  "cross-spawn": "^7.0.3",
35
+ "dotenv": "^16.4.7",
34
36
  "glob": "^11.0.0",
35
37
  "inquirer": "^9.2.12",
36
38
  "minimatch": "^10.0.1",
@@ -4,6 +4,8 @@ import Conf from 'conf';
4
4
  import { execCommand, getPrompt } from '../executor.js';
5
5
  import { getAuthToken, login } from './auth.js';
6
6
  import { PROJECT_NAME } from '../commons.js';
7
+ import ErrorModule from '../modules/ErrorModule.js';
8
+ import putility, { AdvancedBase } from '@heyputer/putility';
7
9
 
8
10
  const config = new Conf({ projectName: PROJECT_NAME });
9
11
 
@@ -32,6 +34,16 @@ export async function startShell() {
32
34
  process.exit(0);
33
35
  }
34
36
 
37
+ const modules = [
38
+ ErrorModule,
39
+ ];
40
+
41
+ const context = new putility.libs.context.Context({
42
+ events: new putility.libs.event.Emitter(),
43
+ });
44
+
45
+ for ( const module of modules ) module({ context });
46
+
35
47
  try {
36
48
  console.log(chalk.green('Welcome to Puter-CLI! Type "help" for available commands.'));
37
49
  rl.setPrompt(getPrompt());
@@ -41,7 +53,7 @@ export async function startShell() {
41
53
  const trimmedLine = line.trim();
42
54
  if (trimmedLine) {
43
55
  try {
44
- await execCommand(trimmedLine);
56
+ await execCommand(context, trimmedLine);
45
57
  } catch (error) {
46
58
  console.error(chalk.red(error.message));
47
59
  }
@@ -5,12 +5,13 @@ import { getCurrentUserName, getCurrentDirectory } from './auth.js';
5
5
  import { API_BASE, getHeaders, generateAppName, resolvePath, isValidAppName } from '../commons.js';
6
6
  import { displayNonNullValues, formatDate, isValidAppUuid } from '../utils.js';
7
7
  import { getSubdomains, createSubdomain, deleteSubdomain } from './subdomains.js';
8
+ import { ErrorAPI } from '../modules/ErrorModule.js';
8
9
 
9
10
 
10
11
  /**
11
12
  * Listing subdomains
12
13
  */
13
- export async function listSites(args = {}) {
14
+ export async function listSites(args = {}, context) {
14
15
  try {
15
16
  const data = await getSubdomains(args);
16
17
 
@@ -57,6 +58,7 @@ export async function listSites(args = {}) {
57
58
  }
58
59
 
59
60
  } catch (error) {
61
+ context.events.emit('error', { error });
60
62
  console.error(chalk.red('Error listing sites:'), error.message);
61
63
  throw error;
62
64
  }
@@ -121,14 +123,12 @@ export async function infoSite(args = []) {
121
123
  }
122
124
 
123
125
  const data = await response.json();
124
- const result = await deleteSubdomain([uuid]);
125
- if (result){
126
- // check if data is empty object
127
- if (Object.keys(data).length === 0){
128
- console.log(chalk.green(`Site ID: "${uuid}" should be deleted.`));
129
- }
126
+ if (Object.keys(data).length==0) {
127
+ console.log(chalk.green(`Site ID: "${uuid}" has been deleted.`));
128
+ return;
130
129
  }
131
- console.log(chalk.yellow(`Site ID: "${uuid}" may already be deleted!`));
130
+
131
+ console.log(chalk.yellow(`Site ID: "${uuid}" should be deleted.`));
132
132
  } catch (error) {
133
133
  console.error(chalk.red('Error deleting site:'), error.message);
134
134
  return false;
package/src/commons.js CHANGED
@@ -4,10 +4,14 @@ import { formatSize } from './utils.js';
4
4
  import { readFile } from 'fs/promises';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { dirname, join } from 'path';
7
+ import dotenv from 'dotenv';
8
+
9
+ dotenv.config();
7
10
 
8
11
  export const PROJECT_NAME = 'puter-cli';
9
- export const API_BASE = 'https://api.puter.com';
10
- export const BASE_URL = 'https://puter.com';
12
+ // If you haven't defined your own values in .env file, we'll assume you're running Puter on a local instance:
13
+ export const API_BASE = process.env.PUTER_API_BASE || 'http://api.puter.localhost:4100';
14
+ export const BASE_URL = process.env.PUTER_BASE_URL || 'http://puter.localhost:4100';
11
15
 
12
16
  /**
13
17
  * Get headers with the correct Content-Type for multipart form data.
package/src/executor.js CHANGED
@@ -12,6 +12,7 @@ import inquirer from 'inquirer';
12
12
  import { exec } from 'node:child_process';
13
13
  import { parseArgs } from './utils.js';
14
14
  import { rl } from './commands/shell.js';
15
+ import { ErrorAPI } from './modules/ErrorModule.js';
15
16
 
16
17
  const config = new Conf({ projectName: PROJECT_NAME });
17
18
 
@@ -61,6 +62,9 @@ const commands = {
61
62
  rl.write(commandToCopy);
62
63
  }
63
64
  },
65
+ 'last-error': async (_, context) => {
66
+ context[ErrorAPI].showLast();
67
+ },
64
68
  'app:create': async (rawArgs) => {
65
69
  try {
66
70
  const args = parseArgs(rawArgs.join(' '));
@@ -150,7 +154,7 @@ const commands = {
150
154
  * Execute a command
151
155
  * @param {string} input The command line input
152
156
  */
153
- export async function execCommand(input) {
157
+ export async function execCommand(context, input) {
154
158
  const [cmd, ...args] = input.split(' ');
155
159
 
156
160
 
@@ -184,7 +188,7 @@ export async function execCommand(input) {
184
188
  }
185
189
  if (commands[cmd]) {
186
190
  try {
187
- await commands[cmd](args);
191
+ await commands[cmd](args, context);
188
192
  } catch (error) {
189
193
  console.error(chalk.red(`Error executing command: ${error.message}`));
190
194
  }
@@ -0,0 +1,33 @@
1
+ const ERROR_BUFFER_LIMIT = 20;
2
+
3
+ export const ErrorAPI = Symbol('ErrorAPI');
4
+
5
+ export default ({ context }) => {
6
+ // State Variables
7
+ const errors = [];
8
+
9
+ context.events.on('error', (error) => {
10
+ context[ErrorAPI].report(error);
11
+ });
12
+
13
+ // Module Methods
14
+ context[ErrorAPI] = {
15
+ // Add an error to the error history
16
+ report (error) {
17
+ errors.push(error);
18
+ if (errors.length > ERROR_BUFFER_LIMIT) {
19
+ errors = errors.slice(errors.length - ERROR_BUFFER_LIMIT);
20
+ }
21
+ },
22
+ // Print the last error from the error history,
23
+ // and remove it from the history
24
+ showLast () {
25
+ const err = errors.pop();
26
+ if (err) {
27
+ console.error(err);
28
+ } else {
29
+ console.log('No errors to report');
30
+ }
31
+ }
32
+ };
33
+ };
@@ -15,14 +15,15 @@ describe('formatDate', () => {
15
15
  });
16
16
 
17
17
  it('should handle different date and time', () => {
18
- const dateString = '2023-01-01T00:00:00.000Z';
19
- const expected = '01/01/2023, 24:00:00';
18
+ const dateString = '2023-01-01T01:30:05.000Z';
19
+ const expected = '01/01/2023, 01:30:05';
20
20
  expect(formatDate(dateString)).toBe(expected);
21
21
  });
22
- it('should handle invalid date', () => {
23
- const dateString = 'invalid-date';
24
- expect(formatDate(dateString)).toBe('Invalid Date');
25
- });
22
+
23
+ it('should handle invalid date', () => {
24
+ const dateString = 'invalid-date';
25
+ expect(formatDate(dateString)).toBe('Invalid Date');
26
+ });
26
27
  });
27
28
 
28
29
  describe('formatDateTime', () => {