tabby-cli-test 0.1.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.
package/README.md ADDED
@@ -0,0 +1,9 @@
1
+ ## This repo contains all the palygrounds random stuff this is where I test things and play with them
2
+
3
+ | Column1 | Column2 |
4
+ | -------------- | --------------- |
5
+ | GO-PG | [VISIT](https://github.com/h3yng/playgrounds/tree/main/go-pg) |
6
+ | VIM-PG | [VISIT](https://github.com/h3yng/playgrounds/tree/main/vim-pg) |
7
+ | DOCKER | [VISIT](https://github.com/h3yng/playgrounds/tree/main/docker) |
8
+ | KUBERNETES | [VISIT](https://github.com/h3yng/playgrounds/tree/main/k8s) |
9
+
package/bin/tabby ADDED
Binary file
package/index.js ADDED
@@ -0,0 +1,30 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const path = require('path');
5
+ const fs = require('fs');
6
+ const { spawn } = require('child_process');
7
+
8
+ const binaryName = "tabby";
9
+ const executable = process.platform === 'win32' ? binaryName + '.exe' : binaryName;
10
+ const binaryPath = path.join(__dirname, 'bin', executable);
11
+
12
+ if (!fs.existsSync(binaryPath)) {
13
+ console.error('[drb99] Binary is missing. Reinstall the package to trigger postinstall.');
14
+ process.exit(1);
15
+ }
16
+
17
+ const child = spawn(binaryPath, process.argv.slice(2), { stdio: 'inherit' });
18
+
19
+ child.on('error', (err) => {
20
+ console.error('[drb99] Failed to start binary:', err.message);
21
+ process.exit(1);
22
+ });
23
+
24
+ child.on('exit', (code, signal) => {
25
+ if (signal) {
26
+ process.kill(process.pid, signal);
27
+ return;
28
+ }
29
+ process.exit(code === null ? 1 : code);
30
+ });
package/install.js ADDED
@@ -0,0 +1,274 @@
1
+ #!/usr/bin/env node
2
+ 'use strict';
3
+
4
+ const fs = require('fs');
5
+ const path = require('path');
6
+ const https = require('https');
7
+ const tar = require('tar');
8
+ const zlib = require('zlib');
9
+
10
+ const binaryName = "tabby";
11
+ const targetDir = path.join(__dirname, 'bin');
12
+ const platformKey = process.platform + '-' + process.arch;
13
+
14
+ const assets = {
15
+ "darwin-arm64": {
16
+ urls: ["https://github.com/h3yng/tabby/releases/download/v0.1.2/tabby_0.1.2_darwin_amd64.tar.gz","https://github.com/h3yng/tabby/releases/download/v0.1.2/tabby_0.1.2_darwin_arm64.tar.gz",],
17
+ fileName: "tabby_v0.1.2_macos_arm64.tar.gz",
18
+ archive: "tar.gz"
19
+ },
20
+ "linux-x64": {
21
+ urls: ["https://github.com/h3yng/tabby/releases/download/v0.1.2/tabby_0.1.2_linux_amd64.tar.gz","https://github.com/h3yng/tabby/releases/download/v0.1.2/tabby_0.1.2_linux_arm64.tar.gz",],
22
+ fileName: "tabby_v0.1.2_linux_amd64.tar.gz",
23
+ archive: "tar.gz"
24
+ },
25
+ "win32-x64": {
26
+ urls: ["https://github.com/h3yng/tabby/releases/download/v0.1.2/tabby_0.1.2_windows_amd64.zip","https://github.com/h3yng/tabby/releases/download/v0.1.2/tabby_0.1.2_windows_arm64.zip",],
27
+ fileName: "tabby_v0.1.2_windows_amd64.zip",
28
+ archive: "zip"
29
+ },
30
+ };
31
+
32
+ function fail(message, details) {
33
+ const extra = details ? '\n' + details : '';
34
+ console.error('[drb99] ' + message + extra);
35
+ process.exit(1);
36
+ }
37
+
38
+ function ensureDir(dir) {
39
+ fs.mkdirSync(dir, { recursive: true });
40
+ }
41
+
42
+ function findBinaryFile(dir) {
43
+ const expectedNames = new Set([binaryName, binaryName + '.exe']);
44
+ const entries = fs.readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
45
+
46
+ for (const entry of entries) {
47
+ const entryPath = path.join(dir, entry.name);
48
+ if (entry.isFile()) {
49
+ if (expectedNames.has(entry.name)) {
50
+ return entryPath;
51
+ }
52
+ continue;
53
+ }
54
+ if (entry.isDirectory()) {
55
+ const nested = findBinaryFile(entryPath);
56
+ if (nested) {
57
+ return nested;
58
+ }
59
+ }
60
+ }
61
+
62
+ return null;
63
+ }
64
+
65
+ async function extractTarGzEntry(archivePath, outputPath) {
66
+ try {
67
+ const extractDir = fs.mkdtempSync(path.join(targetDir, 'tar-'));
68
+ try {
69
+ await tar.x({
70
+ file: archivePath,
71
+ cwd: extractDir,
72
+ gzip: true,
73
+ });
74
+
75
+ const extracted = findBinaryFile(extractDir);
76
+ if (!extracted) {
77
+ fail('Tar archive does not contain the expected binary: ' + binaryName);
78
+ }
79
+
80
+ try {
81
+ fs.rmSync(outputPath, { force: true });
82
+ } catch (_) {
83
+ }
84
+
85
+ fs.renameSync(extracted, outputPath);
86
+ } finally {
87
+ fs.rmSync(extractDir, { recursive: true, force: true });
88
+ }
89
+ } catch (err) {
90
+ throw err;
91
+ }
92
+ }
93
+
94
+ function extractZipEntry(zipPath, outputPath) {
95
+ const data = fs.readFileSync(zipPath);
96
+ const eocdSignature = 0x06054b50;
97
+ const centralSignature = 0x02014b50;
98
+ const localSignature = 0x04034b50;
99
+
100
+ if (data.length < 22) {
101
+ throw new Error('Downloaded archive is too small to be a valid zip file.');
102
+ }
103
+
104
+ let eocdOffset = -1;
105
+ for (let i = data.length - 22; i >= Math.max(0, data.length - 65557); i -= 1) {
106
+ if (data.readUInt32LE(i) === eocdSignature) {
107
+ eocdOffset = i;
108
+ break;
109
+ }
110
+ }
111
+
112
+ if (eocdOffset === -1) {
113
+ throw new Error('Downloaded archive is not a valid zip file.');
114
+ }
115
+
116
+ const centralDirectoryOffset = data.readUInt32LE(eocdOffset + 16);
117
+ const totalEntries = data.readUInt16LE(eocdOffset + 10);
118
+ let cursor = centralDirectoryOffset;
119
+ let selected = null;
120
+
121
+ for (let entry = 0; entry < totalEntries; entry += 1) {
122
+ if (data.readUInt32LE(cursor) !== centralSignature) {
123
+ throw new Error('Invalid zip central directory entry.');
124
+ }
125
+
126
+ const compressionMethod = data.readUInt16LE(cursor + 10);
127
+ const compressedSize = data.readUInt32LE(cursor + 20);
128
+ const fileNameLength = data.readUInt16LE(cursor + 28);
129
+ const extraLength = data.readUInt16LE(cursor + 30);
130
+ const commentLength = data.readUInt16LE(cursor + 32);
131
+ const localHeaderOffset = data.readUInt32LE(cursor + 42);
132
+ const fileName = data.slice(cursor + 46, cursor + 46 + fileNameLength).toString('utf8');
133
+
134
+ if (fileName && !fileName.endsWith('/')) {
135
+ selected = {
136
+ compressionMethod: compressionMethod,
137
+ compressedSize: compressedSize,
138
+ localHeaderOffset: localHeaderOffset,
139
+ fileName: fileName,
140
+ };
141
+ break;
142
+ }
143
+
144
+ cursor += 46 + fileNameLength + extraLength + commentLength;
145
+ }
146
+
147
+ if (!selected) {
148
+ throw new Error('Zip archive does not contain a usable binary.');
149
+ }
150
+
151
+ if (data.readUInt32LE(selected.localHeaderOffset) !== localSignature) {
152
+ throw new Error('Invalid zip local header.');
153
+ }
154
+
155
+ const localNameLength = data.readUInt16LE(selected.localHeaderOffset + 26);
156
+ const localExtraLength = data.readUInt16LE(selected.localHeaderOffset + 28);
157
+ const dataStart = selected.localHeaderOffset + 30 + localNameLength + localExtraLength;
158
+ const payload = data.slice(dataStart, dataStart + selected.compressedSize);
159
+ let extracted;
160
+
161
+ if (selected.compressionMethod === 0) {
162
+ extracted = payload;
163
+ } else if (selected.compressionMethod === 8) {
164
+ extracted = zlib.inflateRawSync(payload);
165
+ } else {
166
+ throw new Error('Unsupported zip compression method: ' + selected.compressionMethod);
167
+ }
168
+
169
+ fs.writeFileSync(outputPath, extracted);
170
+ }
171
+
172
+ function download(url, destination, redirects = 0) {
173
+ return new Promise((resolve, reject) => {
174
+ if (redirects > 5) {
175
+ reject(new Error('Too many redirects while downloading binary: ' + url));
176
+ return;
177
+ }
178
+
179
+ https.get(url, (res) => {
180
+ if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
181
+ return download(res.headers.location, destination, redirects + 1).then(resolve).catch(reject);
182
+ }
183
+
184
+ if (res.statusCode !== 200) {
185
+ reject(new Error('HTTP ' + res.statusCode + ' from ' + url));
186
+ return;
187
+ }
188
+
189
+ const tmpFile = destination + '.tmp';
190
+ const file = fs.createWriteStream(tmpFile);
191
+
192
+ res.pipe(file);
193
+
194
+ file.on('finish', () => {
195
+ file.close(async () => {
196
+ try {
197
+ if (assets[platformKey].archive === 'zip') {
198
+ extractZipEntry(tmpFile, destination);
199
+ fs.unlinkSync(tmpFile);
200
+ } else if (assets[platformKey].archive === 'tar.gz') {
201
+ await extractTarGzEntry(tmpFile, destination);
202
+ fs.unlinkSync(tmpFile);
203
+ } else {
204
+ fs.renameSync(tmpFile, destination);
205
+ }
206
+
207
+ if (process.platform !== 'win32') {
208
+ fs.chmodSync(destination, 0o755);
209
+ }
210
+ resolve();
211
+ } catch (err) {
212
+ try {
213
+ fs.unlinkSync(tmpFile);
214
+ } catch (_) {
215
+ }
216
+ reject(err);
217
+ }
218
+ });
219
+ });
220
+
221
+ file.on('error', (err) => {
222
+ try {
223
+ fs.unlinkSync(tmpFile);
224
+ } catch (_) {
225
+ }
226
+ reject(err);
227
+ });
228
+ }).on('error', reject);
229
+ });
230
+ }
231
+
232
+ async function tryDownloadUrls(urls, destination, urlIndex = 0) {
233
+ if (urlIndex >= urls.length) {
234
+ throw new Error('All asset URLs failed. Tried: ' + urls.join(', '));
235
+ }
236
+
237
+ const url = urls[urlIndex];
238
+ try {
239
+ console.log('[drb99] Attempting to download from ' + (urlIndex + 1) + '/' + urls.length + ': ' + url);
240
+ await download(url, destination);
241
+ console.log('[drb99] Installed ' + binaryName + ' for ' + platformKey);
242
+ } catch (err) {
243
+ if (urlIndex + 1 < urls.length) {
244
+ console.warn('[drb99] Download failed: ' + err.message + '. Trying next URL...');
245
+ return tryDownloadUrls(urls, destination, urlIndex + 1);
246
+ } else {
247
+ throw err;
248
+ }
249
+ }
250
+ }
251
+
252
+ async function main() {
253
+ const target = assets[platformKey];
254
+ if (!target) {
255
+ const supported = Object.keys(assets).join(', ');
256
+ fail('Unsupported platform/architecture.', 'Detected ' + platformKey + '. Supported: ' + supported);
257
+ }
258
+
259
+ if (!target.urls || target.urls.length === 0) {
260
+ fail('No asset URLs configured for this platform.', platformKey);
261
+ }
262
+
263
+ ensureDir(targetDir);
264
+ const outputName = process.platform === 'win32' ? binaryName + '.exe' : binaryName;
265
+ const outputPath = path.join(targetDir, outputName);
266
+
267
+ try {
268
+ await tryDownloadUrls(target.urls, outputPath);
269
+ } catch (err) {
270
+ fail('Unable to install binary.', err.message);
271
+ }
272
+ }
273
+
274
+ main();
package/package.json ADDED
@@ -0,0 +1,22 @@
1
+ {
2
+ "author": "h3yng",
3
+ "bin": {
4
+ "tabby": "index.js"
5
+ },
6
+ "dependencies": {
7
+ "tar": "^7.5.2"
8
+ },
9
+ "description": "terminal based api stress testing with random data + templates",
10
+ "files": [
11
+ "index.js",
12
+ "install.js",
13
+ "bin/",
14
+ "README.md"
15
+ ],
16
+ "license": "AGPL-3.0",
17
+ "name": "tabby-cli-test",
18
+ "scripts": {
19
+ "postinstall": "node install.js"
20
+ },
21
+ "version": "0.1.2"
22
+ }