@heyputer/shell 2.1.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.
- package/.claude/settings.local.json +9 -0
- package/.env.example +3 -0
- package/.github/workflows/npm-build.yml +34 -0
- package/.github/workflows/npm-publish.yml +50 -0
- package/.idx/dev.nix +53 -0
- package/CHANGELOG.md +292 -0
- package/LICENSE.md +21 -0
- package/README.md +18 -0
- package/bin/index.js +258 -0
- package/package.json +58 -0
- package/screenshot.png +0 -0
- package/src/commands/apps.js +356 -0
- package/src/commands/auth.js +195 -0
- package/src/commands/deploy.js +54 -0
- package/src/commands/files.js +1187 -0
- package/src/commands/init.js +322 -0
- package/src/commands/shell.js +61 -0
- package/src/commands/sites.js +169 -0
- package/src/commands/subdomains.js +95 -0
- package/src/commons.js +409 -0
- package/src/crypto.js +9 -0
- package/src/executor.js +386 -0
- package/src/modules/ErrorModule.js +20 -0
- package/src/modules/ProfileModule.js +334 -0
- package/src/modules/PuterModule.js +30 -0
- package/src/utils.js +135 -0
- package/tests/ErrorModule.test.js +42 -0
- package/tests/ProfileModule.test.js +274 -0
- package/tests/PuterModule.test.js +56 -0
- package/tests/apps.test.js +194 -0
- package/tests/commons.test.js +380 -0
- package/tests/deploy.test.js +84 -0
- package/tests/executor.test.js +52 -0
- package/tests/files.test.js +640 -0
- package/tests/login.test.js +206 -0
- package/tests/shell.test.js +184 -0
- package/tests/sites.test.js +67 -0
- package/tests/subdomains.test.js +90 -0
- package/tests/utils.test.js +193 -0
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { describe, it, expect, vi } from 'vitest';
|
|
2
|
+
import { formatDate, formatDateTime, formatSize, displayNonNullValues, parseArgs, isValidAppUuid, is_valid_uuid4 } from '../src/utils.js';
|
|
3
|
+
|
|
4
|
+
describe('formatDate', () => {
|
|
5
|
+
it('should format a date string correctly', () => {
|
|
6
|
+
const dateString = '2024-10-07T15:03:53.000Z';
|
|
7
|
+
const expected = '10/07/2024, 15:03:53';
|
|
8
|
+
expect(formatDate(dateString)).toBe(expected);
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
it('should format a date object correctly', () => {
|
|
12
|
+
const dateObject = new Date(Date.UTC(2024, 9, 7, 15, 3, 53)); // Month is 0-indexed
|
|
13
|
+
const expected = '10/07/2024, 15:03:53';
|
|
14
|
+
expect(formatDate(dateObject)).toBe(expected);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('should handle different date and time', () => {
|
|
18
|
+
const dateString = '2023-01-01T01:30:05.000Z';
|
|
19
|
+
const expected = '01/01/2023, 01:30:05';
|
|
20
|
+
expect(formatDate(dateString)).toBe(expected);
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should handle invalid date', () => {
|
|
24
|
+
const dateString = 'invalid-date';
|
|
25
|
+
expect(formatDate(dateString)).toBe('Invalid Date');
|
|
26
|
+
});
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
describe('formatDateTime', () => {
|
|
30
|
+
it('should format as time if within 24 hours', () => {
|
|
31
|
+
const now = new Date();
|
|
32
|
+
const timestamp = Math.floor(now.getTime() / 1000) - 3600; // 1 hour ago
|
|
33
|
+
const expected = new Date(timestamp * 1000).toLocaleTimeString();
|
|
34
|
+
expect(formatDateTime(timestamp)).toBe(expected);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should format as date if older than 24 hours', () => {
|
|
38
|
+
const timestamp = Math.floor(Date.now() / 1000) - 86400 * 2; // 2 days ago
|
|
39
|
+
const expected = new Date(timestamp * 1000).toLocaleDateString();
|
|
40
|
+
expect(formatDateTime(timestamp)).toBe(expected);
|
|
41
|
+
});
|
|
42
|
+
it('should format timestamp 0', () => {
|
|
43
|
+
const timestamp = 0;
|
|
44
|
+
const expected = new Date(timestamp * 1000).toLocaleDateString();
|
|
45
|
+
expect(formatDateTime(timestamp)).toBe(expected);
|
|
46
|
+
});
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe('formatSize', () => {
|
|
50
|
+
it('should format 0 bytes correctly', () => {
|
|
51
|
+
expect(formatSize(0)).toBe('0');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should format bytes correctly', () => {
|
|
55
|
+
expect(formatSize(512)).toBe('512.0 B');
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should format kilobytes correctly', () => {
|
|
59
|
+
expect(formatSize(1024 * 2)).toBe('2.0 KB');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should format megabytes correctly', () => {
|
|
63
|
+
expect(formatSize(1024 * 1024 * 3)).toBe('3.0 MB');
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should format gigabytes correctly', () => {
|
|
67
|
+
expect(formatSize(1024 * 1024 * 1024 * 4)).toBe('4.0 GB');
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
it('should format terabytes correctly', () => {
|
|
71
|
+
expect(formatSize(1024 * 1024 * 1024 * 1024 * 5)).toBe('5.0 TB');
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
it('should handle null and undefined', () => {
|
|
75
|
+
expect(formatSize(null)).toBe('0');
|
|
76
|
+
expect(formatSize(undefined)).toBe('0');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
describe('displayNonNullValues', () => {
|
|
81
|
+
it('should display non-null values in a formatted table', () => {
|
|
82
|
+
const data = {
|
|
83
|
+
name: 'John Doe',
|
|
84
|
+
age: 30,
|
|
85
|
+
address: {
|
|
86
|
+
street: '123 Main St',
|
|
87
|
+
city: 'Anytown',
|
|
88
|
+
zip: null
|
|
89
|
+
},
|
|
90
|
+
email: null
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const consoleLogSpy = vi.spyOn(console, 'log');
|
|
94
|
+
displayNonNullValues(data);
|
|
95
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
96
|
+
consoleLogSpy.mockRestore();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should handle empty object', () => {
|
|
100
|
+
const data = {};
|
|
101
|
+
const consoleLogSpy = vi.spyOn(console, 'log');
|
|
102
|
+
displayNonNullValues(data);
|
|
103
|
+
expect(consoleLogSpy).toHaveBeenCalled();
|
|
104
|
+
consoleLogSpy.mockRestore();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
it('should handle nested objects with all null values', () => {
|
|
108
|
+
const data = { a: null, b: { c: null, d: null } };
|
|
109
|
+
const consoleLogSpy = vi.spyOn(console, 'log');
|
|
110
|
+
displayNonNullValues(data);
|
|
111
|
+
expect(consoleLogSpy).toHaveBeenCalledTimes(5);
|
|
112
|
+
consoleLogSpy.mockRestore();
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('should handle non-object input', () => {
|
|
116
|
+
const data = "not an object";
|
|
117
|
+
const consoleErrorSpy = vi.spyOn(console, 'error');
|
|
118
|
+
displayNonNullValues(data);
|
|
119
|
+
expect(consoleErrorSpy).toHaveBeenCalledWith("Invalid input: Input must be a non-null object.");
|
|
120
|
+
consoleErrorSpy.mockRestore();
|
|
121
|
+
});
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
describe('parseArgs', () => {
|
|
125
|
+
it('should parse simple arguments', () => {
|
|
126
|
+
const input = 'command --arg1 val1 --arg2 val2';
|
|
127
|
+
const expected = { _: ['command'], arg1: 'val1', arg2: 'val2' };
|
|
128
|
+
expect(parseArgs(input)).toEqual(expect.objectContaining(expected));
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should parse command line arguments with different types', () => {
|
|
132
|
+
const input = 'command --name="John Doe" --age=30';
|
|
133
|
+
const result = parseArgs(input);
|
|
134
|
+
expect(result).toEqual({ _: ['command'], name: 'John Doe', age: 30 });
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it('should parse quoted arguments', () => {
|
|
138
|
+
const input = 'command --arg "quoted value"';
|
|
139
|
+
const expected = { _: ['command'], arg: 'quoted value' };
|
|
140
|
+
expect(parseArgs(input)).toEqual(expect.objectContaining(expected));
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('should parse arguments with equals sign', () => {
|
|
144
|
+
const input = 'command --arg1=val1 --arg2=val2';
|
|
145
|
+
const expected = { _: ['command'], arg1: 'val1', arg2: 'val2' };
|
|
146
|
+
expect(parseArgs(input)).toEqual(expect.objectContaining(expected));
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('should handle empty input', () => {
|
|
150
|
+
const result = parseArgs('');
|
|
151
|
+
expect(result).toEqual({ _: []});
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
it('should parse empty arguments', () => {
|
|
155
|
+
const input = '';
|
|
156
|
+
const expected = { _: [] };
|
|
157
|
+
expect(parseArgs(input)).toEqual(expect.objectContaining(expected));
|
|
158
|
+
});
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
describe('isValidAppUuid', () => {
|
|
162
|
+
it('should return true for a valid app UUID', () => {
|
|
163
|
+
const uuid = 'app-a1b2c3d4-e5f6-4789-8abc-def012345678';
|
|
164
|
+
expect(isValidAppUuid(uuid)).toBe(true);
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should return false if UUID does not start with "app-"', () => {
|
|
168
|
+
const uuid = 'a1b2c3d4-e5f6-4789-8abc-def012345678';
|
|
169
|
+
expect(isValidAppUuid(uuid)).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
it('should return false for an invalid UUID after "app-"', () => {
|
|
173
|
+
const uuid = 'app-invalid-uuid';
|
|
174
|
+
expect(isValidAppUuid(uuid)).toBe(false);
|
|
175
|
+
});
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
describe('is_valid_uuid4', () => {
|
|
179
|
+
it('should return true for a valid UUID v4', () => {
|
|
180
|
+
const uuid = 'a1b2c3d4-e5f6-4789-8abc-def012345678';
|
|
181
|
+
expect(is_valid_uuid4(uuid)).toBe(true);
|
|
182
|
+
});
|
|
183
|
+
|
|
184
|
+
it('should return false for an invalid UUID v4', () => {
|
|
185
|
+
const uuid = 'a1b2c3d4-e5f6-5789-8abc-def012345678'; // Invalid version
|
|
186
|
+
expect(is_valid_uuid4(uuid)).toBe(false);
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
it('should return false for a completely invalid UUID', () => {
|
|
190
|
+
const uuid = 'invalid-uuid';
|
|
191
|
+
expect(is_valid_uuid4(uuid)).toBe(false);
|
|
192
|
+
});
|
|
193
|
+
});
|