@ctrl/deluge 7.0.0 → 7.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/README.md CHANGED
@@ -70,6 +70,15 @@ const res = await client.removeTorrent('torrent_id', true);
70
70
  console.log(res);
71
71
  ```
72
72
 
73
+ ##### export and create from state
74
+
75
+ If you're shutting down the server often (serverless?) you can export the state
76
+
77
+ ```ts
78
+ const state = client.exportState()
79
+ const client = Deluge.createFromState(config, state);
80
+ ```
81
+
73
82
  ### See Also
74
83
  transmission - https://github.com/scttcper/transmission
75
84
  qbittorrent - https://github.com/scttcper/qbittorrent
@@ -1,11 +1,20 @@
1
1
  import { ofetch } from 'ofetch';
2
- import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
2
+ import { Cookie } from 'tough-cookie';
3
+ import type { Jsonify } from 'type-fest';
4
+ import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentClientConfig, TorrentClientState } from '@ctrl/shared-torrent';
3
5
  import type { AddTorrentOptions, AddTorrentResponse, BooleanStatus, ConfigResponse, DefaultResponse, DelugeSettings, GetHostsResponse, GetHostStatusResponse, ListMethods, PluginInfo, PluginsListResponse, StringStatus, TorrentFiles, TorrentInfo, TorrentListResponse, TorrentOptions, TorrentStatus, Tracker, UploadResponse } from './types.js';
6
+ interface DelugeState extends TorrentClientState {
7
+ auth: {
8
+ cookie?: Cookie;
9
+ msgId: number;
10
+ };
11
+ }
4
12
  export declare class Deluge implements TorrentClient {
5
- config: TorrentSettings;
6
- private _msgId;
7
- private _cookie?;
8
- constructor(options?: Partial<TorrentSettings>);
13
+ static createFromState(config: Readonly<TorrentClientConfig>, state: Readonly<Jsonify<DelugeState>>): Deluge;
14
+ config: TorrentClientConfig;
15
+ state: DelugeState;
16
+ constructor(options?: Partial<TorrentClientConfig>);
17
+ exportState(): Jsonify<DelugeState>;
9
18
  resetSession(): void;
10
19
  getHosts(): Promise<GetHostsResponse>;
11
20
  /**
@@ -108,3 +117,4 @@ export declare class Deluge implements TorrentClient {
108
117
  request<T extends object>(method: string, params?: any[], needsAuth?: boolean, autoConnect?: boolean): Promise<ReturnType<typeof ofetch.raw<T>>>;
109
118
  private _validateAuth;
110
119
  }
120
+ export {};
@@ -12,15 +12,37 @@ const defaults = {
12
12
  timeout: 5000,
13
13
  };
14
14
  export class Deluge {
15
+ static createFromState(config, state) {
16
+ const deluge = new Deluge(config);
17
+ deluge.state = {
18
+ ...state,
19
+ auth: state.auth
20
+ ? {
21
+ cookie: Cookie.fromJSON(state.auth.cookie),
22
+ msgId: state.auth.msgId,
23
+ }
24
+ : { msgId: 0 },
25
+ };
26
+ return deluge;
27
+ }
15
28
  config;
16
- _msgId = 0;
17
- _cookie;
29
+ state = { auth: { msgId: 0 } };
18
30
  constructor(options = {}) {
19
31
  this.config = { ...defaults, ...options };
20
32
  }
33
+ exportState() {
34
+ return JSON.parse(JSON.stringify({
35
+ ...this.state,
36
+ auth: this.state.auth
37
+ ? {
38
+ cookie: this.state.auth.cookie.toJSON(),
39
+ msgId: this.state.auth.msgId,
40
+ }
41
+ : { msgId: 0 },
42
+ }));
43
+ }
21
44
  resetSession() {
22
- this._cookie = undefined;
23
- this._msgId = 0;
45
+ this.state.auth = { msgId: 0 };
24
46
  }
25
47
  async getHosts() {
26
48
  const res = await this.request('web.get_hosts', [], true, false);
@@ -75,15 +97,15 @@ export class Deluge {
75
97
  */
76
98
  async checkSession() {
77
99
  // cookie is missing or expires in x seconds
78
- if (this._cookie) {
100
+ if (this.state.auth.cookie) {
79
101
  // eslint-disable-next-line new-cap
80
- if (this._cookie.TTL() < 5000) {
102
+ if (this.state.auth.cookie.TTL() < 5000) {
81
103
  this.resetSession();
82
104
  return false;
83
105
  }
84
106
  return true;
85
107
  }
86
- if (this._cookie) {
108
+ if (this.state.auth.cookie) {
87
109
  try {
88
110
  const check = await this.request('auth.check_session', undefined, false);
89
111
  const body = await check.json();
@@ -108,7 +130,7 @@ export class Deluge {
108
130
  if (!res.ok || !res.headers?.get('set-cookie')?.length) {
109
131
  throw new Error('Auth failed, incorrect password');
110
132
  }
111
- this._cookie = Cookie.parse(res.headers.get('set-cookie'));
133
+ this.state.auth.cookie = Cookie.parse(res.headers.get('set-cookie'));
112
134
  return true;
113
135
  }
114
136
  /**
@@ -298,7 +320,7 @@ export class Deluge {
298
320
  }
299
321
  // update current password to new password
300
322
  this.config.password = password;
301
- this._cookie = Cookie.parse(res.headers.get('set-cookie'));
323
+ this.state.auth.cookie = Cookie.parse(res.headers.get('set-cookie'));
302
324
  return body;
303
325
  }
304
326
  async getAllData() {
@@ -512,8 +534,8 @@ export class Deluge {
512
534
  return req._data;
513
535
  }
514
536
  async request(method, params = [], needsAuth = true, autoConnect = true) {
515
- if (this._msgId === 4096) {
516
- this._msgId = 0;
537
+ if (this.state.auth.msgId === 4096) {
538
+ this.state.auth.msgId = 0;
517
539
  }
518
540
  if (needsAuth) {
519
541
  await this._validateAuth();
@@ -525,7 +547,7 @@ export class Deluge {
525
547
  }
526
548
  }
527
549
  const headers = {
528
- Cookie: this._cookie?.cookieString?.(),
550
+ Cookie: this.state.auth.cookie?.cookieString?.(),
529
551
  };
530
552
  const url = joinURL(this.config.baseUrl, this.config.path);
531
553
  const res = await ofetch.raw(url, {
@@ -533,7 +555,7 @@ export class Deluge {
533
555
  body: JSON.stringify({
534
556
  method,
535
557
  params,
536
- id: this._msgId++,
558
+ id: this.state.auth.msgId++,
537
559
  }),
538
560
  headers,
539
561
  retry: 0,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl/deluge",
3
- "version": "7.0.0",
3
+ "version": "7.1.0",
4
4
  "description": "TypeScript api wrapper for deluge using got",
5
5
  "author": "Scott Cooper <scttcper@gmail.com>",
6
6
  "license": "MIT",
@@ -33,23 +33,24 @@
33
33
  },
34
34
  "dependencies": {
35
35
  "@ctrl/magnet-link": "^4.0.2",
36
- "@ctrl/shared-torrent": "^6.1.0",
36
+ "@ctrl/shared-torrent": "^6.2.1",
37
37
  "node-fetch-native": "^1.6.4",
38
38
  "ofetch": "^1.4.1",
39
39
  "tough-cookie": "^5.0.0",
40
+ "type-fest": "^4.30.2",
40
41
  "ufo": "^1.5.4",
41
42
  "uint8array-extras": "^1.4.0"
42
43
  },
43
44
  "devDependencies": {
44
45
  "@biomejs/biome": "1.9.4",
45
- "@ctrl/eslint-config-biome": "4.2.11",
46
- "@sindresorhus/tsconfig": "6.0.0",
47
- "@types/node": "22.9.0",
48
- "@vitest/coverage-v8": "2.1.4",
46
+ "@ctrl/eslint-config-biome": "4.3.1",
47
+ "@sindresorhus/tsconfig": "7.0.0",
48
+ "@types/node": "22.10.2",
49
+ "@vitest/coverage-v8": "2.1.8",
49
50
  "p-wait-for": "5.0.2",
50
- "typedoc": "0.26.11",
51
- "typescript": "5.6.3",
52
- "vitest": "2.1.4"
51
+ "typedoc": "0.27.5",
52
+ "typescript": "5.7.2",
53
+ "vitest": "2.1.8"
53
54
  },
54
55
  "publishConfig": {
55
56
  "access": "public",