@ctrl/transmission 3.0.0 → 4.0.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.
@@ -0,0 +1,2 @@
1
+ export * from './transmission.js';
2
+ export * from './types.js';
@@ -0,0 +1,2 @@
1
+ export * from './transmission.js';
2
+ export * from './types.js';
@@ -1,7 +1,7 @@
1
- /// <reference types="node" />
1
+ /// <reference types="node" resolution-mode="require"/>
2
2
  import { Response } from 'got';
3
3
  import { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
4
- import { AddTorrentOptions, AddTorrentResponse, DefaultResponse, FreeSpaceResponse, GetTorrentRepsonse, NormalizedTorrentIds, RenamePathOptions, SessionArguments, SessionResponse, SetTorrentOptions } from './types';
4
+ import { AddTorrentOptions, AddTorrentResponse, DefaultResponse, FreeSpaceResponse, GetTorrentRepsonse, NormalizedTorrentIds, RenamePathOptions, SessionArguments, SessionResponse, SetTorrentOptions } from './types.js';
5
5
  export declare class Transmission implements TorrentClient {
6
6
  config: TorrentSettings;
7
7
  sessionId?: string;
@@ -1,13 +1,7 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.Transmission = void 0;
7
- const fs_1 = require("fs");
8
- const got_1 = __importDefault(require("got"));
9
- const shared_torrent_1 = require("@ctrl/shared-torrent");
10
- const url_join_1 = require("@ctrl/url-join");
1
+ import { existsSync, readFileSync } from 'fs';
2
+ import got from 'got';
3
+ import { TorrentState, } from '@ctrl/shared-torrent';
4
+ import { urlJoin } from '@ctrl/url-join';
11
5
  const defaults = {
12
6
  baseUrl: 'http://localhost:9091/',
13
7
  path: '/transmission/rpc',
@@ -15,8 +9,20 @@ const defaults = {
15
9
  password: '',
16
10
  timeout: 5000,
17
11
  };
18
- class Transmission {
12
+ export class Transmission {
19
13
  constructor(options = {}) {
14
+ Object.defineProperty(this, "config", {
15
+ enumerable: true,
16
+ configurable: true,
17
+ writable: true,
18
+ value: void 0
19
+ });
20
+ Object.defineProperty(this, "sessionId", {
21
+ enumerable: true,
22
+ configurable: true,
23
+ writable: true,
24
+ value: void 0
25
+ });
20
26
  this.config = { ...defaults, ...options };
21
27
  }
22
28
  async getSession() {
@@ -145,8 +151,8 @@ class Transmission {
145
151
  ...options,
146
152
  };
147
153
  if (typeof torrent === 'string') {
148
- args.metainfo = (0, fs_1.existsSync)(torrent)
149
- ? Buffer.from((0, fs_1.readFileSync)(torrent)).toString('base64')
154
+ args.metainfo = existsSync(torrent)
155
+ ? Buffer.from(readFileSync(torrent)).toString('base64')
150
156
  : Buffer.from(torrent, 'base64').toString('base64');
151
157
  }
152
158
  else {
@@ -269,7 +275,6 @@ class Transmission {
269
275
  return res.body;
270
276
  }
271
277
  async request(method, args = {}) {
272
- var _a, _b, _c;
273
278
  if (!this.sessionId && method !== 'session-get') {
274
279
  await this.getSession();
275
280
  }
@@ -277,27 +282,27 @@ class Transmission {
277
282
  'X-Transmission-Session-Id': this.sessionId,
278
283
  };
279
284
  if (this.config.username || this.config.password) {
280
- const str = `${(_a = this.config.username) !== null && _a !== void 0 ? _a : ''}:${(_b = this.config.password) !== null && _b !== void 0 ? _b : ''}`;
285
+ const str = `${this.config.username ?? ''}:${this.config.password ?? ''}`;
281
286
  headers.Authorization = 'Basic ' + Buffer.from(str).toString('base64');
282
287
  }
283
- const url = (0, url_join_1.urlJoin)(this.config.baseUrl, this.config.path);
288
+ const url = urlJoin(this.config.baseUrl, this.config.path);
284
289
  try {
285
- const res = await got_1.default.post(url, {
290
+ const res = await got.post(url, {
286
291
  json: {
287
292
  method,
288
293
  arguments: args,
289
294
  },
290
295
  headers,
291
- retry: 0,
296
+ retry: { limit: 0 },
292
297
  // allow proxy agent
293
- agent: this.config.agent,
294
- timeout: this.config.timeout,
298
+ timeout: { request: this.config.timeout },
295
299
  responseType: 'json',
300
+ ...(this.config.agent ? { agent: this.config.agent } : {}),
296
301
  });
297
302
  return res;
298
303
  }
299
304
  catch (error) {
300
- if (((_c = error === null || error === void 0 ? void 0 : error.response) === null || _c === void 0 ? void 0 : _c.statusCode) === 409) {
305
+ if (error?.response?.statusCode === 409) {
301
306
  this.sessionId = error.response.headers['x-transmission-session-id'];
302
307
  // eslint-disable-next-line no-return-await
303
308
  return await this.request(method, args);
@@ -313,26 +318,25 @@ class Transmission {
313
318
  return ids;
314
319
  }
315
320
  _normalizeTorrentData(torrent) {
316
- var _a;
317
321
  const dateAdded = new Date(torrent.addedDate * 1000).toISOString();
318
322
  const dateCompleted = new Date(torrent.doneDate * 1000).toISOString();
319
323
  // normalize state to enum
320
324
  // https://github.com/transmission/transmission/blob/c11f2870fd18ff781ca06ce84b6d43541f3293dd/web/javascript/torrent.js#L18
321
- let state = shared_torrent_1.TorrentState.unknown;
325
+ let state = TorrentState.unknown;
322
326
  if (torrent.status === 6) {
323
- state = shared_torrent_1.TorrentState.seeding;
327
+ state = TorrentState.seeding;
324
328
  }
325
329
  else if (torrent.status === 4) {
326
- state = shared_torrent_1.TorrentState.downloading;
330
+ state = TorrentState.downloading;
327
331
  }
328
332
  else if (torrent.status === 0) {
329
- state = shared_torrent_1.TorrentState.paused;
333
+ state = TorrentState.paused;
330
334
  }
331
335
  else if (torrent.status === 2) {
332
- state = shared_torrent_1.TorrentState.checking;
336
+ state = TorrentState.checking;
333
337
  }
334
338
  else if (torrent.status === 3 || torrent.status === 5) {
335
- state = shared_torrent_1.TorrentState.queued;
339
+ state = TorrentState.queued;
336
340
  }
337
341
  return {
338
342
  id: torrent.hashString,
@@ -344,7 +348,7 @@ class Transmission {
344
348
  ratio: torrent.uploadRatio,
345
349
  dateAdded,
346
350
  dateCompleted,
347
- label: ((_a = torrent.labels) === null || _a === void 0 ? void 0 : _a.length) ? torrent.labels[0] : undefined,
351
+ label: torrent.labels?.length ? torrent.labels[0] : undefined,
348
352
  savePath: torrent.downloadDir,
349
353
  uploadSpeed: torrent.rateUpload,
350
354
  downloadSpeed: torrent.rateDownload,
@@ -361,4 +365,3 @@ class Transmission {
361
365
  };
362
366
  }
363
367
  }
364
- exports.Transmission = Transmission;
File without changes
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,130 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import pWaitFor from 'p-wait-for';
4
+ import { afterEach, describe, expect, it } from 'vitest';
5
+ import { TorrentState } from '@ctrl/shared-torrent';
6
+ import { Transmission } from '../src/index.js';
7
+ const baseUrl = 'http://localhost:9091/';
8
+ const torrentName = 'ubuntu-18.04.1-desktop-amd64.iso';
9
+ const torrentFile = path.join(__dirname, '/ubuntu-18.04.1-desktop-amd64.iso.torrent');
10
+ async function setupTorrent(transmission) {
11
+ const res = await transmission.addTorrent(torrentFile);
12
+ await pWaitFor(async () => {
13
+ const r = await transmission.listTorrents(undefined, ['id']);
14
+ return r.arguments.torrents.length === 1;
15
+ }, { timeout: 10000, interval: 200 });
16
+ return res.arguments['torrent-added'].hashString;
17
+ }
18
+ describe('Transmission', () => {
19
+ afterEach(async () => {
20
+ const transmission = new Transmission({ baseUrl });
21
+ const res = await transmission.listTorrents();
22
+ // clean up all torrents
23
+ for (const torrent of res.arguments.torrents) {
24
+ // eslint-disable-next-line no-await-in-loop
25
+ await transmission.removeTorrent(torrent.id, false);
26
+ }
27
+ });
28
+ it('should be instantiable', () => {
29
+ const transmission = new Transmission({ baseUrl });
30
+ expect(transmission).toBeTruthy();
31
+ });
32
+ it('should add torrent from file path string', async () => {
33
+ const transmission = new Transmission({ baseUrl });
34
+ const res = await transmission.addTorrent(torrentFile);
35
+ expect(res.result).toBe('success');
36
+ });
37
+ it('should add magnet link', async () => {
38
+ const magnet = 'magnet:?xt=urn:btih:B0B81206633C42874173D22E564D293DAEFC45E2&dn=Ubuntu+11+10+Alternate+Amd64+Iso&tr=udp%3A%2F%2Ftracker.coppersurfer.tk%3A6969%2Fannounce&tr=udp%3A%2F%2F9.rarbg.to%3A2710%2Fannounce&tr=udp%3A%2F%2Ftracker.opentrackr.org%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.leechers-paradise.org%3A6969%2Fannounce&tr=udp%3A%2F%2Ftracker.open-internet.nl%3A6969%2Fannounce&tr=udp%3A%2F%2Fopen.demonii.si%3A1337%2Fannounce&tr=udp%3A%2F%2Ftracker.pirateparty.gr%3A6969%2Fannounce&tr=udp%3A%2F%2Fdenis.stalker.upeer.me%3A6969%2Fannounce&tr=udp%3A%2F%2Fp4p.arenabg.com%3A1337%2Fannounce&tr=udp%3A%2F%2Fexodus.desync.com%3A6969%2Fannounce';
39
+ const client = new Transmission({ baseUrl });
40
+ const res = await client.addMagnet(magnet);
41
+ expect(res.result).toBe('success');
42
+ });
43
+ it('should add torrent from file buffer', async () => {
44
+ const transmission = new Transmission({ baseUrl });
45
+ const res = await transmission.addTorrent(fs.readFileSync(torrentFile));
46
+ expect(res.result).toBe('success');
47
+ });
48
+ it('should add torrent from file contents base64', async () => {
49
+ const transmission = new Transmission({ baseUrl });
50
+ const contents = Buffer.from(fs.readFileSync(torrentFile)).toString('base64');
51
+ const res = await transmission.addTorrent(contents);
52
+ expect(res.result).toBe('success');
53
+ });
54
+ it('should get torrents', async () => {
55
+ const transmission = new Transmission({ baseUrl });
56
+ await setupTorrent(transmission);
57
+ const res = await transmission.listTorrents(undefined, ['id']);
58
+ expect(res.arguments.torrents).toHaveLength(1);
59
+ });
60
+ it('should get normalized all torrent data', async () => {
61
+ const transmission = new Transmission({ baseUrl });
62
+ await setupTorrent(transmission);
63
+ const res = await transmission.getAllData();
64
+ expect(res.torrents).toHaveLength(1);
65
+ expect(res.torrents[0].name).toBe(torrentName);
66
+ });
67
+ it('should get normalized torrent data', async () => {
68
+ const transmission = new Transmission({ baseUrl });
69
+ const id = await setupTorrent(transmission);
70
+ const res = await transmission.getTorrent(id);
71
+ expect(res.name).toBe(torrentName);
72
+ });
73
+ it('should remove torrent', async () => {
74
+ const transmission = new Transmission({ baseUrl });
75
+ const key = await setupTorrent(transmission);
76
+ await transmission.removeTorrent(key, false);
77
+ });
78
+ it('should verify torrent', async () => {
79
+ const transmission = new Transmission({ baseUrl });
80
+ const key = await setupTorrent(transmission);
81
+ await transmission.verifyTorrent(key);
82
+ });
83
+ it('should move in queue', async () => {
84
+ const transmission = new Transmission({ baseUrl });
85
+ const key = await setupTorrent(transmission);
86
+ await transmission.queueUp(key);
87
+ await transmission.queueDown(key);
88
+ await transmission.queueTop(key);
89
+ await transmission.queueBottom(key);
90
+ });
91
+ it('should report free space', async () => {
92
+ const transmission = new Transmission({ baseUrl });
93
+ const p = '/downloads';
94
+ const res = await transmission.freeSpace(p);
95
+ expect(res.result).toBe('success');
96
+ expect(res.arguments.path).toBe(p);
97
+ expect(typeof res.arguments['size-bytes']).toBe('number');
98
+ });
99
+ it('should add from url', async () => {
100
+ const transmission = new Transmission({ baseUrl });
101
+ const res = await transmission.addUrl('https://releases.ubuntu.com/20.10/ubuntu-20.10-desktop-amd64.iso.torrent');
102
+ expect(res.result).toBe('success');
103
+ });
104
+ it('should add torrent with normalized response', async () => {
105
+ const client = new Transmission({ baseUrl });
106
+ const torrent = await client.normalizedAddTorrent(fs.readFileSync(torrentFile), {
107
+ label: 'test',
108
+ });
109
+ expect(torrent.connectedPeers).toBe(0);
110
+ expect(torrent.connectedSeeds).toBe(0);
111
+ expect(torrent.downloadSpeed).toBe(0);
112
+ expect(torrent.eta).toBe(-1);
113
+ expect(torrent.isCompleted).toBe(false);
114
+ expect(torrent.label).toBe('test');
115
+ expect(torrent.name).toBe(torrentName);
116
+ expect(torrent.progress).toBeGreaterThanOrEqual(0);
117
+ expect(torrent.queuePosition).toBe(0);
118
+ // expect(torrent.ratio).toBe(0);
119
+ expect(torrent.savePath).toBe('/downloads');
120
+ expect(torrent.state).toBe(TorrentState.checking);
121
+ expect(torrent.stateMessage).toBe('');
122
+ expect(torrent.totalDownloaded).toBe(0);
123
+ expect(torrent.totalPeers).toBe(0);
124
+ expect(torrent.totalSeeds).toBe(0);
125
+ expect(torrent.totalSelected).toBe(1953349632);
126
+ // expect(torrent.totalSize).toBe(undefined);
127
+ expect(torrent.totalUploaded).toBe(0);
128
+ expect(torrent.uploadSpeed).toBe(0);
129
+ });
130
+ });
@@ -0,0 +1,2 @@
1
+ declare const _default: any;
2
+ export default _default;
@@ -0,0 +1,7 @@
1
+ // @ts-expect-error
2
+ import { defineConfig } from 'vitest/config';
3
+ export default defineConfig({
4
+ test: {
5
+ threads: false,
6
+ },
7
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl/transmission",
3
- "version": "3.0.0",
3
+ "version": "4.0.0",
4
4
  "description": "TypeScript api wrapper for transmission using got",
5
5
  "author": "Scott Cooper <scttcper@gmail.com>",
6
6
  "license": "MIT",
@@ -9,8 +9,9 @@
9
9
  "transmission",
10
10
  "typescript"
11
11
  ],
12
- "main": "dist/index.js",
13
- "typings": "dist/index.d.ts",
12
+ "type": "module",
13
+ "main": "./dist/src/index.js",
14
+ "typings": "./dist/src/index.d.ts",
14
15
  "files": [
15
16
  "dist"
16
17
  ],
@@ -19,48 +20,40 @@
19
20
  "lint": "eslint --ext .ts .",
20
21
  "lint:fix": "eslint --fix --ext .ts .",
21
22
  "prepare": "npm run build",
22
- "build": "tsc -p tsconfig.build.json",
23
+ "build": "tsc",
23
24
  "build:docs": "typedoc",
24
- "test": "jest --runInBand",
25
- "test:watch": "jest --watch --runInBand",
26
- "test:ci": "jest --ci --runInBand --reporters=default --reporters=jest-junit --coverage"
25
+ "test": "vitest run",
26
+ "test:watch": "vitest",
27
+ "test:ci": "vitest run --coverage"
27
28
  },
28
29
  "dependencies": {
29
- "@ctrl/shared-torrent": "^3.0.5",
30
- "got": "^11.8.3",
31
- "@ctrl/url-join": "^1.0.4"
30
+ "@ctrl/shared-torrent": "^4.1.0",
31
+ "@ctrl/url-join": "^2.0.0",
32
+ "got": "^12.1.0"
32
33
  },
33
34
  "devDependencies": {
34
- "@babel/plugin-transform-modules-commonjs": "7.16.8",
35
- "@babel/preset-typescript": "7.16.7",
36
- "@ctrl/eslint-config": "3.3.1",
37
- "@jest/globals": "27.4.6",
38
- "@types/node": "17.0.14",
39
- "jest": "27.4.7",
40
- "jest-junit": "13.0.0",
41
- "p-wait-for": "3.2.0",
42
- "typedoc": "0.22.11",
43
- "typescript": "4.5.5"
35
+ "@ctrl/eslint-config": "3.4.4",
36
+ "@sindresorhus/tsconfig": "3.0.1",
37
+ "@types/node": "17.0.38",
38
+ "c8": "7.11.3",
39
+ "p-wait-for": "4.1.0",
40
+ "typedoc": "0.22.17",
41
+ "typescript": "4.7.2",
42
+ "vitest": "0.13.1"
44
43
  },
45
44
  "jest": {
46
45
  "testEnvironment": "node",
47
46
  "coverageProvider": "v8"
48
47
  },
49
- "babel": {
50
- "presets": [
51
- "@babel/preset-typescript"
52
- ],
53
- "plugins": [
54
- "@babel/plugin-transform-modules-commonjs"
55
- ]
56
- },
57
48
  "publishConfig": {
58
49
  "access": "public"
59
50
  },
60
51
  "release": {
61
- "branch": "master"
52
+ "branches": [
53
+ "master"
54
+ ]
62
55
  },
63
56
  "engines": {
64
- "node": ">=10.19.0"
57
+ "node": ">=14.16"
65
58
  }
66
59
  }
package/dist/index.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './transmission';
2
- export * from './types';
package/dist/index.js DELETED
@@ -1,14 +0,0 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5
- }) : (function(o, m, k, k2) {
6
- if (k2 === undefined) k2 = k;
7
- o[k2] = m[k];
8
- }));
9
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
10
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11
- };
12
- Object.defineProperty(exports, "__esModule", { value: true });
13
- __exportStar(require("./transmission"), exports);
14
- __exportStar(require("./types"), exports);
package/dist/types.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });