ogi-addon 2.0.0 → 2.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/build/{EventResponse-DgSuJPu8.d.cts → EventResponse-Btb5YASI.d.cts} +31 -21
- package/build/{EventResponse-D0TZjAVC.d.mts → EventResponse-Clg-5HI_.d.mts} +31 -21
- package/build/EventResponse.d.cts +1 -1
- package/build/EventResponse.d.mts +1 -1
- package/build/main.cjs +57 -53
- package/build/main.cjs.map +1 -1
- package/build/main.d.cts +2 -2
- package/build/main.d.mts +2 -2
- package/build/main.mjs +58 -53
- package/build/main.mjs.map +1 -1
- package/package.json +1 -1
- package/src/main.ts +92 -59
|
@@ -271,11 +271,9 @@ declare class OGIAddon {
|
|
|
271
271
|
searchGame(query: string, storefront: string): Promise<BasicLibraryInfo[]>;
|
|
272
272
|
/**
|
|
273
273
|
* Notify the OGI Addon Server that you are performing a background task. This can be used to help users understand what is happening in the background.
|
|
274
|
-
* @
|
|
275
|
-
* @param progress {number}
|
|
276
|
-
* @param logs {string[]}
|
|
274
|
+
* @returns {Promise<Task>} A Task instance for managing the background task.
|
|
277
275
|
*/
|
|
278
|
-
task(): Promise<
|
|
276
|
+
task(): Promise<Task>;
|
|
279
277
|
/**
|
|
280
278
|
* Register a task handler for a specific task name. The task name should match the taskName field in SearchResult or ActionOption.
|
|
281
279
|
* @param taskName {string} The name of the task (should match taskName in SearchResult or ActionOption.setTaskName()).
|
|
@@ -321,27 +319,32 @@ declare class OGIAddon {
|
|
|
321
319
|
*/
|
|
322
320
|
extractFile(path: string, outputPath: string, type: 'unrar' | 'unzip'): Promise<void>;
|
|
323
321
|
}
|
|
324
|
-
declare class CustomTask {
|
|
325
|
-
readonly id: string;
|
|
326
|
-
progress: number;
|
|
327
|
-
logs: string[];
|
|
328
|
-
finished: boolean;
|
|
329
|
-
ws: OGIAddonWSListener;
|
|
330
|
-
failed: string | undefined;
|
|
331
|
-
constructor(ws: OGIAddonWSListener, id: string, progress: number, logs: string[]);
|
|
332
|
-
log(log: string): void;
|
|
333
|
-
finish(): void;
|
|
334
|
-
fail(message: string): void;
|
|
335
|
-
setProgress(progress: number): void;
|
|
336
|
-
update(): void;
|
|
337
|
-
}
|
|
338
322
|
/**
|
|
339
|
-
* A
|
|
323
|
+
* A unified task API for both server-initiated tasks (via onTask handlers)
|
|
324
|
+
* and addon-initiated background tasks (via addon.task()).
|
|
340
325
|
* Provides chainable methods for logging, progress updates, and completion.
|
|
341
326
|
*/
|
|
342
327
|
declare class Task {
|
|
343
328
|
private event;
|
|
329
|
+
private ws;
|
|
330
|
+
private readonly id;
|
|
331
|
+
private progress;
|
|
332
|
+
private logs;
|
|
333
|
+
private finished;
|
|
334
|
+
private failed;
|
|
335
|
+
/**
|
|
336
|
+
* Construct a Task from an EventResponse (for onTask handlers).
|
|
337
|
+
* @param event {EventResponse<void>} The event response to wrap.
|
|
338
|
+
*/
|
|
344
339
|
constructor(event: EventResponse<void>);
|
|
340
|
+
/**
|
|
341
|
+
* Construct a Task from WebSocket listener (for addon.task()).
|
|
342
|
+
* @param ws {OGIAddonWSListener} The WebSocket listener.
|
|
343
|
+
* @param id {string} The task ID.
|
|
344
|
+
* @param progress {number} Initial progress (0-100).
|
|
345
|
+
* @param logs {string[]} Initial logs array.
|
|
346
|
+
*/
|
|
347
|
+
constructor(ws: OGIAddonWSListener, id: string, progress: number, logs: string[]);
|
|
345
348
|
/**
|
|
346
349
|
* Log a message to the task. Returns this for chaining.
|
|
347
350
|
* @param message {string} The message to log.
|
|
@@ -363,13 +366,20 @@ declare class Task {
|
|
|
363
366
|
fail(message: string): void;
|
|
364
367
|
/**
|
|
365
368
|
* Ask the user for input using a ConfigurationBuilder screen.
|
|
369
|
+
* Only available for EventResponse-based tasks (onTask handlers).
|
|
366
370
|
* The return type is inferred from the ConfigurationBuilder's accumulated option types.
|
|
367
371
|
* @param name {string} The name/title of the input prompt.
|
|
368
372
|
* @param description {string} The description of what input is needed.
|
|
369
373
|
* @param screen {ConfigurationBuilder<U>} The configuration builder for the input form.
|
|
370
374
|
* @returns {Promise<U>} The user's input with types matching the configuration options.
|
|
375
|
+
* @throws {Error} If called on a WebSocket-based task.
|
|
371
376
|
*/
|
|
372
377
|
askForInput<U extends Record<string, string | number | boolean>>(name: string, description: string, screen: ConfigurationBuilder<U>): Promise<U>;
|
|
378
|
+
/**
|
|
379
|
+
* Update the task state (for WebSocket-based tasks only).
|
|
380
|
+
* Called automatically when using log(), setProgress(), complete(), or fail().
|
|
381
|
+
*/
|
|
382
|
+
private update;
|
|
373
383
|
}
|
|
374
384
|
/**
|
|
375
385
|
* A search tool wrapper over Fuse.js for the OGI Addon. This tool is used to search for items in the library.
|
|
@@ -483,5 +493,5 @@ declare class EventResponse<T> {
|
|
|
483
493
|
askForInput<U extends Record<string, string | number | boolean>>(name: string, description: string, screen: ConfigurationBuilder<U>): Promise<U>;
|
|
484
494
|
}
|
|
485
495
|
//#endregion
|
|
486
|
-
export {
|
|
487
|
-
//# sourceMappingURL=EventResponse-
|
|
496
|
+
export { WebsocketMessageServer as _, LibraryInfo as a, OGIAddonConfiguration as c, SearchTool as d, SetupEventResponse as f, WebsocketMessageClient as g, VERSION as h, EventListenerTypes as i, OGIAddonEvent as l, Task as m, BasicLibraryInfo as n, OGIAddon as o, StoreData as p, ClientSentEventTypes as r, OGIAddonClientSentEvent as s, EventResponse as t, OGIAddonServerSentEvent as u, ZodLibraryInfo as v };
|
|
497
|
+
//# sourceMappingURL=EventResponse-Btb5YASI.d.cts.map
|
|
@@ -271,11 +271,9 @@ declare class OGIAddon {
|
|
|
271
271
|
searchGame(query: string, storefront: string): Promise<BasicLibraryInfo[]>;
|
|
272
272
|
/**
|
|
273
273
|
* Notify the OGI Addon Server that you are performing a background task. This can be used to help users understand what is happening in the background.
|
|
274
|
-
* @
|
|
275
|
-
* @param progress {number}
|
|
276
|
-
* @param logs {string[]}
|
|
274
|
+
* @returns {Promise<Task>} A Task instance for managing the background task.
|
|
277
275
|
*/
|
|
278
|
-
task(): Promise<
|
|
276
|
+
task(): Promise<Task>;
|
|
279
277
|
/**
|
|
280
278
|
* Register a task handler for a specific task name. The task name should match the taskName field in SearchResult or ActionOption.
|
|
281
279
|
* @param taskName {string} The name of the task (should match taskName in SearchResult or ActionOption.setTaskName()).
|
|
@@ -321,27 +319,32 @@ declare class OGIAddon {
|
|
|
321
319
|
*/
|
|
322
320
|
extractFile(path: string, outputPath: string, type: 'unrar' | 'unzip'): Promise<void>;
|
|
323
321
|
}
|
|
324
|
-
declare class CustomTask {
|
|
325
|
-
readonly id: string;
|
|
326
|
-
progress: number;
|
|
327
|
-
logs: string[];
|
|
328
|
-
finished: boolean;
|
|
329
|
-
ws: OGIAddonWSListener;
|
|
330
|
-
failed: string | undefined;
|
|
331
|
-
constructor(ws: OGIAddonWSListener, id: string, progress: number, logs: string[]);
|
|
332
|
-
log(log: string): void;
|
|
333
|
-
finish(): void;
|
|
334
|
-
fail(message: string): void;
|
|
335
|
-
setProgress(progress: number): void;
|
|
336
|
-
update(): void;
|
|
337
|
-
}
|
|
338
322
|
/**
|
|
339
|
-
* A
|
|
323
|
+
* A unified task API for both server-initiated tasks (via onTask handlers)
|
|
324
|
+
* and addon-initiated background tasks (via addon.task()).
|
|
340
325
|
* Provides chainable methods for logging, progress updates, and completion.
|
|
341
326
|
*/
|
|
342
327
|
declare class Task {
|
|
343
328
|
private event;
|
|
329
|
+
private ws;
|
|
330
|
+
private readonly id;
|
|
331
|
+
private progress;
|
|
332
|
+
private logs;
|
|
333
|
+
private finished;
|
|
334
|
+
private failed;
|
|
335
|
+
/**
|
|
336
|
+
* Construct a Task from an EventResponse (for onTask handlers).
|
|
337
|
+
* @param event {EventResponse<void>} The event response to wrap.
|
|
338
|
+
*/
|
|
344
339
|
constructor(event: EventResponse<void>);
|
|
340
|
+
/**
|
|
341
|
+
* Construct a Task from WebSocket listener (for addon.task()).
|
|
342
|
+
* @param ws {OGIAddonWSListener} The WebSocket listener.
|
|
343
|
+
* @param id {string} The task ID.
|
|
344
|
+
* @param progress {number} Initial progress (0-100).
|
|
345
|
+
* @param logs {string[]} Initial logs array.
|
|
346
|
+
*/
|
|
347
|
+
constructor(ws: OGIAddonWSListener, id: string, progress: number, logs: string[]);
|
|
345
348
|
/**
|
|
346
349
|
* Log a message to the task. Returns this for chaining.
|
|
347
350
|
* @param message {string} The message to log.
|
|
@@ -363,13 +366,20 @@ declare class Task {
|
|
|
363
366
|
fail(message: string): void;
|
|
364
367
|
/**
|
|
365
368
|
* Ask the user for input using a ConfigurationBuilder screen.
|
|
369
|
+
* Only available for EventResponse-based tasks (onTask handlers).
|
|
366
370
|
* The return type is inferred from the ConfigurationBuilder's accumulated option types.
|
|
367
371
|
* @param name {string} The name/title of the input prompt.
|
|
368
372
|
* @param description {string} The description of what input is needed.
|
|
369
373
|
* @param screen {ConfigurationBuilder<U>} The configuration builder for the input form.
|
|
370
374
|
* @returns {Promise<U>} The user's input with types matching the configuration options.
|
|
375
|
+
* @throws {Error} If called on a WebSocket-based task.
|
|
371
376
|
*/
|
|
372
377
|
askForInput<U extends Record<string, string | number | boolean>>(name: string, description: string, screen: ConfigurationBuilder<U>): Promise<U>;
|
|
378
|
+
/**
|
|
379
|
+
* Update the task state (for WebSocket-based tasks only).
|
|
380
|
+
* Called automatically when using log(), setProgress(), complete(), or fail().
|
|
381
|
+
*/
|
|
382
|
+
private update;
|
|
373
383
|
}
|
|
374
384
|
/**
|
|
375
385
|
* A search tool wrapper over Fuse.js for the OGI Addon. This tool is used to search for items in the library.
|
|
@@ -483,5 +493,5 @@ declare class EventResponse<T> {
|
|
|
483
493
|
askForInput<U extends Record<string, string | number | boolean>>(name: string, description: string, screen: ConfigurationBuilder<U>): Promise<U>;
|
|
484
494
|
}
|
|
485
495
|
//#endregion
|
|
486
|
-
export {
|
|
487
|
-
//# sourceMappingURL=EventResponse-
|
|
496
|
+
export { WebsocketMessageServer as _, LibraryInfo as a, OGIAddonConfiguration as c, SearchTool as d, SetupEventResponse as f, WebsocketMessageClient as g, VERSION as h, EventListenerTypes as i, OGIAddonEvent as l, Task as m, BasicLibraryInfo as n, OGIAddon as o, StoreData as p, ClientSentEventTypes as r, OGIAddonClientSentEvent as s, EventResponse as t, OGIAddonServerSentEvent as u, ZodLibraryInfo as v };
|
|
497
|
+
//# sourceMappingURL=EventResponse-Clg-5HI_.d.mts.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as EventResponse } from "./EventResponse-
|
|
1
|
+
import { t as EventResponse } from "./EventResponse-Btb5YASI.cjs";
|
|
2
2
|
export = EventResponse;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { t as EventResponse } from "./EventResponse-
|
|
1
|
+
import { t as EventResponse } from "./EventResponse-Clg-5HI_.mjs";
|
|
2
2
|
export { EventResponse as default };
|
package/build/main.cjs
CHANGED
|
@@ -14,7 +14,7 @@ let node_fs = require("node:fs");
|
|
|
14
14
|
node_fs = require_ConfigurationBuilder.__toESM(node_fs);
|
|
15
15
|
|
|
16
16
|
//#region package.json
|
|
17
|
-
var version = "2.
|
|
17
|
+
var version = "2.1.0";
|
|
18
18
|
|
|
19
19
|
//#endregion
|
|
20
20
|
//#region src/main.ts
|
|
@@ -97,15 +97,13 @@ var OGIAddon = class {
|
|
|
97
97
|
}
|
|
98
98
|
/**
|
|
99
99
|
* Notify the OGI Addon Server that you are performing a background task. This can be used to help users understand what is happening in the background.
|
|
100
|
-
* @
|
|
101
|
-
* @param progress {number}
|
|
102
|
-
* @param logs {string[]}
|
|
100
|
+
* @returns {Promise<Task>} A Task instance for managing the background task.
|
|
103
101
|
*/
|
|
104
102
|
async task() {
|
|
105
103
|
const id = Math.random().toString(36).substring(7);
|
|
106
104
|
const progress = 0;
|
|
107
105
|
const logs = [];
|
|
108
|
-
const task = new
|
|
106
|
+
const task = new Task(this.addonWSListener, id, progress, logs);
|
|
109
107
|
this.addonWSListener.send("task-update", {
|
|
110
108
|
id,
|
|
111
109
|
progress,
|
|
@@ -232,61 +230,40 @@ var OGIAddon = class {
|
|
|
232
230
|
});
|
|
233
231
|
}
|
|
234
232
|
};
|
|
235
|
-
var CustomTask = class {
|
|
236
|
-
id;
|
|
237
|
-
progress;
|
|
238
|
-
logs;
|
|
239
|
-
finished = false;
|
|
240
|
-
ws;
|
|
241
|
-
failed = void 0;
|
|
242
|
-
constructor(ws$2, id, progress, logs) {
|
|
243
|
-
this.id = id;
|
|
244
|
-
this.progress = progress;
|
|
245
|
-
this.logs = logs;
|
|
246
|
-
this.ws = ws$2;
|
|
247
|
-
}
|
|
248
|
-
log(log) {
|
|
249
|
-
this.logs.push(log);
|
|
250
|
-
this.update();
|
|
251
|
-
}
|
|
252
|
-
finish() {
|
|
253
|
-
this.finished = true;
|
|
254
|
-
this.update();
|
|
255
|
-
}
|
|
256
|
-
fail(message) {
|
|
257
|
-
this.failed = message;
|
|
258
|
-
this.update();
|
|
259
|
-
}
|
|
260
|
-
setProgress(progress) {
|
|
261
|
-
this.progress = progress;
|
|
262
|
-
this.update();
|
|
263
|
-
}
|
|
264
|
-
update() {
|
|
265
|
-
this.ws.send("task-update", {
|
|
266
|
-
id: this.id,
|
|
267
|
-
progress: this.progress,
|
|
268
|
-
logs: this.logs,
|
|
269
|
-
finished: this.finished,
|
|
270
|
-
failed: this.failed
|
|
271
|
-
});
|
|
272
|
-
}
|
|
273
|
-
};
|
|
274
233
|
/**
|
|
275
|
-
* A
|
|
234
|
+
* A unified task API for both server-initiated tasks (via onTask handlers)
|
|
235
|
+
* and addon-initiated background tasks (via addon.task()).
|
|
276
236
|
* Provides chainable methods for logging, progress updates, and completion.
|
|
277
237
|
*/
|
|
278
238
|
var Task = class {
|
|
279
239
|
event;
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
240
|
+
ws;
|
|
241
|
+
id;
|
|
242
|
+
progress = 0;
|
|
243
|
+
logs = [];
|
|
244
|
+
finished = false;
|
|
245
|
+
failed = void 0;
|
|
246
|
+
constructor(eventOrWs, id, progress, logs) {
|
|
247
|
+
if (eventOrWs instanceof require_EventResponse) {
|
|
248
|
+
this.event = eventOrWs;
|
|
249
|
+
this.event.defer();
|
|
250
|
+
} else {
|
|
251
|
+
this.ws = eventOrWs;
|
|
252
|
+
this.id = id;
|
|
253
|
+
this.progress = progress ?? 0;
|
|
254
|
+
this.logs = logs ?? [];
|
|
255
|
+
}
|
|
283
256
|
}
|
|
284
257
|
/**
|
|
285
258
|
* Log a message to the task. Returns this for chaining.
|
|
286
259
|
* @param message {string} The message to log.
|
|
287
260
|
*/
|
|
288
261
|
log(message) {
|
|
289
|
-
this.event.log(message);
|
|
262
|
+
if (this.event) this.event.log(message);
|
|
263
|
+
else {
|
|
264
|
+
this.logs.push(message);
|
|
265
|
+
this.update();
|
|
266
|
+
}
|
|
290
267
|
return this;
|
|
291
268
|
}
|
|
292
269
|
/**
|
|
@@ -294,33 +271,61 @@ var Task = class {
|
|
|
294
271
|
* @param progress {number} The progress value (0-100).
|
|
295
272
|
*/
|
|
296
273
|
setProgress(progress) {
|
|
297
|
-
this.event.progress = progress;
|
|
274
|
+
if (this.event) this.event.progress = progress;
|
|
275
|
+
else {
|
|
276
|
+
this.progress = progress;
|
|
277
|
+
this.update();
|
|
278
|
+
}
|
|
298
279
|
return this;
|
|
299
280
|
}
|
|
300
281
|
/**
|
|
301
282
|
* Complete the task successfully.
|
|
302
283
|
*/
|
|
303
284
|
complete() {
|
|
304
|
-
this.event.complete();
|
|
285
|
+
if (this.event) this.event.complete();
|
|
286
|
+
else {
|
|
287
|
+
this.finished = true;
|
|
288
|
+
this.update();
|
|
289
|
+
}
|
|
305
290
|
}
|
|
306
291
|
/**
|
|
307
292
|
* Fail the task with an error message.
|
|
308
293
|
* @param message {string} The error message.
|
|
309
294
|
*/
|
|
310
295
|
fail(message) {
|
|
311
|
-
this.event.fail(message);
|
|
296
|
+
if (this.event) this.event.fail(message);
|
|
297
|
+
else {
|
|
298
|
+
this.failed = message;
|
|
299
|
+
this.update();
|
|
300
|
+
}
|
|
312
301
|
}
|
|
313
302
|
/**
|
|
314
303
|
* Ask the user for input using a ConfigurationBuilder screen.
|
|
304
|
+
* Only available for EventResponse-based tasks (onTask handlers).
|
|
315
305
|
* The return type is inferred from the ConfigurationBuilder's accumulated option types.
|
|
316
306
|
* @param name {string} The name/title of the input prompt.
|
|
317
307
|
* @param description {string} The description of what input is needed.
|
|
318
308
|
* @param screen {ConfigurationBuilder<U>} The configuration builder for the input form.
|
|
319
309
|
* @returns {Promise<U>} The user's input with types matching the configuration options.
|
|
310
|
+
* @throws {Error} If called on a WebSocket-based task.
|
|
320
311
|
*/
|
|
321
312
|
async askForInput(name, description, screen) {
|
|
313
|
+
if (!this.event) throw new Error("askForInput() is only available for EventResponse-based tasks (onTask handlers)");
|
|
322
314
|
return this.event.askForInput(name, description, screen);
|
|
323
315
|
}
|
|
316
|
+
/**
|
|
317
|
+
* Update the task state (for WebSocket-based tasks only).
|
|
318
|
+
* Called automatically when using log(), setProgress(), complete(), or fail().
|
|
319
|
+
*/
|
|
320
|
+
update() {
|
|
321
|
+
if (this.ws && this.id !== void 0) this.ws.send("task-update", {
|
|
322
|
+
id: this.id,
|
|
323
|
+
progress: this.progress,
|
|
324
|
+
logs: this.logs,
|
|
325
|
+
finished: this.finished,
|
|
326
|
+
failed: this.failed
|
|
327
|
+
});
|
|
328
|
+
}
|
|
324
329
|
};
|
|
325
330
|
/**
|
|
326
331
|
* A search tool wrapper over Fuse.js for the OGI Addon. This tool is used to search for items in the library.
|
|
@@ -614,7 +619,6 @@ var OGIAddonWSListener = class {
|
|
|
614
619
|
//#endregion
|
|
615
620
|
exports.Configuration = require_config_Configuration.Configuration;
|
|
616
621
|
exports.ConfigurationBuilder = require_ConfigurationBuilder.ConfigurationBuilder;
|
|
617
|
-
exports.CustomTask = CustomTask;
|
|
618
622
|
exports.EventResponse = require_EventResponse;
|
|
619
623
|
exports.SearchTool = SearchTool;
|
|
620
624
|
exports.Task = Task;
|
package/build/main.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.cjs","names":["pjson.version","events","Configuration","fs","ws","Fuse","z","ConfigurationBuilder","EventResponse","result"],"sources":["../package.json","../src/main.ts"],"sourcesContent":["","import ws, { WebSocket } from 'ws';\nimport events from 'node:events';\nimport { ConfigurationBuilder } from './config/ConfigurationBuilder';\nimport type { ConfigurationFile } from './config/ConfigurationBuilder';\nimport { Configuration } from './config/Configuration';\nimport EventResponse from './EventResponse';\nimport type { SearchResult } from './SearchEngine';\nimport Fuse, { IFuseOptions } from 'fuse.js';\n\nexport type OGIAddonEvent =\n | 'connect'\n | 'disconnect'\n | 'configure'\n | 'authenticate'\n | 'search'\n | 'setup'\n | 'library-search'\n | 'game-details'\n | 'exit'\n | 'check-for-updates'\n | 'request-dl'\n | 'catalog';\n\nexport type OGIAddonClientSentEvent =\n | 'response'\n | 'authenticate'\n | 'configure'\n | 'defer-update'\n | 'notification'\n | 'input-asked'\n | 'get-app-details'\n | 'search-app-name'\n | 'flag'\n | 'task-update';\n\nexport type OGIAddonServerSentEvent =\n | 'authenticate'\n | 'configure'\n | 'config-update'\n | 'search'\n | 'setup'\n | 'response'\n | 'library-search'\n | 'check-for-updates'\n | 'task-run'\n | 'game-details'\n | 'request-dl'\n | 'catalog';\nexport { ConfigurationBuilder, Configuration, EventResponse };\nexport type { SearchResult };\nconst defaultPort = 7654;\nimport pjson from '../package.json';\nimport { exec, spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { z } from 'zod';\nexport const VERSION = pjson.version;\n\nexport interface ClientSentEventTypes {\n response: any;\n authenticate: {\n name: string;\n id: string;\n description: string;\n version: string;\n author: string;\n };\n configure: ConfigurationFile;\n 'defer-update': {\n logs: string[];\n progress: number;\n };\n notification: Notification;\n 'input-asked': ConfigurationBuilder<\n Record<string, string | number | boolean>\n >;\n 'task-update': {\n id: string;\n progress: number;\n logs: string[];\n finished: boolean;\n failed: string | undefined;\n };\n 'get-app-details': {\n appID: number;\n storefront: string;\n };\n 'search-app-name': {\n query: string;\n storefront: string;\n };\n flag: {\n flag: string;\n value: string | string[];\n };\n}\n\nexport type BasicLibraryInfo = {\n name: string;\n capsuleImage: string;\n appID: number;\n storefront: string;\n};\n\nexport type SetupEventResponse = Omit<\n LibraryInfo,\n | 'capsuleImage'\n | 'coverImage'\n | 'name'\n | 'appID'\n | 'storefront'\n | 'addonsource'\n | 'titleImage'\n> & {\n redistributables?: {\n name: string;\n path: string;\n }[];\n};\n\nexport interface EventListenerTypes {\n /**\n * This event is emitted when the addon connects to the OGI Addon Server. Addon does not need to resolve anything.\n * @param event\n * @returns\n */\n connect: (event: EventResponse<void>) => void;\n\n /**\n * This event is emitted when the client requests for the addon to disconnect. Addon does not need to resolve this event, but we recommend `process.exit(0)` so the addon can exit gracefully instead of by force by the addon server.\n * @param reason\n * @returns\n */\n disconnect: (reason: string) => void;\n /**\n * This event is emitted when the client requests for the addon to configure itself. Addon should resolve the event with the internal configuration. (See ConfigurationBuilder)\n * @param config\n * @returns\n */\n configure: (config: ConfigurationBuilder) => ConfigurationBuilder;\n /**\n * This event is called when the client provides a response to any event. This should be treated as middleware.\n * @param response\n * @returns\n */\n response: (response: any) => void;\n\n /**\n * This event is called when the client requests for the addon to authenticate itself. You don't need to provide any info.\n * @param config\n * @returns\n */\n authenticate: (config: any) => void;\n /**\n * This event is emitted when the client requests for a torrent/direct download search to be performed. Addon is given the gameID (could be a steam appID or custom store appID), along with the storefront type. Addon should resolve the event with the search results. (See SearchResult)\n * @param query\n * @param event\n * @returns\n */\n search: (\n query: {\n storefront: string;\n appID: number;\n } & (\n | {\n for: 'game' | 'task' | 'all';\n }\n | {\n for: 'update';\n libraryInfo: LibraryInfo;\n }\n ),\n event: EventResponse<SearchResult[]>\n ) => void;\n /**\n * This event is emitted when the client requests for app setup to be performed. Addon should resolve the event with the metadata for the library entry. (See LibraryInfo)\n * @param data\n * @param event\n * @returns\n */\n setup: (\n data: {\n path: string;\n type: 'direct' | 'torrent' | 'magnet' | 'empty';\n name: string;\n usedRealDebrid: boolean;\n multiPartFiles?: {\n name: string;\n downloadURL: string;\n }[];\n appID: number;\n storefront: string;\n manifest?: Record<string, unknown>;\n } & (\n | {\n for: 'game';\n }\n | {\n for: 'update';\n currentLibraryInfo: LibraryInfo;\n }\n ),\n event: EventResponse<SetupEventResponse>\n ) => void;\n\n /**\n * This event is emitted when the client requires for a search to be performed. Input is the search query.\n * @param query\n * @param event\n * @returns\n */\n 'library-search': (\n query: string,\n event: EventResponse<BasicLibraryInfo[]>\n ) => void;\n\n /**\n * This event is emitted when the client requests for a game details to be fetched. Addon should resolve the event with the game details. This is used to generate a store page for the game.\n * @param appID\n * @param event\n * @returns\n */\n 'game-details': (\n details: { appID: number; storefront: string },\n event: EventResponse<StoreData | undefined>\n ) => void;\n\n /**\n * This event is emitted when the client requests for the addon to exit. Use this to perform any cleanup tasks, ending with a `process.exit(0)`.\n * @returns\n */\n exit: () => void;\n\n /**\n * This event is emitted when the client requests for a download to be performed with the 'request' type. Addon should resolve the event with a SearchResult containing the actual download info.\n * @param appID\n * @param info\n * @param event\n * @returns\n */\n 'request-dl': (\n appID: number,\n info: SearchResult,\n event: EventResponse<SearchResult>\n ) => void;\n\n /**\n * This event is emitted when the client requests for a catalog to be fetched. Addon should resolve the event with the catalog.\n * @param event\n * @returns\n */\n catalog: (\n event: Omit<\n EventResponse<{\n [key: string]: {\n name: string;\n description: string;\n listings: BasicLibraryInfo[];\n };\n }>,\n 'askForInput'\n >\n ) => void;\n\n /**\n * This event is emitted when the client requests for an addon to check for updates. Addon should resolve the event with the update information.\n * @param data\n * @param event\n * @returns\n */\n 'check-for-updates': (\n data: { appID: number; storefront: string; currentVersion: string },\n event: EventResponse<\n | {\n available: true;\n version: string;\n }\n | {\n available: false;\n }\n >\n ) => void;\n}\n\nexport interface StoreData {\n name: string;\n publishers: string[];\n developers: string[];\n appID: number;\n releaseDate: string;\n capsuleImage: string;\n coverImage: string;\n basicDescription: string;\n description: string;\n headerImage: string;\n latestVersion: string;\n}\nexport interface WebsocketMessageClient {\n event: OGIAddonClientSentEvent;\n id?: string;\n args: any;\n statusError?: string;\n}\nexport interface WebsocketMessageServer {\n event: OGIAddonServerSentEvent;\n id?: string;\n args: any;\n statusError?: string;\n}\n\n/**\n * The configuration for the addon. This is used to identify the addon and provide information about it.\n * Storefronts is an array of names of stores that the addon supports.\n */\nexport interface OGIAddonConfiguration {\n name: string;\n id: string;\n description: string;\n version: string;\n\n author: string;\n repository: string;\n storefronts: string[];\n}\n\n/**\n * The main class for the OGI Addon. This class is used to interact with the OGI Addon Server. The OGI Addon Server provides a `--addonSecret` to the addon so it can securely connect.\n * @example\n * ```typescript\n * const addon = new OGIAddon({\n * name: 'Test Addon',\n * id: 'test-addon',\n * description: 'A test addon',\n * version: '1.0.0',\n * author: 'OGI Developers',\n * repository: ''\n * });\n * ```\n *\n */\nexport default class OGIAddon {\n public eventEmitter = new events.EventEmitter();\n public addonWSListener: OGIAddonWSListener;\n public addonInfo: OGIAddonConfiguration;\n public config: Configuration = new Configuration({});\n private eventsAvailable: OGIAddonEvent[] = [];\n private registeredConnectEvent: boolean = false;\n private taskHandlers: Map<\n string,\n (\n task: Task,\n data: {\n manifest: Record<string, unknown>;\n downloadPath: string;\n name: string;\n }\n ) => Promise<void> | void\n > = new Map();\n\n constructor(addonInfo: OGIAddonConfiguration) {\n this.addonInfo = addonInfo;\n this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);\n }\n\n /**\n * Register an event listener for the addon. (See EventListenerTypes)\n * @param event {OGIAddonEvent}\n * @param listener {EventListenerTypes[OGIAddonEvent]}\n */\n public on<T extends OGIAddonEvent>(\n event: T,\n listener: EventListenerTypes[T]\n ) {\n this.eventEmitter.on(event, listener);\n this.eventsAvailable.push(event);\n // wait for the addon to be connected\n if (!this.registeredConnectEvent) {\n this.addonWSListener.eventEmitter.once('connect', () => {\n this.addonWSListener.send('flag', {\n flag: 'events-available',\n value: this.eventsAvailable,\n });\n });\n this.registeredConnectEvent = true;\n }\n }\n\n public emit<T extends OGIAddonEvent>(\n event: T,\n ...args: Parameters<EventListenerTypes[T]>\n ) {\n this.eventEmitter.emit(event, ...args);\n }\n\n /**\n * Notify the client using a notification. Provide the type of notification, the message, and an ID.\n * @param notification {Notification}\n */\n public notify(notification: Notification) {\n this.addonWSListener.send('notification', [notification]);\n }\n\n /**\n * Get the app details for a given appID and storefront.\n * @param appID {number}\n * @param storefront {string}\n * @returns {Promise<StoreData>}\n */\n public async getAppDetails(appID: number, storefront: string) {\n const id = this.addonWSListener.send('get-app-details', {\n appID,\n storefront,\n });\n return await this.addonWSListener.waitForResponseFromServer<\n StoreData | undefined\n >(id);\n }\n\n public async searchGame(query: string, storefront: string) {\n const id = this.addonWSListener.send('search-app-name', {\n query,\n storefront,\n });\n return await this.addonWSListener.waitForResponseFromServer<\n BasicLibraryInfo[]\n >(id);\n }\n\n /**\n * Notify the OGI Addon Server that you are performing a background task. This can be used to help users understand what is happening in the background.\n * @param id {string}\n * @param progress {number}\n * @param logs {string[]}\n */\n public async task() {\n const id = Math.random().toString(36).substring(7);\n const progress = 0;\n const logs: string[] = [];\n const task = new CustomTask(this.addonWSListener, id, progress, logs);\n this.addonWSListener.send('task-update', {\n id,\n progress,\n logs,\n finished: false,\n failed: undefined,\n });\n return task;\n }\n\n /**\n * Register a task handler for a specific task name. The task name should match the taskName field in SearchResult or ActionOption.\n * @param taskName {string} The name of the task (should match taskName in SearchResult or ActionOption.setTaskName()).\n * @param handler {(task: Task, data: { manifest: Record<string, unknown>; downloadPath: string; name: string }) => Promise<void> | void} The handler function.\n * @example\n * ```typescript\n * addon.onTask('clearCache', async (task) => {\n * task.log('Clearing cache...');\n * task.setProgress(50);\n * await clearCacheFiles();\n * task.setProgress(100);\n * task.complete();\n * });\n * ```\n */\n public onTask(\n taskName: string,\n handler: (\n task: Task,\n data: {\n manifest: Record<string, unknown>;\n downloadPath: string;\n name: string;\n }\n ) => Promise<void> | void\n ): void {\n this.taskHandlers.set(taskName, handler);\n }\n\n /**\n * Check if a task handler is registered for the given task name.\n * @param taskName {string} The task name to check.\n * @returns {boolean} True if a handler is registered.\n */\n public hasTaskHandler(taskName: string): boolean {\n return this.taskHandlers.has(taskName);\n }\n\n /**\n * Get a task handler for the given task name.\n * @param taskName {string} The task name.\n * @returns The handler function or undefined if not found.\n */\n public getTaskHandler(taskName: string):\n | ((\n task: Task,\n data: {\n manifest: Record<string, unknown>;\n downloadPath: string;\n name: string;\n }\n ) => Promise<void> | void)\n | undefined {\n return this.taskHandlers.get(taskName);\n }\n\n /**\n * Extract a file using 7-Zip on Windows, unzip on Linux/Mac.\n * @param path {string}\n * @param outputPath {string}\n * @param type {'unrar' | 'unzip'}\n * @returns {Promise<void>}\n */\n public async extractFile(\n path: string,\n outputPath: string,\n type: 'unrar' | 'unzip'\n ) {\n return new Promise<void>((resolve, reject) => {\n // Ensure outputPath exists\n if (!fs.existsSync(outputPath)) {\n fs.mkdirSync(outputPath, { recursive: true });\n }\n\n if (type === 'unzip') {\n // Prefer 7-Zip on Windows, unzip on Linux/Mac\n if (process.platform === 'win32') {\n // 7-Zip path (default install location)\n const s7ZipPath = '\"C:\\\\Program Files\\\\7-Zip\\\\7z.exe\"';\n exec(\n `${s7ZipPath} x \"${path}\" -o\"${outputPath}\"`,\n (err: any, stdout: any, stderr: any) => {\n if (err) {\n console.error(err);\n console.log(stderr);\n reject(new Error('Failed to extract ZIP file'));\n return;\n }\n console.log(stdout);\n console.log(stderr);\n resolve();\n }\n );\n } else {\n // Use unzip on Linux/Mac\n const unzipProcess = spawn(\n 'unzip',\n [\n '-o', // overwrite files without prompting\n path,\n '-d', // specify output directory\n outputPath,\n ],\n {\n env: {\n ...process.env,\n UNZIP_DISABLE_ZIPBOMB_DETECTION: 'TRUE',\n },\n }\n );\n\n unzipProcess.stdout.on('data', (data: Buffer) => {\n console.log(`[unzip stdout]: ${data}`);\n });\n\n unzipProcess.stderr.on('data', (data: Buffer) => {\n console.error(`[unzip stderr]: ${data}`);\n });\n\n unzipProcess.on('close', (code: number) => {\n if (code !== 0) {\n console.error(`unzip process exited with code ${code}`);\n reject(new Error('Failed to extract ZIP file'));\n return;\n }\n resolve();\n });\n }\n } else if (type === 'unrar') {\n if (process.platform === 'win32') {\n // 7-Zip path (default install location)\n const s7ZipPath = '\"C:\\\\Program Files\\\\7-Zip\\\\7z.exe\"';\n exec(\n `${s7ZipPath} x \"${path}\" -o\"${outputPath}\"`,\n (err: any, stdout: any, stderr: any) => {\n if (err) {\n console.error(err);\n console.log(stderr);\n reject(new Error('Failed to extract RAR file'));\n return;\n }\n console.log(stdout);\n console.log(stderr);\n resolve();\n }\n );\n } else {\n // Use unrar on Linux/Mac\n const unrarProcess = spawn('unrar', ['x', '-y', path, outputPath]);\n\n unrarProcess.stdout.on('data', (data: Buffer) => {\n console.log(`[unrar stdout]: ${data}`);\n });\n\n unrarProcess.stderr.on('data', (data: Buffer) => {\n console.error(`[unrar stderr]: ${data}`);\n });\n\n unrarProcess.on('close', (code: number) => {\n if (code !== 0) {\n console.error(`unrar process exited with code ${code}`);\n reject(new Error('Failed to extract RAR file'));\n return;\n }\n resolve();\n });\n }\n } else {\n reject(new Error('Unknown extraction type'));\n }\n });\n }\n}\n\nexport class CustomTask {\n public readonly id: string;\n public progress: number;\n public logs: string[];\n public finished: boolean = false;\n public ws: OGIAddonWSListener;\n public failed: string | undefined = undefined;\n constructor(\n ws: OGIAddonWSListener,\n id: string,\n progress: number,\n logs: string[]\n ) {\n this.id = id;\n this.progress = progress;\n this.logs = logs;\n this.ws = ws;\n }\n public log(log: string) {\n this.logs.push(log);\n this.update();\n }\n public finish() {\n this.finished = true;\n this.update();\n }\n public fail(message: string) {\n this.failed = message;\n this.update();\n }\n public setProgress(progress: number) {\n this.progress = progress;\n this.update();\n }\n public update() {\n this.ws.send('task-update', {\n id: this.id,\n progress: this.progress,\n logs: this.logs,\n finished: this.finished,\n failed: this.failed,\n });\n }\n}\n\n/**\n * A cleaner API wrapper around EventResponse for task handlers.\n * Provides chainable methods for logging, progress updates, and completion.\n */\nexport class Task {\n private event: EventResponse<void>;\n\n constructor(event: EventResponse<void>) {\n this.event = event;\n this.event.defer();\n }\n\n /**\n * Log a message to the task. Returns this for chaining.\n * @param message {string} The message to log.\n */\n log(message: string): this {\n this.event.log(message);\n return this;\n }\n\n /**\n * Set the progress of the task (0-100). Returns this for chaining.\n * @param progress {number} The progress value (0-100).\n */\n setProgress(progress: number): this {\n this.event.progress = progress;\n return this;\n }\n\n /**\n * Complete the task successfully.\n */\n complete(): void {\n this.event.complete();\n }\n\n /**\n * Fail the task with an error message.\n * @param message {string} The error message.\n */\n fail(message: string): void {\n this.event.fail(message);\n }\n\n /**\n * Ask the user for input using a ConfigurationBuilder screen.\n * The return type is inferred from the ConfigurationBuilder's accumulated option types.\n * @param name {string} The name/title of the input prompt.\n * @param description {string} The description of what input is needed.\n * @param screen {ConfigurationBuilder<U>} The configuration builder for the input form.\n * @returns {Promise<U>} The user's input with types matching the configuration options.\n */\n async askForInput<U extends Record<string, string | number | boolean>>(\n name: string,\n description: string,\n screen: ConfigurationBuilder<U>\n ): Promise<U> {\n return this.event.askForInput(name, description, screen);\n }\n}\n/**\n * A search tool wrapper over Fuse.js for the OGI Addon. This tool is used to search for items in the library.\n * @example\n * ```typescript\n * const searchTool = new SearchTool<LibraryInfo>([{ name: 'test', appID: 123 }, { name: 'test2', appID: 124 }], ['name']);\n * const results = searchTool.search('test', 10);\n * ```\n */\nexport class SearchTool<T> {\n private fuse: Fuse<T>;\n constructor(\n items: T[],\n keys: string[],\n options: Omit<IFuseOptions<T>, 'keys'> = {\n threshold: 0.3,\n includeScore: true,\n }\n ) {\n this.fuse = new Fuse(items, {\n keys,\n ...options,\n });\n }\n public search(query: string, limit: number = 10): T[] {\n return this.fuse\n .search(query)\n .slice(0, limit)\n .map((result) => result.item);\n }\n public addItems(items: T[]) {\n items.map((item) => this.fuse.add(item));\n }\n}\n/**\n * Library Info is the metadata for a library entry after setting up a game.\n */\nexport const ZodLibraryInfo = z.object({\n name: z.string(),\n version: z.string(),\n cwd: z.string(),\n appID: z.number(),\n launchExecutable: z.string(),\n launchArguments: z.string().optional(),\n capsuleImage: z.string(),\n storefront: z.string(),\n addonsource: z.string(),\n coverImage: z.string(),\n titleImage: z.string().optional(),\n});\nexport type LibraryInfo = z.infer<typeof ZodLibraryInfo>;\ninterface Notification {\n type: 'warning' | 'error' | 'info' | 'success';\n message: string;\n id: string;\n}\nclass OGIAddonWSListener {\n private socket: WebSocket;\n public eventEmitter: events.EventEmitter;\n public addon: OGIAddon;\n\n constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter) {\n if (\n process.argv[process.argv.length - 1].split('=')[0] !== '--addonSecret'\n ) {\n throw new Error(\n 'No secret provided. This usually happens because the addon was not started by the OGI Addon Server.'\n );\n }\n this.addon = ogiAddon;\n this.eventEmitter = eventEmitter;\n this.socket = new ws('ws://localhost:' + defaultPort);\n this.socket.on('open', () => {\n console.log('Connected to OGI Addon Server');\n console.log('OGI Addon Server Version:', VERSION);\n\n // Authenticate with OGI Addon Server\n this.send('authenticate', {\n ...this.addon.addonInfo,\n secret: process.argv[process.argv.length - 1].split('=')[1],\n ogiVersion: VERSION,\n });\n\n // send a configuration request\n let configBuilder = new ConfigurationBuilder();\n this.eventEmitter.emit('configure', configBuilder);\n this.send('configure', configBuilder.build(false));\n this.addon.config = new Configuration(configBuilder.build(true));\n\n // wait for the config-update to be received then send connect\n const configListener = (event: ws.MessageEvent) => {\n if (event === undefined) return;\n // event can be a Buffer, string, ArrayBuffer, or Buffer[]\n let data: string;\n if (typeof event === 'string') {\n data = event;\n } else if (event instanceof Buffer) {\n data = event.toString();\n } else if (event && typeof (event as any).data === 'string') {\n data = (event as any).data;\n } else if (event && (event as any).data instanceof Buffer) {\n data = (event as any).data.toString();\n } else {\n // fallback for other types\n data = event.toString();\n }\n const message: WebsocketMessageServer = JSON.parse(data);\n if (message.event === 'config-update') {\n console.log('Config update received');\n this.socket.off('message', configListener);\n this.eventEmitter.emit(\n 'connect',\n new EventResponse<void>((screen, name, description) => {\n return this.userInputAsked(\n screen,\n name,\n description,\n this.socket\n );\n })\n );\n }\n };\n this.socket.on('message', configListener);\n });\n\n this.socket.on('error', (error) => {\n if (error.message.includes('Failed to connect')) {\n throw new Error(\n 'OGI Addon Server is not running/is unreachable. Please start the server and try again.'\n );\n }\n console.error('An error occurred:', error);\n });\n\n this.socket.on('close', (code, reason) => {\n if (code === 1008) {\n console.error('Authentication failed:', reason);\n return;\n }\n this.eventEmitter.emit('disconnect', reason);\n console.log('Disconnected from OGI Addon Server');\n console.error(reason.toString());\n this.eventEmitter.emit('exit');\n this.socket.close();\n });\n\n this.registerMessageReceiver();\n }\n\n private async userInputAsked<\n U extends Record<string, string | number | boolean>,\n >(\n configBuilt: ConfigurationBuilder<U>,\n name: string,\n description: string,\n socket: WebSocket\n ): Promise<U> {\n const config = configBuilt.build(false);\n const id = Math.random().toString(36).substring(7);\n if (!socket) {\n throw new Error('Socket is not connected');\n }\n socket.send(\n JSON.stringify({\n event: 'input-asked',\n args: {\n config,\n name,\n description,\n },\n id: id,\n })\n );\n return await this.waitForResponseFromServer<U>(id);\n }\n\n private registerMessageReceiver() {\n this.socket.on('message', async (data: string) => {\n const message: WebsocketMessageServer = JSON.parse(data);\n switch (message.event) {\n case 'config-update':\n const result = this.addon.config.updateConfig(message.args);\n if (!result[0]) {\n this.respondToMessage(\n message.id!!,\n {\n success: false,\n error: result[1],\n },\n undefined\n );\n } else {\n this.respondToMessage(message.id!!, { success: true }, undefined);\n }\n break;\n case 'search':\n let searchResultEvent = new EventResponse<SearchResult[]>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit('search', message.args, searchResultEvent);\n const searchResult =\n await this.waitForEventToRespond(searchResultEvent);\n this.respondToMessage(\n message.id!!,\n searchResult.data,\n searchResultEvent\n );\n break;\n case 'setup': {\n let setupEvent = new EventResponse<SetupEventResponse>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit('setup', message.args, setupEvent);\n const interval = setInterval(() => {\n if (setupEvent.resolved) {\n clearInterval(interval);\n return;\n }\n this.send('defer-update', {\n logs: setupEvent.logs,\n deferID: message.args.deferID,\n progress: setupEvent.progress,\n failed: setupEvent.failed,\n } as ClientSentEventTypes['defer-update']);\n }, 100);\n const setupResult = await this.waitForEventToRespond(setupEvent);\n this.respondToMessage(message.id!!, setupResult.data, setupEvent);\n break;\n }\n case 'library-search':\n let librarySearchEvent = new EventResponse<BasicLibraryInfo[]>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit(\n 'library-search',\n message.args,\n librarySearchEvent\n );\n const librarySearchResult =\n await this.waitForEventToRespond(librarySearchEvent);\n this.respondToMessage(\n message.id!!,\n librarySearchResult.data,\n librarySearchEvent\n );\n break;\n case 'game-details':\n let gameDetailsEvent = new EventResponse<StoreData | undefined>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n if (this.eventEmitter.listenerCount('game-details') === 0) {\n this.respondToMessage(\n message.id!!,\n {\n error: 'No event listener for game-details',\n },\n gameDetailsEvent\n );\n break;\n }\n this.eventEmitter.emit(\n 'game-details',\n message.args,\n gameDetailsEvent\n );\n const gameDetailsResult =\n await this.waitForEventToRespond(gameDetailsEvent);\n this.respondToMessage(\n message.id!!,\n gameDetailsResult.data,\n gameDetailsEvent\n );\n break;\n case 'check-for-updates':\n let checkForUpdatesEvent = new EventResponse<\n | {\n available: true;\n version: string;\n }\n | {\n available: false;\n }\n >((screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit(\n 'check-for-updates',\n message.args,\n checkForUpdatesEvent\n );\n const checkForUpdatesResult =\n await this.waitForEventToRespond(checkForUpdatesEvent);\n this.respondToMessage(\n message.id!!,\n checkForUpdatesResult.data,\n checkForUpdatesEvent\n );\n break;\n case 'request-dl':\n let requestDLEvent = new EventResponse<SearchResult>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n if (this.eventEmitter.listenerCount('request-dl') === 0) {\n this.respondToMessage(\n message.id!!,\n {\n error: 'No event listener for request-dl',\n },\n requestDLEvent\n );\n break;\n }\n this.eventEmitter.emit(\n 'request-dl',\n message.args.appID,\n message.args.info,\n requestDLEvent\n );\n const requestDLResult =\n await this.waitForEventToRespond(requestDLEvent);\n if (requestDLEvent.failed) {\n this.respondToMessage(message.id!!, undefined, requestDLEvent);\n break;\n }\n if (\n requestDLEvent.data === undefined ||\n requestDLEvent.data?.downloadType === 'request'\n ) {\n throw new Error(\n 'Request DL event did not return a valid result. Please ensure that the event does not resolve with another `request` download type.'\n );\n }\n this.respondToMessage(\n message.id!!,\n requestDLResult.data,\n requestDLEvent\n );\n break;\n case 'catalog':\n let catalogEvent = new EventResponse<{\n [key: string]: {\n name: string;\n description: string;\n listings: BasicLibraryInfo[];\n };\n }>();\n this.eventEmitter.emit('catalog', catalogEvent);\n const catalogResult = await this.waitForEventToRespond(catalogEvent);\n this.respondToMessage(message.id!!, catalogResult.data, catalogEvent);\n break;\n case 'task-run': {\n let taskRunEvent = new EventResponse<void>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n\n // Check for taskName: first from args directly (from SearchResult), then from manifest.__taskName (for ActionOption)\n const taskName =\n message.args.taskName && typeof message.args.taskName === 'string'\n ? message.args.taskName\n : message.args.manifest &&\n typeof message.args.manifest === 'object'\n ? (message.args.manifest as Record<string, unknown>).__taskName\n : undefined;\n\n if (\n taskName &&\n typeof taskName === 'string' &&\n this.addon.hasTaskHandler(taskName)\n ) {\n // Use the registered task handler\n const handler = this.addon.getTaskHandler(taskName)!;\n const task = new Task(taskRunEvent);\n try {\n const interval = setInterval(() => {\n if (taskRunEvent.resolved) {\n clearInterval(interval);\n return;\n }\n this.send('defer-update', {\n logs: taskRunEvent.logs,\n deferID: message.args.deferID,\n progress: taskRunEvent.progress,\n failed: taskRunEvent.failed,\n } as ClientSentEventTypes['defer-update']);\n }, 100);\n const result = handler(task, {\n manifest: message.args.manifest || {},\n downloadPath: message.args.downloadPath || '',\n name: message.args.name || '',\n });\n // If handler returns a promise, wait for it\n if (result instanceof Promise) {\n await result;\n }\n\n clearInterval(interval);\n } catch (error) {\n taskRunEvent.fail(\n error instanceof Error ? error.message : String(error)\n );\n }\n } else {\n // No handler found - fail the task\n taskRunEvent.fail(\n taskName\n ? `No task handler registered for task name: ${taskName}`\n : 'No task name provided'\n );\n }\n\n const taskRunResult = await this.waitForEventToRespond(taskRunEvent);\n this.respondToMessage(message.id!!, taskRunResult.data, taskRunEvent);\n break;\n }\n }\n });\n }\n\n private waitForEventToRespond<T>(\n event: EventResponse<T>\n ): Promise<EventResponse<T>> {\n // check the handlers to see if there even is any\n return new Promise((resolve, reject) => {\n const dataGet = setInterval(() => {\n if (event.resolved) {\n resolve(event);\n clearTimeout(timeout);\n }\n }, 5);\n\n const timeout = setTimeout(() => {\n if (event.deffered) {\n clearInterval(dataGet);\n const interval = setInterval(() => {\n if (event.resolved) {\n clearInterval(interval);\n resolve(event);\n }\n }, 100);\n } else {\n reject('Event did not respond in time');\n }\n }, 5000);\n });\n }\n\n public respondToMessage(\n messageID: string,\n response: any,\n originalEvent: EventResponse<any> | undefined\n ) {\n this.socket.send(\n JSON.stringify({\n event: 'response',\n id: messageID,\n args: response,\n statusError: originalEvent ? originalEvent.failed : undefined,\n })\n );\n console.log('dispatched response to ' + messageID);\n }\n\n public waitForResponseFromServer<T>(messageID: string): Promise<T> {\n return new Promise((resolve) => {\n const waiter = (data: string) => {\n const message: WebsocketMessageClient = JSON.parse(data);\n if (message.event !== 'response') {\n this.socket.once('message', waiter);\n return;\n }\n console.log('received response from ' + messageID);\n\n if (message.id === messageID) {\n resolve(message.args);\n } else {\n this.socket.once('message', waiter);\n }\n };\n this.socket.once('message', waiter);\n });\n }\n\n public send(\n event: OGIAddonClientSentEvent,\n args: ClientSentEventTypes[OGIAddonClientSentEvent]\n ): string {\n // generate a random id\n const id = Math.random().toString(36).substring(7);\n this.socket.send(\n JSON.stringify({\n event,\n args,\n id,\n })\n );\n return id;\n }\n\n public close() {\n this.socket.close();\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"main.cjs","names":["pjson.version","events","Configuration","fs","EventResponse","Fuse","z","ConfigurationBuilder","result"],"sources":["../package.json","../src/main.ts"],"sourcesContent":["","import ws, { WebSocket } from 'ws';\nimport events from 'node:events';\nimport { ConfigurationBuilder } from './config/ConfigurationBuilder';\nimport type { ConfigurationFile } from './config/ConfigurationBuilder';\nimport { Configuration } from './config/Configuration';\nimport EventResponse from './EventResponse';\nimport type { SearchResult } from './SearchEngine';\nimport Fuse, { IFuseOptions } from 'fuse.js';\n\nexport type OGIAddonEvent =\n | 'connect'\n | 'disconnect'\n | 'configure'\n | 'authenticate'\n | 'search'\n | 'setup'\n | 'library-search'\n | 'game-details'\n | 'exit'\n | 'check-for-updates'\n | 'request-dl'\n | 'catalog';\n\nexport type OGIAddonClientSentEvent =\n | 'response'\n | 'authenticate'\n | 'configure'\n | 'defer-update'\n | 'notification'\n | 'input-asked'\n | 'get-app-details'\n | 'search-app-name'\n | 'flag'\n | 'task-update';\n\nexport type OGIAddonServerSentEvent =\n | 'authenticate'\n | 'configure'\n | 'config-update'\n | 'search'\n | 'setup'\n | 'response'\n | 'library-search'\n | 'check-for-updates'\n | 'task-run'\n | 'game-details'\n | 'request-dl'\n | 'catalog';\nexport { ConfigurationBuilder, Configuration, EventResponse };\nexport type { SearchResult };\nconst defaultPort = 7654;\nimport pjson from '../package.json';\nimport { exec, spawn } from 'node:child_process';\nimport fs from 'node:fs';\nimport { z } from 'zod';\nexport const VERSION = pjson.version;\n\nexport interface ClientSentEventTypes {\n response: any;\n authenticate: {\n name: string;\n id: string;\n description: string;\n version: string;\n author: string;\n };\n configure: ConfigurationFile;\n 'defer-update': {\n logs: string[];\n progress: number;\n };\n notification: Notification;\n 'input-asked': ConfigurationBuilder<\n Record<string, string | number | boolean>\n >;\n 'task-update': {\n id: string;\n progress: number;\n logs: string[];\n finished: boolean;\n failed: string | undefined;\n };\n 'get-app-details': {\n appID: number;\n storefront: string;\n };\n 'search-app-name': {\n query: string;\n storefront: string;\n };\n flag: {\n flag: string;\n value: string | string[];\n };\n}\n\nexport type BasicLibraryInfo = {\n name: string;\n capsuleImage: string;\n appID: number;\n storefront: string;\n};\n\nexport type SetupEventResponse = Omit<\n LibraryInfo,\n | 'capsuleImage'\n | 'coverImage'\n | 'name'\n | 'appID'\n | 'storefront'\n | 'addonsource'\n | 'titleImage'\n> & {\n redistributables?: {\n name: string;\n path: string;\n }[];\n};\n\nexport interface EventListenerTypes {\n /**\n * This event is emitted when the addon connects to the OGI Addon Server. Addon does not need to resolve anything.\n * @param event\n * @returns\n */\n connect: (event: EventResponse<void>) => void;\n\n /**\n * This event is emitted when the client requests for the addon to disconnect. Addon does not need to resolve this event, but we recommend `process.exit(0)` so the addon can exit gracefully instead of by force by the addon server.\n * @param reason\n * @returns\n */\n disconnect: (reason: string) => void;\n /**\n * This event is emitted when the client requests for the addon to configure itself. Addon should resolve the event with the internal configuration. (See ConfigurationBuilder)\n * @param config\n * @returns\n */\n configure: (config: ConfigurationBuilder) => ConfigurationBuilder;\n /**\n * This event is called when the client provides a response to any event. This should be treated as middleware.\n * @param response\n * @returns\n */\n response: (response: any) => void;\n\n /**\n * This event is called when the client requests for the addon to authenticate itself. You don't need to provide any info.\n * @param config\n * @returns\n */\n authenticate: (config: any) => void;\n /**\n * This event is emitted when the client requests for a torrent/direct download search to be performed. Addon is given the gameID (could be a steam appID or custom store appID), along with the storefront type. Addon should resolve the event with the search results. (See SearchResult)\n * @param query\n * @param event\n * @returns\n */\n search: (\n query: {\n storefront: string;\n appID: number;\n } & (\n | {\n for: 'game' | 'task' | 'all';\n }\n | {\n for: 'update';\n libraryInfo: LibraryInfo;\n }\n ),\n event: EventResponse<SearchResult[]>\n ) => void;\n /**\n * This event is emitted when the client requests for app setup to be performed. Addon should resolve the event with the metadata for the library entry. (See LibraryInfo)\n * @param data\n * @param event\n * @returns\n */\n setup: (\n data: {\n path: string;\n type: 'direct' | 'torrent' | 'magnet' | 'empty';\n name: string;\n usedRealDebrid: boolean;\n multiPartFiles?: {\n name: string;\n downloadURL: string;\n }[];\n appID: number;\n storefront: string;\n manifest?: Record<string, unknown>;\n } & (\n | {\n for: 'game';\n }\n | {\n for: 'update';\n currentLibraryInfo: LibraryInfo;\n }\n ),\n event: EventResponse<SetupEventResponse>\n ) => void;\n\n /**\n * This event is emitted when the client requires for a search to be performed. Input is the search query.\n * @param query\n * @param event\n * @returns\n */\n 'library-search': (\n query: string,\n event: EventResponse<BasicLibraryInfo[]>\n ) => void;\n\n /**\n * This event is emitted when the client requests for a game details to be fetched. Addon should resolve the event with the game details. This is used to generate a store page for the game.\n * @param appID\n * @param event\n * @returns\n */\n 'game-details': (\n details: { appID: number; storefront: string },\n event: EventResponse<StoreData | undefined>\n ) => void;\n\n /**\n * This event is emitted when the client requests for the addon to exit. Use this to perform any cleanup tasks, ending with a `process.exit(0)`.\n * @returns\n */\n exit: () => void;\n\n /**\n * This event is emitted when the client requests for a download to be performed with the 'request' type. Addon should resolve the event with a SearchResult containing the actual download info.\n * @param appID\n * @param info\n * @param event\n * @returns\n */\n 'request-dl': (\n appID: number,\n info: SearchResult,\n event: EventResponse<SearchResult>\n ) => void;\n\n /**\n * This event is emitted when the client requests for a catalog to be fetched. Addon should resolve the event with the catalog.\n * @param event\n * @returns\n */\n catalog: (\n event: Omit<\n EventResponse<{\n [key: string]: {\n name: string;\n description: string;\n listings: BasicLibraryInfo[];\n };\n }>,\n 'askForInput'\n >\n ) => void;\n\n /**\n * This event is emitted when the client requests for an addon to check for updates. Addon should resolve the event with the update information.\n * @param data\n * @param event\n * @returns\n */\n 'check-for-updates': (\n data: { appID: number; storefront: string; currentVersion: string },\n event: EventResponse<\n | {\n available: true;\n version: string;\n }\n | {\n available: false;\n }\n >\n ) => void;\n}\n\nexport interface StoreData {\n name: string;\n publishers: string[];\n developers: string[];\n appID: number;\n releaseDate: string;\n capsuleImage: string;\n coverImage: string;\n basicDescription: string;\n description: string;\n headerImage: string;\n latestVersion: string;\n}\nexport interface WebsocketMessageClient {\n event: OGIAddonClientSentEvent;\n id?: string;\n args: any;\n statusError?: string;\n}\nexport interface WebsocketMessageServer {\n event: OGIAddonServerSentEvent;\n id?: string;\n args: any;\n statusError?: string;\n}\n\n/**\n * The configuration for the addon. This is used to identify the addon and provide information about it.\n * Storefronts is an array of names of stores that the addon supports.\n */\nexport interface OGIAddonConfiguration {\n name: string;\n id: string;\n description: string;\n version: string;\n\n author: string;\n repository: string;\n storefronts: string[];\n}\n\n/**\n * The main class for the OGI Addon. This class is used to interact with the OGI Addon Server. The OGI Addon Server provides a `--addonSecret` to the addon so it can securely connect.\n * @example\n * ```typescript\n * const addon = new OGIAddon({\n * name: 'Test Addon',\n * id: 'test-addon',\n * description: 'A test addon',\n * version: '1.0.0',\n * author: 'OGI Developers',\n * repository: ''\n * });\n * ```\n *\n */\nexport default class OGIAddon {\n public eventEmitter = new events.EventEmitter();\n public addonWSListener: OGIAddonWSListener;\n public addonInfo: OGIAddonConfiguration;\n public config: Configuration = new Configuration({});\n private eventsAvailable: OGIAddonEvent[] = [];\n private registeredConnectEvent: boolean = false;\n private taskHandlers: Map<\n string,\n (\n task: Task,\n data: {\n manifest: Record<string, unknown>;\n downloadPath: string;\n name: string;\n }\n ) => Promise<void> | void\n > = new Map();\n\n constructor(addonInfo: OGIAddonConfiguration) {\n this.addonInfo = addonInfo;\n this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);\n }\n\n /**\n * Register an event listener for the addon. (See EventListenerTypes)\n * @param event {OGIAddonEvent}\n * @param listener {EventListenerTypes[OGIAddonEvent]}\n */\n public on<T extends OGIAddonEvent>(\n event: T,\n listener: EventListenerTypes[T]\n ) {\n this.eventEmitter.on(event, listener);\n this.eventsAvailable.push(event);\n // wait for the addon to be connected\n if (!this.registeredConnectEvent) {\n this.addonWSListener.eventEmitter.once('connect', () => {\n this.addonWSListener.send('flag', {\n flag: 'events-available',\n value: this.eventsAvailable,\n });\n });\n this.registeredConnectEvent = true;\n }\n }\n\n public emit<T extends OGIAddonEvent>(\n event: T,\n ...args: Parameters<EventListenerTypes[T]>\n ) {\n this.eventEmitter.emit(event, ...args);\n }\n\n /**\n * Notify the client using a notification. Provide the type of notification, the message, and an ID.\n * @param notification {Notification}\n */\n public notify(notification: Notification) {\n this.addonWSListener.send('notification', [notification]);\n }\n\n /**\n * Get the app details for a given appID and storefront.\n * @param appID {number}\n * @param storefront {string}\n * @returns {Promise<StoreData>}\n */\n public async getAppDetails(appID: number, storefront: string) {\n const id = this.addonWSListener.send('get-app-details', {\n appID,\n storefront,\n });\n return await this.addonWSListener.waitForResponseFromServer<\n StoreData | undefined\n >(id);\n }\n\n public async searchGame(query: string, storefront: string) {\n const id = this.addonWSListener.send('search-app-name', {\n query,\n storefront,\n });\n return await this.addonWSListener.waitForResponseFromServer<\n BasicLibraryInfo[]\n >(id);\n }\n\n /**\n * Notify the OGI Addon Server that you are performing a background task. This can be used to help users understand what is happening in the background.\n * @returns {Promise<Task>} A Task instance for managing the background task.\n */\n public async task(): Promise<Task> {\n const id = Math.random().toString(36).substring(7);\n const progress = 0;\n const logs: string[] = [];\n const task = new Task(this.addonWSListener, id, progress, logs);\n this.addonWSListener.send('task-update', {\n id,\n progress,\n logs,\n finished: false,\n failed: undefined,\n });\n return task;\n }\n\n /**\n * Register a task handler for a specific task name. The task name should match the taskName field in SearchResult or ActionOption.\n * @param taskName {string} The name of the task (should match taskName in SearchResult or ActionOption.setTaskName()).\n * @param handler {(task: Task, data: { manifest: Record<string, unknown>; downloadPath: string; name: string }) => Promise<void> | void} The handler function.\n * @example\n * ```typescript\n * addon.onTask('clearCache', async (task) => {\n * task.log('Clearing cache...');\n * task.setProgress(50);\n * await clearCacheFiles();\n * task.setProgress(100);\n * task.complete();\n * });\n * ```\n */\n public onTask(\n taskName: string,\n handler: (\n task: Task,\n data: {\n manifest: Record<string, unknown>;\n downloadPath: string;\n name: string;\n }\n ) => Promise<void> | void\n ): void {\n this.taskHandlers.set(taskName, handler);\n }\n\n /**\n * Check if a task handler is registered for the given task name.\n * @param taskName {string} The task name to check.\n * @returns {boolean} True if a handler is registered.\n */\n public hasTaskHandler(taskName: string): boolean {\n return this.taskHandlers.has(taskName);\n }\n\n /**\n * Get a task handler for the given task name.\n * @param taskName {string} The task name.\n * @returns The handler function or undefined if not found.\n */\n public getTaskHandler(taskName: string):\n | ((\n task: Task,\n data: {\n manifest: Record<string, unknown>;\n downloadPath: string;\n name: string;\n }\n ) => Promise<void> | void)\n | undefined {\n return this.taskHandlers.get(taskName);\n }\n\n /**\n * Extract a file using 7-Zip on Windows, unzip on Linux/Mac.\n * @param path {string}\n * @param outputPath {string}\n * @param type {'unrar' | 'unzip'}\n * @returns {Promise<void>}\n */\n public async extractFile(\n path: string,\n outputPath: string,\n type: 'unrar' | 'unzip'\n ) {\n return new Promise<void>((resolve, reject) => {\n // Ensure outputPath exists\n if (!fs.existsSync(outputPath)) {\n fs.mkdirSync(outputPath, { recursive: true });\n }\n\n if (type === 'unzip') {\n // Prefer 7-Zip on Windows, unzip on Linux/Mac\n if (process.platform === 'win32') {\n // 7-Zip path (default install location)\n const s7ZipPath = '\"C:\\\\Program Files\\\\7-Zip\\\\7z.exe\"';\n exec(\n `${s7ZipPath} x \"${path}\" -o\"${outputPath}\"`,\n (err: any, stdout: any, stderr: any) => {\n if (err) {\n console.error(err);\n console.log(stderr);\n reject(new Error('Failed to extract ZIP file'));\n return;\n }\n console.log(stdout);\n console.log(stderr);\n resolve();\n }\n );\n } else {\n // Use unzip on Linux/Mac\n const unzipProcess = spawn(\n 'unzip',\n [\n '-o', // overwrite files without prompting\n path,\n '-d', // specify output directory\n outputPath,\n ],\n {\n env: {\n ...process.env,\n UNZIP_DISABLE_ZIPBOMB_DETECTION: 'TRUE',\n },\n }\n );\n\n unzipProcess.stdout.on('data', (data: Buffer) => {\n console.log(`[unzip stdout]: ${data}`);\n });\n\n unzipProcess.stderr.on('data', (data: Buffer) => {\n console.error(`[unzip stderr]: ${data}`);\n });\n\n unzipProcess.on('close', (code: number) => {\n if (code !== 0) {\n console.error(`unzip process exited with code ${code}`);\n reject(new Error('Failed to extract ZIP file'));\n return;\n }\n resolve();\n });\n }\n } else if (type === 'unrar') {\n if (process.platform === 'win32') {\n // 7-Zip path (default install location)\n const s7ZipPath = '\"C:\\\\Program Files\\\\7-Zip\\\\7z.exe\"';\n exec(\n `${s7ZipPath} x \"${path}\" -o\"${outputPath}\"`,\n (err: any, stdout: any, stderr: any) => {\n if (err) {\n console.error(err);\n console.log(stderr);\n reject(new Error('Failed to extract RAR file'));\n return;\n }\n console.log(stdout);\n console.log(stderr);\n resolve();\n }\n );\n } else {\n // Use unrar on Linux/Mac\n const unrarProcess = spawn('unrar', ['x', '-y', path, outputPath]);\n\n unrarProcess.stdout.on('data', (data: Buffer) => {\n console.log(`[unrar stdout]: ${data}`);\n });\n\n unrarProcess.stderr.on('data', (data: Buffer) => {\n console.error(`[unrar stderr]: ${data}`);\n });\n\n unrarProcess.on('close', (code: number) => {\n if (code !== 0) {\n console.error(`unrar process exited with code ${code}`);\n reject(new Error('Failed to extract RAR file'));\n return;\n }\n resolve();\n });\n }\n } else {\n reject(new Error('Unknown extraction type'));\n }\n });\n }\n}\n\n/**\n * A unified task API for both server-initiated tasks (via onTask handlers)\n * and addon-initiated background tasks (via addon.task()).\n * Provides chainable methods for logging, progress updates, and completion.\n */\nexport class Task {\n // EventResponse-based mode (for onTask handlers)\n private event: EventResponse<void> | undefined;\n \n // WebSocket-based mode (for addon.task())\n private ws: OGIAddonWSListener | undefined;\n private readonly id: string | undefined;\n private progress: number = 0;\n private logs: string[] = [];\n private finished: boolean = false;\n private failed: string | undefined = undefined;\n\n /**\n * Construct a Task from an EventResponse (for onTask handlers).\n * @param event {EventResponse<void>} The event response to wrap.\n */\n constructor(event: EventResponse<void>);\n \n /**\n * Construct a Task from WebSocket listener (for addon.task()).\n * @param ws {OGIAddonWSListener} The WebSocket listener.\n * @param id {string} The task ID.\n * @param progress {number} Initial progress (0-100).\n * @param logs {string[]} Initial logs array.\n */\n constructor(ws: OGIAddonWSListener, id: string, progress: number, logs: string[]);\n \n constructor(\n eventOrWs: EventResponse<void> | OGIAddonWSListener,\n id?: string,\n progress?: number,\n logs?: string[]\n ) {\n if (eventOrWs instanceof EventResponse) {\n // EventResponse-based mode\n this.event = eventOrWs;\n this.event.defer();\n } else {\n // WebSocket-based mode\n this.ws = eventOrWs;\n this.id = id!;\n this.progress = progress ?? 0;\n this.logs = logs ?? [];\n }\n }\n\n /**\n * Log a message to the task. Returns this for chaining.\n * @param message {string} The message to log.\n */\n log(message: string): this {\n if (this.event) {\n this.event.log(message);\n } else {\n this.logs.push(message);\n this.update();\n }\n return this;\n }\n\n /**\n * Set the progress of the task (0-100). Returns this for chaining.\n * @param progress {number} The progress value (0-100).\n */\n setProgress(progress: number): this {\n if (this.event) {\n this.event.progress = progress;\n } else {\n this.progress = progress;\n this.update();\n }\n return this;\n }\n\n /**\n * Complete the task successfully.\n */\n complete(): void {\n if (this.event) {\n this.event.complete();\n } else {\n this.finished = true;\n this.update();\n }\n }\n\n /**\n * Fail the task with an error message.\n * @param message {string} The error message.\n */\n fail(message: string): void {\n if (this.event) {\n this.event.fail(message);\n } else {\n this.failed = message;\n this.update();\n }\n }\n\n /**\n * Ask the user for input using a ConfigurationBuilder screen.\n * Only available for EventResponse-based tasks (onTask handlers).\n * The return type is inferred from the ConfigurationBuilder's accumulated option types.\n * @param name {string} The name/title of the input prompt.\n * @param description {string} The description of what input is needed.\n * @param screen {ConfigurationBuilder<U>} The configuration builder for the input form.\n * @returns {Promise<U>} The user's input with types matching the configuration options.\n * @throws {Error} If called on a WebSocket-based task.\n */\n async askForInput<U extends Record<string, string | number | boolean>>(\n name: string,\n description: string,\n screen: ConfigurationBuilder<U>\n ): Promise<U> {\n if (!this.event) {\n throw new Error('askForInput() is only available for EventResponse-based tasks (onTask handlers)');\n }\n return this.event.askForInput(name, description, screen);\n }\n\n /**\n * Update the task state (for WebSocket-based tasks only).\n * Called automatically when using log(), setProgress(), complete(), or fail().\n */\n private update(): void {\n if (this.ws && this.id !== undefined) {\n this.ws.send('task-update', {\n id: this.id,\n progress: this.progress,\n logs: this.logs,\n finished: this.finished,\n failed: this.failed,\n });\n }\n }\n}\n/**\n * A search tool wrapper over Fuse.js for the OGI Addon. This tool is used to search for items in the library.\n * @example\n * ```typescript\n * const searchTool = new SearchTool<LibraryInfo>([{ name: 'test', appID: 123 }, { name: 'test2', appID: 124 }], ['name']);\n * const results = searchTool.search('test', 10);\n * ```\n */\nexport class SearchTool<T> {\n private fuse: Fuse<T>;\n constructor(\n items: T[],\n keys: string[],\n options: Omit<IFuseOptions<T>, 'keys'> = {\n threshold: 0.3,\n includeScore: true,\n }\n ) {\n this.fuse = new Fuse(items, {\n keys,\n ...options,\n });\n }\n public search(query: string, limit: number = 10): T[] {\n return this.fuse\n .search(query)\n .slice(0, limit)\n .map((result) => result.item);\n }\n public addItems(items: T[]) {\n items.map((item) => this.fuse.add(item));\n }\n}\n/**\n * Library Info is the metadata for a library entry after setting up a game.\n */\nexport const ZodLibraryInfo = z.object({\n name: z.string(),\n version: z.string(),\n cwd: z.string(),\n appID: z.number(),\n launchExecutable: z.string(),\n launchArguments: z.string().optional(),\n capsuleImage: z.string(),\n storefront: z.string(),\n addonsource: z.string(),\n coverImage: z.string(),\n titleImage: z.string().optional(),\n});\nexport type LibraryInfo = z.infer<typeof ZodLibraryInfo>;\ninterface Notification {\n type: 'warning' | 'error' | 'info' | 'success';\n message: string;\n id: string;\n}\nclass OGIAddonWSListener {\n private socket: WebSocket;\n public eventEmitter: events.EventEmitter;\n public addon: OGIAddon;\n\n constructor(ogiAddon: OGIAddon, eventEmitter: events.EventEmitter) {\n if (\n process.argv[process.argv.length - 1].split('=')[0] !== '--addonSecret'\n ) {\n throw new Error(\n 'No secret provided. This usually happens because the addon was not started by the OGI Addon Server.'\n );\n }\n this.addon = ogiAddon;\n this.eventEmitter = eventEmitter;\n this.socket = new ws('ws://localhost:' + defaultPort);\n this.socket.on('open', () => {\n console.log('Connected to OGI Addon Server');\n console.log('OGI Addon Server Version:', VERSION);\n\n // Authenticate with OGI Addon Server\n this.send('authenticate', {\n ...this.addon.addonInfo,\n secret: process.argv[process.argv.length - 1].split('=')[1],\n ogiVersion: VERSION,\n });\n\n // send a configuration request\n let configBuilder = new ConfigurationBuilder();\n this.eventEmitter.emit('configure', configBuilder);\n this.send('configure', configBuilder.build(false));\n this.addon.config = new Configuration(configBuilder.build(true));\n\n // wait for the config-update to be received then send connect\n const configListener = (event: ws.MessageEvent) => {\n if (event === undefined) return;\n // event can be a Buffer, string, ArrayBuffer, or Buffer[]\n let data: string;\n if (typeof event === 'string') {\n data = event;\n } else if (event instanceof Buffer) {\n data = event.toString();\n } else if (event && typeof (event as any).data === 'string') {\n data = (event as any).data;\n } else if (event && (event as any).data instanceof Buffer) {\n data = (event as any).data.toString();\n } else {\n // fallback for other types\n data = event.toString();\n }\n const message: WebsocketMessageServer = JSON.parse(data);\n if (message.event === 'config-update') {\n console.log('Config update received');\n this.socket.off('message', configListener);\n this.eventEmitter.emit(\n 'connect',\n new EventResponse<void>((screen, name, description) => {\n return this.userInputAsked(\n screen,\n name,\n description,\n this.socket\n );\n })\n );\n }\n };\n this.socket.on('message', configListener);\n });\n\n this.socket.on('error', (error) => {\n if (error.message.includes('Failed to connect')) {\n throw new Error(\n 'OGI Addon Server is not running/is unreachable. Please start the server and try again.'\n );\n }\n console.error('An error occurred:', error);\n });\n\n this.socket.on('close', (code, reason) => {\n if (code === 1008) {\n console.error('Authentication failed:', reason);\n return;\n }\n this.eventEmitter.emit('disconnect', reason);\n console.log('Disconnected from OGI Addon Server');\n console.error(reason.toString());\n this.eventEmitter.emit('exit');\n this.socket.close();\n });\n\n this.registerMessageReceiver();\n }\n\n private async userInputAsked<\n U extends Record<string, string | number | boolean>,\n >(\n configBuilt: ConfigurationBuilder<U>,\n name: string,\n description: string,\n socket: WebSocket\n ): Promise<U> {\n const config = configBuilt.build(false);\n const id = Math.random().toString(36).substring(7);\n if (!socket) {\n throw new Error('Socket is not connected');\n }\n socket.send(\n JSON.stringify({\n event: 'input-asked',\n args: {\n config,\n name,\n description,\n },\n id: id,\n })\n );\n return await this.waitForResponseFromServer<U>(id);\n }\n\n private registerMessageReceiver() {\n this.socket.on('message', async (data: string) => {\n const message: WebsocketMessageServer = JSON.parse(data);\n switch (message.event) {\n case 'config-update':\n const result = this.addon.config.updateConfig(message.args);\n if (!result[0]) {\n this.respondToMessage(\n message.id!!,\n {\n success: false,\n error: result[1],\n },\n undefined\n );\n } else {\n this.respondToMessage(message.id!!, { success: true }, undefined);\n }\n break;\n case 'search':\n let searchResultEvent = new EventResponse<SearchResult[]>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit('search', message.args, searchResultEvent);\n const searchResult =\n await this.waitForEventToRespond(searchResultEvent);\n this.respondToMessage(\n message.id!!,\n searchResult.data,\n searchResultEvent\n );\n break;\n case 'setup': {\n let setupEvent = new EventResponse<SetupEventResponse>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit('setup', message.args, setupEvent);\n const interval = setInterval(() => {\n if (setupEvent.resolved) {\n clearInterval(interval);\n return;\n }\n this.send('defer-update', {\n logs: setupEvent.logs,\n deferID: message.args.deferID,\n progress: setupEvent.progress,\n failed: setupEvent.failed,\n } as ClientSentEventTypes['defer-update']);\n }, 100);\n const setupResult = await this.waitForEventToRespond(setupEvent);\n this.respondToMessage(message.id!!, setupResult.data, setupEvent);\n break;\n }\n case 'library-search':\n let librarySearchEvent = new EventResponse<BasicLibraryInfo[]>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit(\n 'library-search',\n message.args,\n librarySearchEvent\n );\n const librarySearchResult =\n await this.waitForEventToRespond(librarySearchEvent);\n this.respondToMessage(\n message.id!!,\n librarySearchResult.data,\n librarySearchEvent\n );\n break;\n case 'game-details':\n let gameDetailsEvent = new EventResponse<StoreData | undefined>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n if (this.eventEmitter.listenerCount('game-details') === 0) {\n this.respondToMessage(\n message.id!!,\n {\n error: 'No event listener for game-details',\n },\n gameDetailsEvent\n );\n break;\n }\n this.eventEmitter.emit(\n 'game-details',\n message.args,\n gameDetailsEvent\n );\n const gameDetailsResult =\n await this.waitForEventToRespond(gameDetailsEvent);\n this.respondToMessage(\n message.id!!,\n gameDetailsResult.data,\n gameDetailsEvent\n );\n break;\n case 'check-for-updates':\n let checkForUpdatesEvent = new EventResponse<\n | {\n available: true;\n version: string;\n }\n | {\n available: false;\n }\n >((screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n this.eventEmitter.emit(\n 'check-for-updates',\n message.args,\n checkForUpdatesEvent\n );\n const checkForUpdatesResult =\n await this.waitForEventToRespond(checkForUpdatesEvent);\n this.respondToMessage(\n message.id!!,\n checkForUpdatesResult.data,\n checkForUpdatesEvent\n );\n break;\n case 'request-dl':\n let requestDLEvent = new EventResponse<SearchResult>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n if (this.eventEmitter.listenerCount('request-dl') === 0) {\n this.respondToMessage(\n message.id!!,\n {\n error: 'No event listener for request-dl',\n },\n requestDLEvent\n );\n break;\n }\n this.eventEmitter.emit(\n 'request-dl',\n message.args.appID,\n message.args.info,\n requestDLEvent\n );\n const requestDLResult =\n await this.waitForEventToRespond(requestDLEvent);\n if (requestDLEvent.failed) {\n this.respondToMessage(message.id!!, undefined, requestDLEvent);\n break;\n }\n if (\n requestDLEvent.data === undefined ||\n requestDLEvent.data?.downloadType === 'request'\n ) {\n throw new Error(\n 'Request DL event did not return a valid result. Please ensure that the event does not resolve with another `request` download type.'\n );\n }\n this.respondToMessage(\n message.id!!,\n requestDLResult.data,\n requestDLEvent\n );\n break;\n case 'catalog':\n let catalogEvent = new EventResponse<{\n [key: string]: {\n name: string;\n description: string;\n listings: BasicLibraryInfo[];\n };\n }>();\n this.eventEmitter.emit('catalog', catalogEvent);\n const catalogResult = await this.waitForEventToRespond(catalogEvent);\n this.respondToMessage(message.id!!, catalogResult.data, catalogEvent);\n break;\n case 'task-run': {\n let taskRunEvent = new EventResponse<void>(\n (screen, name, description) =>\n this.userInputAsked(screen, name, description, this.socket)\n );\n\n // Check for taskName: first from args directly (from SearchResult), then from manifest.__taskName (for ActionOption)\n const taskName =\n message.args.taskName && typeof message.args.taskName === 'string'\n ? message.args.taskName\n : message.args.manifest &&\n typeof message.args.manifest === 'object'\n ? (message.args.manifest as Record<string, unknown>).__taskName\n : undefined;\n\n if (\n taskName &&\n typeof taskName === 'string' &&\n this.addon.hasTaskHandler(taskName)\n ) {\n // Use the registered task handler\n const handler = this.addon.getTaskHandler(taskName)!;\n const task = new Task(taskRunEvent);\n try {\n const interval = setInterval(() => {\n if (taskRunEvent.resolved) {\n clearInterval(interval);\n return;\n }\n this.send('defer-update', {\n logs: taskRunEvent.logs,\n deferID: message.args.deferID,\n progress: taskRunEvent.progress,\n failed: taskRunEvent.failed,\n } as ClientSentEventTypes['defer-update']);\n }, 100);\n const result = handler(task, {\n manifest: message.args.manifest || {},\n downloadPath: message.args.downloadPath || '',\n name: message.args.name || '',\n });\n // If handler returns a promise, wait for it\n if (result instanceof Promise) {\n await result;\n }\n\n clearInterval(interval);\n } catch (error) {\n taskRunEvent.fail(\n error instanceof Error ? error.message : String(error)\n );\n }\n } else {\n // No handler found - fail the task\n taskRunEvent.fail(\n taskName\n ? `No task handler registered for task name: ${taskName}`\n : 'No task name provided'\n );\n }\n\n const taskRunResult = await this.waitForEventToRespond(taskRunEvent);\n this.respondToMessage(message.id!!, taskRunResult.data, taskRunEvent);\n break;\n }\n }\n });\n }\n\n private waitForEventToRespond<T>(\n event: EventResponse<T>\n ): Promise<EventResponse<T>> {\n // check the handlers to see if there even is any\n return new Promise((resolve, reject) => {\n const dataGet = setInterval(() => {\n if (event.resolved) {\n resolve(event);\n clearTimeout(timeout);\n }\n }, 5);\n\n const timeout = setTimeout(() => {\n if (event.deffered) {\n clearInterval(dataGet);\n const interval = setInterval(() => {\n if (event.resolved) {\n clearInterval(interval);\n resolve(event);\n }\n }, 100);\n } else {\n reject('Event did not respond in time');\n }\n }, 5000);\n });\n }\n\n public respondToMessage(\n messageID: string,\n response: any,\n originalEvent: EventResponse<any> | undefined\n ) {\n this.socket.send(\n JSON.stringify({\n event: 'response',\n id: messageID,\n args: response,\n statusError: originalEvent ? originalEvent.failed : undefined,\n })\n );\n console.log('dispatched response to ' + messageID);\n }\n\n public waitForResponseFromServer<T>(messageID: string): Promise<T> {\n return new Promise((resolve) => {\n const waiter = (data: string) => {\n const message: WebsocketMessageClient = JSON.parse(data);\n if (message.event !== 'response') {\n this.socket.once('message', waiter);\n return;\n }\n console.log('received response from ' + messageID);\n\n if (message.id === messageID) {\n resolve(message.args);\n } else {\n this.socket.once('message', waiter);\n }\n };\n this.socket.once('message', waiter);\n });\n }\n\n public send(\n event: OGIAddonClientSentEvent,\n args: ClientSentEventTypes[OGIAddonClientSentEvent]\n ): string {\n // generate a random id\n const id = Math.random().toString(36).substring(7);\n this.socket.send(\n JSON.stringify({\n event,\n args,\n id,\n })\n );\n return id;\n }\n\n public close() {\n this.socket.close();\n }\n}\n"],"mappings":"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"}
|
package/build/main.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as ConfigurationBuilder } from "./ConfigurationBuilder-C83EP5v2.cjs";
|
|
2
2
|
import { t as Configuration } from "./Configuration-DdkCGFMU.cjs";
|
|
3
3
|
import { t as SearchResult } from "./SearchEngine-Cn_-M-at.cjs";
|
|
4
|
-
import { _ as
|
|
5
|
-
export { BasicLibraryInfo, ClientSentEventTypes, Configuration, ConfigurationBuilder,
|
|
4
|
+
import { _ as WebsocketMessageServer, a as LibraryInfo, c as OGIAddonConfiguration, d as SearchTool, f as SetupEventResponse, g as WebsocketMessageClient, h as VERSION, i as EventListenerTypes, l as OGIAddonEvent, m as Task, n as BasicLibraryInfo, o as OGIAddon, p as StoreData, r as ClientSentEventTypes, s as OGIAddonClientSentEvent, t as EventResponse, u as OGIAddonServerSentEvent, v as ZodLibraryInfo } from "./EventResponse-Btb5YASI.cjs";
|
|
5
|
+
export { BasicLibraryInfo, ClientSentEventTypes, Configuration, ConfigurationBuilder, EventListenerTypes, EventResponse, LibraryInfo, OGIAddonClientSentEvent, OGIAddonConfiguration, OGIAddonEvent, OGIAddonServerSentEvent, SearchResult, SearchTool, SetupEventResponse, StoreData, Task, VERSION, WebsocketMessageClient, WebsocketMessageServer, ZodLibraryInfo, OGIAddon as default };
|