ogi-addon 0.2.0 → 0.3.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/package.json CHANGED
@@ -1,50 +1,50 @@
1
- {
2
- "name": "ogi-addon",
3
- "module": "./build/main.js",
4
- "type": "module",
5
- "main": "./build/main.cjs",
6
- "exports": {
7
- ".": {
8
- "import": {
9
- "default": "./build/main.js",
10
- "types": "./build/main.d.ts"
11
- },
12
- "require": {
13
- "default": "./build/main.cjs",
14
- "types": "./build/main.d.cts"
15
- }
16
- },
17
- "./config": {
18
- "import": {
19
- "default": "./build/config/Configuration.js",
20
- "types": "./build/config/Configuration.d.ts"
21
- },
22
- "require": {
23
- "default": "./build/config/Configuration.cjs",
24
- "types": "./build/config/Configuration.d.cts"
25
- }
26
- }
27
- },
28
- "typings": "./build/main.d.ts",
29
- "author": {
30
- "name": "Nat3z",
31
- "email": "me@nat3z.com",
32
- "url": "https://nat3z.com/"
33
- },
34
- "version": "0.2.0",
35
- "dependencies": {
36
- "ws": "^8.4.0",
37
- "zod": "^3.23.8"
38
- },
39
- "scripts": {
40
- "auto-build": "tsc -w",
41
- "build": "tsup --config tsup.config.js",
42
- "release": "bun run build && npm publish"
43
- },
44
- "devDependencies": {
45
- "@types/node": "^20.14.12",
46
- "@types/ws": "^8.4.0",
47
- "tsup": "^8.2.3",
48
- "typescript": "^5.0.0"
49
- }
1
+ {
2
+ "name": "ogi-addon",
3
+ "module": "./build/main.js",
4
+ "type": "module",
5
+ "main": "./build/main.cjs",
6
+ "exports": {
7
+ ".": {
8
+ "import": {
9
+ "default": "./build/main.js",
10
+ "types": "./build/main.d.ts"
11
+ },
12
+ "require": {
13
+ "default": "./build/main.cjs",
14
+ "types": "./build/main.d.cts"
15
+ }
16
+ },
17
+ "./config": {
18
+ "import": {
19
+ "default": "./build/config/Configuration.js",
20
+ "types": "./build/config/Configuration.d.ts"
21
+ },
22
+ "require": {
23
+ "default": "./build/config/Configuration.cjs",
24
+ "types": "./build/config/Configuration.d.cts"
25
+ }
26
+ }
27
+ },
28
+ "typings": "./build/main.d.ts",
29
+ "author": {
30
+ "name": "Nat3z",
31
+ "email": "me@nat3z.com",
32
+ "url": "https://nat3z.com/"
33
+ },
34
+ "version": "0.3.0",
35
+ "dependencies": {
36
+ "ws": "^8.4.0",
37
+ "zod": "^3.23.8"
38
+ },
39
+ "scripts": {
40
+ "auto-build": "tsc -w",
41
+ "build": "tsup --config tsup.config.js",
42
+ "release": "bun run build && npm publish"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^20.14.12",
46
+ "@types/ws": "^8.4.0",
47
+ "tsup": "^8.2.3",
48
+ "typescript": "^5.0.0"
49
+ }
50
50
  }
@@ -1,9 +1,17 @@
1
+ import { ConfigurationBuilder } from "./main";
2
+
1
3
  export default class EventResponse<T> {
2
4
  data: T | undefined = undefined;
3
5
  deffered: boolean = false;
4
6
  resolved: boolean = false;
5
7
  progress: number = 0;
6
8
  logs: string[] = [];
9
+ onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>;
10
+
11
+ constructor(onInputAsked?: (screen: ConfigurationBuilder, name: string, description: string) => Promise<{ [key: string]: boolean | string | number }>) {
12
+ this.onInputAsked = onInputAsked;
13
+ }
14
+
7
15
 
8
16
  public defer() {
9
17
  this.deffered = true;
@@ -22,5 +30,12 @@ export default class EventResponse<T> {
22
30
  this.logs.push(message);
23
31
  }
24
32
 
33
+ public async askForInput(name: string, description: string, screen: ConfigurationBuilder) {
34
+ if (!this.onInputAsked) {
35
+ throw new Error('No input asked callback');
36
+ }
37
+ return await this.onInputAsked(screen, name, description);
38
+ }
39
+
25
40
 
26
41
  }
@@ -4,6 +4,7 @@ export type SearchResult = {
4
4
  coverURL: string;
5
5
  downloadType: 'torrent' | 'direct' | 'magnet';
6
6
  downloadSize: number;
7
+ steamAppID?: number;
7
8
  filename?: string;
8
9
  downloadURL?: string;
9
10
  files?: {
@@ -100,6 +100,7 @@ export class StringOption extends ConfigurationOption {
100
100
  public minTextLength: number = 0;
101
101
  public maxTextLength: number = Number.MAX_SAFE_INTEGER;
102
102
  public defaultValue: string = '';
103
+ public inputType: 'text' | 'file' | 'password' | 'folder' = 'text';
103
104
  public type: ConfigurationOptionType = 'string'
104
105
 
105
106
  setAllowedValues(allowedValues: string[]): this {
@@ -122,6 +123,11 @@ export class StringOption extends ConfigurationOption {
122
123
  return this;
123
124
  }
124
125
 
126
+ setInputType(inputType: 'text' | 'file' | 'password' | 'folder'): this {
127
+ this.inputType = inputType;
128
+ return this;
129
+ }
130
+
125
131
  override validate(input: unknown): [ boolean, string ] {
126
132
  if (typeof input !== 'string') {
127
133
  return [ false, 'Input is not a string' ];
package/src/main.ts CHANGED
@@ -6,11 +6,12 @@ import EventResponse from './EventResponse';
6
6
  import { SearchResult } from './SearchEngine';
7
7
 
8
8
  export type OGIAddonEvent = 'connect' | 'disconnect' | 'configure' | 'authenticate' | 'search' | 'setup';
9
- export type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification';
9
+ export type OGIAddonClientSentEvent = 'response' | 'authenticate' | 'configure' | 'defer-update' | 'notification' | 'input-asked';
10
10
 
11
- export type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup';
11
+ export type OGIAddonServerSentEvent = 'authenticate' | 'configure' | 'config-update' | 'search' | 'setup' | 'response';
12
12
  export { ConfigurationBuilder, Configuration, EventResponse, SearchResult };
13
13
  const defaultPort = 7654;
14
+ const version = process.env.npm_package_version;
14
15
 
15
16
  export interface ClientSentEventTypes {
16
17
  response: any;
@@ -21,6 +22,7 @@ export interface ClientSentEventTypes {
21
22
  progress: number
22
23
  };
23
24
  notification: Notification;
25
+ 'input-asked': ConfigurationBuilder;
24
26
  }
25
27
 
26
28
  export interface EventListenerTypes {
@@ -29,7 +31,7 @@ export interface EventListenerTypes {
29
31
  configure: (config: ConfigurationBuilder) => ConfigurationBuilder;
30
32
  response: (response: any) => void;
31
33
  authenticate: (config: any) => void;
32
- search: (query: string, event: EventResponse<SearchResult[]>) => void;
34
+ search: (query: { type: 'steamapp', text: string }, event: EventResponse<SearchResult[]>) => void;
33
35
  setup: (
34
36
  data: {
35
37
  path: string,
@@ -40,7 +42,8 @@ export interface EventListenerTypes {
40
42
  name: string,
41
43
  downloadURL: string
42
44
  }[],
43
- }, event: EventResponse<undefined | null>
45
+ steamAppID: number
46
+ }, event: EventResponse<LibraryInfo>
44
47
  ) => void;
45
48
  }
46
49
 
@@ -86,6 +89,16 @@ export default class OGIAddon {
86
89
  this.addonWSListener.send('notification', [ notification ]);
87
90
  }
88
91
  }
92
+
93
+ export interface LibraryInfo {
94
+ name: string;
95
+ version: string;
96
+ cwd: string;
97
+ steamAppID: number;
98
+ launchExecutable: string;
99
+ launchArguments?: string;
100
+ capsuleImage: string;
101
+ }
89
102
  interface Notification {
90
103
  type: 'warning' | 'error' | 'info' | 'success';
91
104
  message: string;
@@ -105,13 +118,15 @@ class OGIAddonWSListener {
105
118
  this.socket = new ws('ws://localhost:' + defaultPort);
106
119
  this.socket.on('open', () => {
107
120
  console.log('Connected to OGI Addon Server');
121
+ console.log('OGI Addon Server Version:', version);
108
122
 
109
123
  // Authenticate with OGI Addon Server
110
124
  this.socket.send(JSON.stringify({
111
125
  event: 'authenticate',
112
126
  args: {
113
127
  ...this.addon.addonInfo,
114
- secret: process.argv[process.argv.length - 1].split('=')[1]
128
+ secret: process.argv[process.argv.length - 1].split('=')[1],
129
+ ogiVersion: version
115
130
  }
116
131
  }));
117
132
 
@@ -142,12 +157,31 @@ class OGIAddonWSListener {
142
157
  }
143
158
  this.eventEmitter.emit('disconnect', reason);
144
159
  console.log("Disconnected from OGI Addon Server")
160
+ console.log(reason.toString())
145
161
  this.socket.close();
146
162
  });
147
163
 
148
164
  this.registerMessageReceiver();
149
165
  }
150
166
 
167
+ private async userInputAsked(configBuilt: ConfigurationBuilder, name: string, description: string, socket: WebSocket): Promise<{ [key: string]: number | boolean | string }> {
168
+ const config = configBuilt.build(false);
169
+ const id = Math.random().toString(36).substring(7);
170
+ if (!socket) {
171
+ return {};
172
+ }
173
+ socket.send(JSON.stringify({
174
+ event: 'input-asked',
175
+ args: {
176
+ config,
177
+ name,
178
+ description
179
+ },
180
+ id: id
181
+ }));
182
+ return await this.waitForResponseFromServer(id);
183
+ }
184
+
151
185
  private registerMessageReceiver() {
152
186
  this.socket.on('message', async (data: string) => {
153
187
  const message: WebsocketMessageServer = JSON.parse(data);
@@ -162,15 +196,15 @@ class OGIAddonWSListener {
162
196
  }
163
197
  break
164
198
  case 'search':
165
- let searchResultEvent = new EventResponse<SearchResult[]>();
199
+ let searchResultEvent = new EventResponse<SearchResult[]>((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
166
200
  this.eventEmitter.emit('search', message.args, searchResultEvent);
167
201
  const searchResult = await this.waitForEventToRespond(searchResultEvent);
168
202
  console.log(searchResult.data)
169
203
  this.respondToMessage(message.id!!, searchResult.data);
170
204
  break
171
205
  case 'setup':
172
- let setupEvent = new EventResponse<undefined | null>();
173
- this.eventEmitter.emit('setup', { path: message.args.path, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);
206
+ let setupEvent = new EventResponse<LibraryInfo>((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
207
+ this.eventEmitter.emit('setup', { path: message.args.path, steamAppID: message.args.steamAppID, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);
174
208
  const interval = setInterval(() => {
175
209
  if (setupEvent.resolved) {
176
210
  clearInterval(interval);
@@ -224,6 +258,27 @@ class OGIAddonWSListener {
224
258
  console.log("dispatched response to " + messageID)
225
259
  }
226
260
 
261
+ public waitForResponseFromServer<T>(messageID: string): Promise<T> {
262
+ return new Promise((resolve) => {
263
+ const waiter = (data: string) => {
264
+ const message: WebsocketMessageClient = JSON.parse(data);
265
+ if (message.event !== 'response') {
266
+ this.socket.once('message', waiter);
267
+ return;
268
+ }
269
+ console.log("received response from " + messageID)
270
+
271
+ if (message.id === messageID) {
272
+ resolve(message.args);
273
+ }
274
+ else {
275
+ this.socket.once('message', waiter);
276
+ }
277
+ }
278
+ this.socket.once('message', waiter);
279
+ });
280
+ }
281
+
227
282
  public send(event: OGIAddonClientSentEvent, args: Parameters<ClientSentEventTypes[OGIAddonClientSentEvent]>) {
228
283
  this.socket.send(JSON.stringify({
229
284
  event,