@fett/synology-api 0.0.1-beta.9 → 0.0.2-beta.1

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.
Files changed (114) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +72 -11
  3. package/lib/cli/apis.d.ts +7 -0
  4. package/lib/cli/apis.js +57 -0
  5. package/lib/{types/cli → cli}/config.d.ts +0 -1
  6. package/lib/{esm/cli → cli}/config.js +40 -45
  7. package/lib/cli/core.js +20 -0
  8. package/lib/{types/cli → cli}/helper.d.ts +1 -0
  9. package/lib/{esm/cli → cli}/helper.js +9 -5
  10. package/lib/cli/index.d.ts +2 -0
  11. package/lib/cli/index.js +5 -0
  12. package/lib/{types/core.d.ts → core.d.ts} +1 -1
  13. package/lib/core.js +99 -0
  14. package/lib/decorators/bindMethods.d.ts +5 -0
  15. package/lib/decorators/bindMethods.js +29 -0
  16. package/lib/decorators/index.d.ts +1 -0
  17. package/lib/decorators/index.js +1 -0
  18. package/lib/{types/errorcodes.d.ts → errorcodes.d.ts} +2 -2
  19. package/lib/{esm/errorcodes.js → errorcodes.js} +10 -5
  20. package/lib/helpers.js +73 -0
  21. package/lib/index.d.ts +4 -0
  22. package/lib/index.js +4 -0
  23. package/lib/{types/modules → modules}/Api/Auth.d.ts +2 -2
  24. package/lib/modules/Api/Auth.js +30 -0
  25. package/lib/modules/Api/Info.d.ts +3 -0
  26. package/lib/modules/Api/Info.js +15 -0
  27. package/lib/modules/Api/index.d.ts +2 -0
  28. package/lib/modules/Api/index.js +2 -0
  29. package/lib/modules/AudioStation/Album.d.ts +30 -0
  30. package/lib/modules/AudioStation/Album.js +17 -0
  31. package/lib/modules/AudioStation/Artist.d.ts +25 -0
  32. package/lib/modules/AudioStation/Artist.js +17 -0
  33. package/lib/modules/AudioStation/Folder.d.ts +24 -0
  34. package/lib/modules/AudioStation/Folder.js +17 -0
  35. package/lib/modules/AudioStation/Info.d.ts +45 -0
  36. package/lib/modules/AudioStation/Info.js +9 -0
  37. package/lib/modules/AudioStation/Lyrics.d.ts +25 -0
  38. package/lib/modules/AudioStation/Lyrics.js +23 -0
  39. package/lib/modules/AudioStation/Playlist.d.ts +34 -0
  40. package/lib/modules/AudioStation/Playlist.js +38 -0
  41. package/lib/modules/AudioStation/Search.d.ts +53 -0
  42. package/lib/modules/AudioStation/Search.js +17 -0
  43. package/lib/modules/AudioStation/Song.d.ts +33 -0
  44. package/lib/modules/AudioStation/Song.js +27 -0
  45. package/lib/modules/AudioStation/index.d.ts +23 -0
  46. package/lib/modules/AudioStation/index.js +23 -0
  47. package/lib/modules/Auth/AuthKey.d.ts +8 -0
  48. package/lib/modules/Auth/AuthKey.js +12 -0
  49. package/lib/modules/Auth/index.d.ts +7 -0
  50. package/lib/modules/Auth/index.js +8 -0
  51. package/lib/modules/FileStation/File.d.ts +0 -0
  52. package/lib/modules/FileStation/File.js +0 -0
  53. package/lib/{types/modules → modules}/FileStation/Info.d.ts +1 -1
  54. package/lib/modules/FileStation/Info.js +9 -0
  55. package/lib/{types/modules → modules}/FileStation/List.d.ts +1 -1
  56. package/lib/modules/FileStation/List.js +30 -0
  57. package/lib/{types/modules → modules}/FileStation/index.d.ts +4 -4
  58. package/lib/{esm/modules → modules}/FileStation/index.js +4 -4
  59. package/lib/modules/VideoStation/File.d.ts +48 -0
  60. package/lib/modules/VideoStation/File.js +20 -0
  61. package/lib/modules/VideoStation/HomeVideo.d.ts +6 -0
  62. package/lib/modules/VideoStation/HomeVideo.js +10 -0
  63. package/lib/modules/VideoStation/Info.d.ts +44 -0
  64. package/lib/modules/VideoStation/Info.js +9 -0
  65. package/lib/modules/VideoStation/Library.d.ts +70 -0
  66. package/lib/modules/VideoStation/Library.js +23 -0
  67. package/lib/modules/VideoStation/Movie.d.ts +27 -0
  68. package/lib/modules/VideoStation/Movie.js +13 -0
  69. package/lib/modules/VideoStation/Streaming.d.ts +11 -0
  70. package/lib/modules/VideoStation/Streaming.js +24 -0
  71. package/lib/modules/VideoStation/index.d.ts +15 -0
  72. package/lib/modules/VideoStation/index.js +16 -0
  73. package/lib/modules/VideoStation/types.d.ts +27 -0
  74. package/lib/modules/VideoStation/types.js +1 -0
  75. package/lib/modules/index.d.ts +27 -0
  76. package/lib/modules/index.js +75 -0
  77. package/lib/types/{types/apiInfo.d.ts → apiInfo.d.ts} +15 -2
  78. package/lib/{esm/types → types}/apiInfo.js +15 -1
  79. package/lib/types/index.d.ts +2 -5
  80. package/lib/types/index.js +2 -0
  81. package/lib/{types/utils.d.ts → utils.d.ts} +1 -0
  82. package/lib/{esm/utils.js → utils.js} +3 -0
  83. package/package.json +27 -24
  84. package/bin/syno +0 -6
  85. package/lib/cjs/index.js +0 -728
  86. package/lib/esm/cli/apis.js +0 -53
  87. package/lib/esm/cli/index.js +0 -30
  88. package/lib/esm/core.js +0 -111
  89. package/lib/esm/helpers.js +0 -81
  90. package/lib/esm/index.js +0 -5
  91. package/lib/esm/modules/Api/Auth.js +0 -43
  92. package/lib/esm/modules/Api/Info.js +0 -26
  93. package/lib/esm/modules/Api/index.js +0 -2
  94. package/lib/esm/modules/AudioStation/Song.js +0 -18
  95. package/lib/esm/modules/AudioStation/index.js +0 -7
  96. package/lib/esm/modules/FileStation/Info.js +0 -20
  97. package/lib/esm/modules/FileStation/List.js +0 -32
  98. package/lib/esm/modules/index.js +0 -46
  99. package/lib/esm/types/index.js +0 -2
  100. package/lib/types/cli/apis.d.ts +0 -6
  101. package/lib/types/modules/Api/Info.d.ts +0 -3
  102. package/lib/types/modules/Api/index.d.ts +0 -2
  103. package/lib/types/modules/AudioStation/Song.d.ts +0 -22
  104. package/lib/types/modules/AudioStation/index.d.ts +0 -7
  105. package/lib/types/modules/index.d.ts +0 -16
  106. package/lib/types/types/index.d.ts +0 -2
  107. /package/lib/{types/cli/index.d.ts → cli/core.d.ts} +0 -0
  108. /package/lib/{types/constants.d.ts → constants.d.ts} +0 -0
  109. /package/lib/{esm/constants.js → constants.js} +0 -0
  110. /package/lib/{types/helpers.d.ts → helpers.d.ts} +0 -0
  111. /package/lib/{esm/modules/FileStation/File.js → modules/AudioStation/Cover.d.ts} +0 -0
  112. /package/lib/{types/modules/FileStation/File.d.ts → modules/AudioStation/Cover.js} +0 -0
  113. /package/lib/types/{types/request.d.ts → request.d.ts} +0 -0
  114. /package/lib/{esm/types → types}/request.js +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Chris Song
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,26 +1,87 @@
1
- # Synology Api
1
+ <p align="center">
2
+ <a >
3
+ <img width="100" src="assets/logo.png">
4
+ </a>
5
+ </p>
6
+ <h1 align="center">Javascript Synology Api</h1>
2
7
 
3
- nodejs synology api wrapper
8
+ ⚠️ The project is under development ...
4
9
 
5
- ## Usage
10
+ Synology Api Javascript wrapper, can be used in Browser、CLI or Nodejs to interact with Synology NAS.
11
+ You can use domain or ip address, also supports Synology Quick Connect connect Synology server.
12
+ All apis from [https://kb.synology.cn](https://kb.synology.cn/zh-cn/search?query=API&services%5B%5D=File_Station)
13
+
14
+ ## Install
15
+
16
+ ```
17
+ npm install @fett/synology-api
18
+ ```
19
+
20
+ ## Use In Browser or Node.js
21
+
22
+ First you need to confirm that you can access across domains,for example in the React Native environment
6
23
 
7
24
  ```js
8
25
  import SynologyApi from '@fett/synology-api';
9
26
 
10
- // Create a new instance
11
27
  const synologyApi = new SynologyApi(
12
- server: "https:192.168.1.1:5001",
13
- username: "admin",
14
- password: "password",
28
+ server: "https://192.168.1.1:5001",
29
+ username: "username",
30
+ password: "password",
15
31
  );
16
32
 
17
- // you can now use the api by calling the methods
18
33
  const info = await synologyApi.FileStation.getInfo();
34
+ console.log(info);
35
+ ```
19
36
 
37
+ ## Use In CLI
38
+
39
+ First install the package globally
40
+
41
+ ```bash
42
+ npm i -g @fett/synology-api
43
+ ```
44
+
45
+ Then run cmd help message
46
+
47
+ ```bash
48
+ syno --help
20
49
  ```
21
50
 
22
- ## API
51
+ run `syno config -h` you will see the help message
52
+
53
+ ```bash
54
+ Usage: synology config [options] [command]
55
+
56
+ synology api config management
57
+
58
+ Options:
59
+ -h, --help display help for command
60
+
61
+ Commands:
62
+ ls List all the connection config
63
+ add [options] [name] Add connection config
64
+ use [name] Change current connection
65
+ del [name] Remove a connection
66
+ rename <name> <newName> Change connection name
67
+ help [command] display help for command
68
+ ```
69
+
70
+ add a connect configuration
71
+
72
+ ```bash
73
+ syno config add newConnetionName --server=https://192.168.1.1:5001 --username=admin --password=password
74
+ ```
75
+
76
+ then you can use it and exec command
77
+
78
+ ```bash
79
+ syno config use newConnetionName
80
+
81
+ syno fs getInfo --pretty # print file system info
82
+
83
+ ```
23
84
 
24
- ### FileStation
85
+ ## License
25
86
 
26
- ### AudioStation
87
+ [MIT](https://github.com/ChrisSong1994/synology-api/blob/main/LICENSE)
@@ -0,0 +1,7 @@
1
+ export type MethodOptions = {
2
+ params?: string;
3
+ pretty?: boolean;
4
+ list?: boolean;
5
+ };
6
+ export declare const onMethodCall: (module: string) => (method: string, options: MethodOptions) => Promise<void>;
7
+ export declare const apiCmdRegister: () => void;
@@ -0,0 +1,57 @@
1
+ import { program } from "commander";
2
+ import chalk from "chalk";
3
+ import { loadConfig } from "./config.js";
4
+ import { SynologyApi } from "../core.js";
5
+ import { SynologyApiModules, SynologyApiMethods } from "../modules/index.js";
6
+ import { printMessages } from "./helper.js";
7
+ export const onMethodCall = (module) => async (method, options) => {
8
+ const config = await loadConfig();
9
+ const params = JSON.parse(options.params || "{}");
10
+ const pretty = options.pretty;
11
+ const connection = config.connections?.[config.used];
12
+ if (!connection) {
13
+ throw new Error("Connection undefined");
14
+ }
15
+ if (!SynologyApiMethods[module]) {
16
+ throw new Error(`Module ${module} not found`);
17
+ }
18
+ // list all module methods
19
+ if (!method && options.list) {
20
+ const methods = SynologyApiMethods[module];
21
+ console.log(chalk.greenBright(`${module} methods list:`));
22
+ return printMessages(Object.keys(methods));
23
+ }
24
+ if (!SynologyApiMethods[module]?.[method]) {
25
+ throw new Error(`Module method ${module} not found`);
26
+ }
27
+ if (typeof SynologyApiMethods[module][method] !== "function") {
28
+ throw new Error(`Module method ${module} is not a function`);
29
+ }
30
+ const synologyApi = new SynologyApi(connection);
31
+ const result = await synologyApi[module]?.[method](params);
32
+ if (pretty) {
33
+ console.log(JSON.stringify(result, null, 2));
34
+ }
35
+ else {
36
+ console.log(JSON.stringify(result));
37
+ }
38
+ synologyApi.disconnect();
39
+ process.exit(0);
40
+ };
41
+ // register all modules
42
+ const apisCmdRegisterInfo = SynologyApiModules.map((module) => ({
43
+ cmd: module.KEY,
44
+ alias: module.ALIAS_KEY,
45
+ }));
46
+ export const apiCmdRegister = () => {
47
+ apisCmdRegisterInfo.forEach((info) => {
48
+ program
49
+ .command(`${info.cmd} [method]`)
50
+ .alias(info.alias)
51
+ .option("-p,--params <params>", `${info.cmd} method params`)
52
+ .option("--pretty", "Prettyprint JSON Output")
53
+ .option("-l,--list", `list all ${info.cmd} methods`)
54
+ .description(`Synology ${info.cmd} method call`)
55
+ .action(onMethodCall(info.cmd));
56
+ });
57
+ };
@@ -9,5 +9,4 @@ export type Config = {
9
9
  };
10
10
  export declare const loadConfig: () => Promise<Config>;
11
11
  export declare const updateConfig: (config: Config) => Promise<void>;
12
- export declare const checkConfig: () => Promise<void>;
13
12
  export declare const configCmdRegister: () => void;
@@ -1,47 +1,36 @@
1
- var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
2
- function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
3
- return new (P || (P = Promise))(function (resolve, reject) {
4
- function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
5
- function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
6
- function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
7
- step((generator = generator.apply(thisArg, _arguments || [])).next());
8
- });
9
- };
10
1
  import fse from "fs-extra";
11
2
  import path from "path";
12
3
  import os from "os";
13
4
  import { program } from "commander";
14
5
  import chalk from "chalk";
15
- import { isLowerCaseEqual, printMessages, geneDashLine } from "./helper";
6
+ import { isLowerCaseEqual, printMessages, geneDashLine } from "./helper.js";
16
7
  const CONFIG_FILE_PATH = process.env.NODE_ENV === "development"
17
8
  ? path.join(process.cwd(), "./.userdata/.synology-api.json") // development
18
9
  : path.join(os.homedir(), "./.synology-api.json");
19
10
  // load config
20
- export const loadConfig = () => __awaiter(void 0, void 0, void 0, function* () {
21
- if (!(yield fse.pathExists(CONFIG_FILE_PATH))) {
22
- yield fse.ensureFile(CONFIG_FILE_PATH);
23
- yield fse.writeJSON(CONFIG_FILE_PATH, {
11
+ export const loadConfig = async () => {
12
+ if (!(await fse.pathExists(CONFIG_FILE_PATH))) {
13
+ await fse.ensureFile(CONFIG_FILE_PATH);
14
+ await fse.writeJSON(CONFIG_FILE_PATH, {
24
15
  used: "",
25
16
  connections: {},
26
17
  });
27
18
  }
28
- const config = yield fse.readJSON(CONFIG_FILE_PATH);
19
+ const config = await fse.readJSON(CONFIG_FILE_PATH);
29
20
  return config;
30
- });
21
+ };
31
22
  // update config
32
- export const updateConfig = (config) => __awaiter(void 0, void 0, void 0, function* () {
33
- yield fse.writeJSON(CONFIG_FILE_PATH, config);
34
- });
35
- // check config
36
- export const checkConfig = () => __awaiter(void 0, void 0, void 0, function* () { });
23
+ export const updateConfig = async (config) => {
24
+ await fse.writeJSON(CONFIG_FILE_PATH, config);
25
+ };
37
26
  export const configCmdRegister = () => {
38
27
  const configCmd = program.command("config").description("synology api config management");
39
28
  // list connection config
40
29
  configCmd
41
30
  .command("ls")
42
31
  .description("List all the connection config")
43
- .action(() => __awaiter(void 0, void 0, void 0, function* () {
44
- const config = yield loadConfig();
32
+ .action(async () => {
33
+ const config = await loadConfig();
45
34
  const keys = Object.keys(config.connections);
46
35
  const dashLineLength = Math.max(...keys.map((key) => key.length)) + 3;
47
36
  const messages = keys.map((key) => {
@@ -57,32 +46,38 @@ export const configCmdRegister = () => {
57
46
  connection.password);
58
47
  });
59
48
  printMessages(messages);
60
- }));
49
+ });
61
50
  // add connection
62
51
  configCmd
63
- .command("add [name]")
52
+ .command("add <name>")
64
53
  .description("Add connection config")
65
54
  .requiredOption("-s, --server <server>", "Synology server domain or QuickConnect ID ")
66
55
  .requiredOption("-u, --username <username>", "username")
67
56
  .requiredOption("-p, --password <password>", "password")
68
- .action((name, options) => __awaiter(void 0, void 0, void 0, function* () {
57
+ .action(async (name, options) => {
69
58
  if (!name.trim())
70
59
  throw new Error("Plaease input connection name");
71
60
  // 实际代码中应保存配置到文件
72
- const config = yield loadConfig();
73
- const newConfig = Object.assign(Object.assign({}, config), { connections: Object.assign(Object.assign({}, config.connections), { [name]: {
61
+ const config = await loadConfig();
62
+ const newConfig = {
63
+ used: config.used || name,
64
+ connections: {
65
+ ...config.connections,
66
+ [name]: {
74
67
  server: options.server,
75
68
  username: options.username,
76
69
  password: options.password,
77
- } }) });
78
- yield updateConfig(newConfig);
79
- }));
70
+ },
71
+ },
72
+ };
73
+ await updateConfig(newConfig);
74
+ });
80
75
  // use connection
81
76
  configCmd
82
- .command("use [name]")
77
+ .command("use <name>")
83
78
  .description("Change current connection")
84
- .action((name) => __awaiter(void 0, void 0, void 0, function* () {
85
- const config = yield loadConfig();
79
+ .action(async (name) => {
80
+ const config = await loadConfig();
86
81
  if (config.used === name)
87
82
  return;
88
83
  if (!config.connections[name]) {
@@ -90,15 +85,15 @@ export const configCmdRegister = () => {
90
85
  return;
91
86
  }
92
87
  config.used = name;
93
- yield updateConfig(config);
94
- }));
88
+ await updateConfig(config);
89
+ });
95
90
  // del connection
96
91
  configCmd
97
- .command("del [name]")
92
+ .command("del <name>")
98
93
  .description("Remove a connection")
99
- .action((name) => __awaiter(void 0, void 0, void 0, function* () {
94
+ .action(async (name) => {
100
95
  console.log("Remove a connection", name);
101
- const config = yield loadConfig();
96
+ const config = await loadConfig();
102
97
  // 删除配置
103
98
  if (!config.connections[name]) {
104
99
  console.log("Connection not found");
@@ -108,14 +103,14 @@ export const configCmdRegister = () => {
108
103
  if (config.used === name) {
109
104
  config.used = "";
110
105
  }
111
- yield updateConfig(config);
112
- }));
106
+ await updateConfig(config);
107
+ });
113
108
  // Change connection name
114
109
  configCmd
115
110
  .command("rename <name> <newName>")
116
111
  .description("Change connection name")
117
- .action((name, newName) => __awaiter(void 0, void 0, void 0, function* () {
118
- const config = yield loadConfig();
112
+ .action(async (name, newName) => {
113
+ const config = await loadConfig();
119
114
  if (!config.connections[name]) {
120
115
  console.log("Connection not found");
121
116
  return;
@@ -125,6 +120,6 @@ export const configCmdRegister = () => {
125
120
  if (config.used === name) {
126
121
  config.used = newName;
127
122
  }
128
- yield updateConfig(config);
129
- }));
123
+ await updateConfig(config);
124
+ });
130
125
  };
@@ -0,0 +1,20 @@
1
+ import fse from "fs-extra";
2
+ import path from "path";
3
+ import { program } from "commander";
4
+ import { configCmdRegister } from "./config.js";
5
+ import { apiCmdRegister } from "./apis.js";
6
+ import { __dirname } from "./helper.js";
7
+ export async function loadCli() {
8
+ // git program info
9
+ const pkg = await fse.readJSON(path.join(__dirname(), "../../package.json"));
10
+ // command
11
+ program
12
+ .name("synology")
13
+ .usage("<command> [options]")
14
+ .description("synology api cli tool")
15
+ .version(pkg.version, "-v, --version", "output the version number");
16
+ // register commands
17
+ configCmdRegister();
18
+ apiCmdRegister();
19
+ program.parse(process.argv);
20
+ }
@@ -1,3 +1,4 @@
1
+ export declare const __dirname: () => string;
1
2
  export declare function printMessages(messages: string[]): void;
2
3
  export declare function isLowerCaseEqual(str1: string, str2: string): boolean;
3
4
  export declare function padding(message?: string, before?: number, after?: number): string;
@@ -1,4 +1,10 @@
1
1
  import chalk from "chalk";
2
+ import { fileURLToPath } from "url";
3
+ import { dirname } from "path";
4
+ export const __dirname = () => {
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ return dirname(__filename);
7
+ };
2
8
  export function printMessages(messages) {
3
9
  console.log(messages.join("\n"));
4
10
  }
@@ -8,12 +14,10 @@ export function isLowerCaseEqual(str1, str2) {
8
14
  }
9
15
  return !str1 && !str2;
10
16
  }
11
- export function padding(message = '', before = 1, after = 1) {
12
- return (new Array(before).fill(' ').join('') +
13
- message +
14
- new Array(after).fill(' ').join(''));
17
+ export function padding(message = "", before = 1, after = 1) {
18
+ return new Array(before).fill(" ").join("") + message + new Array(after).fill(" ").join("");
15
19
  }
16
20
  export function geneDashLine(message, length) {
17
- const finalMessage = new Array(Math.max(2, length - message.length + 2)).join('-');
21
+ const finalMessage = new Array(Math.max(2, length - message.length + 2)).join("-");
18
22
  return padding(chalk.dim(finalMessage));
19
23
  }
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env node
2
+ import { loadCli } from "./core.js";
3
+ (async () => {
4
+ await loadCli();
5
+ })();
@@ -1,4 +1,4 @@
1
- import { BaseSynologyApi } from "./modules";
1
+ import { BaseSynologyApi } from "./modules/index.js";
2
2
  export interface SynologyApiOptions {
3
3
  server: string;
4
4
  username: string;
package/lib/core.js ADDED
@@ -0,0 +1,99 @@
1
+ // reference: https://kb.synology.com/zh-tw/DSM/tutorial/What_websites_does_Synology_NAS_connect_to_when_running_services_or_updating_software
2
+ import ky from "ky";
3
+ import { BaseSynologyApi } from "./modules/index.js";
4
+ import { isHttpUrl, getApiKey, isUndfined } from "./utils.js";
5
+ import { getServerInfo } from "./helpers.js";
6
+ import { login, logout, getApiInfo } from "./modules/Api/index.js";
7
+ import { resWithErrorCode } from "./errorcodes.js";
8
+ export class SynologyApi extends BaseSynologyApi {
9
+ constructor(options) {
10
+ super();
11
+ this.isConnecting = false;
12
+ this.authInfo = null;
13
+ this.apiInfo = {};
14
+ this.server = options.server;
15
+ this.username = options.username;
16
+ this.password = options.password;
17
+ this.baseUrl = `${this.server}/webapi/`;
18
+ }
19
+ async connect() {
20
+ // if quickconnect id
21
+ if (!isHttpUrl(this.server)) {
22
+ this.server = await getServerInfo(this.server);
23
+ // reset base url
24
+ this.baseUrl = `${this.server}/webapi/`;
25
+ }
26
+ try {
27
+ const result = await login(this);
28
+ this.authInfo = result.data;
29
+ this.isConnecting = true;
30
+ await this._getApiInfo();
31
+ return true;
32
+ }
33
+ catch (err) {
34
+ console.error(err);
35
+ return false;
36
+ }
37
+ }
38
+ async disconnect() {
39
+ try {
40
+ await logout(this);
41
+ this.authInfo = null;
42
+ this.apiInfo = {};
43
+ this.isConnecting = false;
44
+ return true;
45
+ }
46
+ catch (err) {
47
+ console.error(err);
48
+ return false;
49
+ }
50
+ }
51
+ async _getApiInfo() {
52
+ try {
53
+ const result = await getApiInfo(this);
54
+ this.apiInfo = result.data;
55
+ }
56
+ catch (err) {
57
+ console.error(err);
58
+ }
59
+ }
60
+ hasApi(apiName) {
61
+ if (!this.isConnecting) {
62
+ throw new Error("Not connected");
63
+ }
64
+ return Object.prototype.hasOwnProperty.call(this.apiInfo, apiName);
65
+ }
66
+ async run(apiName, options) {
67
+ if (!this.isConnecting) {
68
+ const res = await this.connect();
69
+ if (!res) {
70
+ throw new Error("Not connected");
71
+ }
72
+ }
73
+ if (!this.hasApi(apiName)) {
74
+ throw new Error(`${apiName} not found`);
75
+ }
76
+ const { method = "get", params, data, headers } = options;
77
+ const api = this.apiInfo[apiName];
78
+ const url = `${this.baseUrl}${api.path}`;
79
+ const externalParams = {
80
+ api: apiName,
81
+ version: api.maxVersion,
82
+ _sid: this.authInfo.sid,
83
+ ...params,
84
+ };
85
+ let result = null;
86
+ if (method === "get") {
87
+ result = await ky.get(url, { searchParams: externalParams, headers }).json();
88
+ }
89
+ if (method === "post") {
90
+ result = await ky.post(url, { searchParams: externalParams, json: data, headers }).json();
91
+ }
92
+ // match error code msg
93
+ const apiKey = getApiKey(apiName);
94
+ if (!isUndfined(apiKey)) {
95
+ result = resWithErrorCode(apiKey, result);
96
+ }
97
+ return result;
98
+ }
99
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * bind methods to BaseSynologyApi prototype
3
+ * @param source
4
+ */
5
+ export declare function BindMethods<T extends object>(source: T): ClassDecorator;
@@ -0,0 +1,29 @@
1
+ // bind methods to context
2
+ function methodsBundler(cxt, methods) {
3
+ const output = {};
4
+ for (const key in methods) {
5
+ output[key] = methods[key].bind(cxt);
6
+ }
7
+ return output;
8
+ }
9
+ /**
10
+ * bind methods to BaseSynologyApi prototype
11
+ * @param source
12
+ */
13
+ export function BindMethods(source) {
14
+ return function (target) {
15
+ const modulesKeys = Object.getOwnPropertyNames(source);
16
+ modulesKeys.forEach((moduleName) => {
17
+ const methods = source[moduleName];
18
+ const descriptor = {
19
+ configurable: false,
20
+ enumerable: true,
21
+ get() {
22
+ return methodsBundler(this, methods);
23
+ },
24
+ set() { },
25
+ };
26
+ Object.defineProperty(target.prototype, moduleName, descriptor);
27
+ });
28
+ };
29
+ }
@@ -0,0 +1 @@
1
+ export * from "./bindMethods.js";
@@ -0,0 +1 @@
1
+ export * from "./bindMethods.js";
@@ -1,5 +1,5 @@
1
- import { SynologyApiKeys } from "./modules";
2
- import { SynologyApiResponse } from "./types";
1
+ import { SynologyApiKeys } from "./modules/index.js";
2
+ import { SynologyApiResponse } from "./types/index.js";
3
3
  export declare const SYNOLOGY_ERROR_CODES: {
4
4
  [SynologyApiKeys.FileStation]: {
5
5
  400: string;
@@ -1,5 +1,5 @@
1
- import { SynologyApiKeys } from "./modules";
2
- import { isUndfined } from "./utils";
1
+ import { SynologyApiKeys } from "./modules/index.js";
2
+ import { isUndfined } from "./utils.js";
3
3
  const CODE_SUCCESS = 0;
4
4
  const CODE_UNKNOWN = 9999;
5
5
  export const SYNOLOGY_ERROR_CODES = {
@@ -88,10 +88,15 @@ export const SYNOLOGY_ERROR_CODES = {
88
88
  },
89
89
  };
90
90
  export const resWithErrorCode = (apiKey, res) => {
91
- var _a, _b;
92
91
  const errorCodes = SYNOLOGY_ERROR_CODES[apiKey];
93
- const code = (_a = res === null || res === void 0 ? void 0 : res.error) === null || _a === void 0 ? void 0 : _a.code;
92
+ const code = res?.error?.code;
94
93
  if (isUndfined(code))
95
94
  return res;
96
- return Object.assign(Object.assign({}, res), { error: Object.assign(Object.assign({}, res.error), { message: ((_b = res === null || res === void 0 ? void 0 : res.error) === null || _b === void 0 ? void 0 : _b.message) || (errorCodes === null || errorCodes === void 0 ? void 0 : errorCodes[code]) || "Unknown error" }) });
95
+ return {
96
+ ...res,
97
+ error: {
98
+ ...res.error,
99
+ message: res?.error?.message || errorCodes?.[code] || "Unknown error",
100
+ },
101
+ };
97
102
  };