ogi-addon 1.2.0 → 1.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/build/main.js CHANGED
@@ -14,7 +14,7 @@ var ConfigurationBuilder = class {
14
14
  /**
15
15
  * Add a number option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.
16
16
  * @param option { (option: NumberOption) => NumberOption }
17
- * @returns
17
+ * @returns
18
18
  */
19
19
  addNumberOption(option) {
20
20
  let newOption = new NumberOption();
@@ -25,7 +25,7 @@ var ConfigurationBuilder = class {
25
25
  /**
26
26
  * Add a string option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.
27
27
  * @param option { (option: StringOption) => StringOption }
28
- */
28
+ */
29
29
  addStringOption(option) {
30
30
  let newOption = new StringOption();
31
31
  newOption = option(newOption);
@@ -35,7 +35,7 @@ var ConfigurationBuilder = class {
35
35
  /**
36
36
  * Add a boolean option to the configuration builder and return the builder for chaining. You must provide a name, display name, and description for the option.
37
37
  * @param option { (option: BooleanOption) => BooleanOption }
38
- */
38
+ */
39
39
  addBooleanOption(option) {
40
40
  let newOption = new BooleanOption();
41
41
  newOption = option(newOption);
@@ -74,9 +74,9 @@ var ConfigurationOption = class {
74
74
  return this;
75
75
  }
76
76
  /**
77
- * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED**
78
- * @param displayName {string} The display name of the option.
79
- * @returns
77
+ * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED**
78
+ * @param displayName {string} The display name of the option.
79
+ * @returns
80
80
  */
81
81
  setDisplayName(displayName) {
82
82
  this.displayName = displayName;
@@ -84,8 +84,8 @@ var ConfigurationOption = class {
84
84
  }
85
85
  /**
86
86
  * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**
87
- * @param description {string} The description of the option.
88
- * @returns
87
+ * @param description {string} The description of the option.
88
+ * @returns
89
89
  */
90
90
  setDescription(description) {
91
91
  this.description = description;
@@ -107,7 +107,7 @@ var StringOption = class extends ConfigurationOption {
107
107
  inputType = "text";
108
108
  type = "string";
109
109
  /**
110
- * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown.
110
+ * Set the allowed values for the string. If the array is empty, any value is allowed. When provided, the client will act like this option is a dropdown.
111
111
  * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.
112
112
  */
113
113
  setAllowedValues(allowedValues) {
@@ -123,15 +123,15 @@ var StringOption = class extends ConfigurationOption {
123
123
  return this;
124
124
  }
125
125
  /**
126
- * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail.
127
- * @param minTextLength {number} The minimum text length for the string.
126
+ * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail.
127
+ * @param minTextLength {number} The minimum text length for the string.
128
128
  */
129
129
  setMinTextLength(minTextLength) {
130
130
  this.minTextLength = minTextLength;
131
131
  return this;
132
132
  }
133
133
  /**
134
- * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail.
134
+ * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail.
135
135
  * @param maxTextLength {number} The maximum text length for the string.
136
136
  */
137
137
  setMaxTextLength(maxTextLength) {
@@ -139,8 +139,8 @@ var StringOption = class extends ConfigurationOption {
139
139
  return this;
140
140
  }
141
141
  /**
142
- * Set the input type for the string. This will change how the client renders the input.
143
- * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string.
142
+ * Set the input type for the string. This will change how the client renders the input.
143
+ * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string.
144
144
  */
145
145
  setInputType(inputType) {
146
146
  this.inputType = inputType;
@@ -153,9 +153,15 @@ var StringOption = class extends ConfigurationOption {
153
153
  if (this.allowedValues.length === 0 && input.length !== 0)
154
154
  return [true, ""];
155
155
  if (input.length < this.minTextLength || input.length > this.maxTextLength) {
156
- return [false, "Input is not within the text length " + this.minTextLength + " and " + this.maxTextLength + " characters (currently " + input.length + " characters)"];
156
+ return [
157
+ false,
158
+ "Input is not within the text length " + this.minTextLength + " and " + this.maxTextLength + " characters (currently " + input.length + " characters)"
159
+ ];
157
160
  }
158
- return [this.allowedValues.includes(input), "Input is not an allowed value"];
161
+ return [
162
+ this.allowedValues.includes(input),
163
+ "Input is not an allowed value"
164
+ ];
159
165
  }
160
166
  };
161
167
  var NumberOption = class extends ConfigurationOption {
@@ -173,8 +179,8 @@ var NumberOption = class extends ConfigurationOption {
173
179
  return this;
174
180
  }
175
181
  /**
176
- * Set the input type for the number. This will change how the client renders the input.
177
- * @param type {'range' | 'number'} The input type for the number.
182
+ * Set the input type for the number. This will change how the client renders the input.
183
+ * @param type {'range' | 'number'} The input type for the number.
178
184
  */
179
185
  setInputType(type) {
180
186
  this.inputType = type;
@@ -201,7 +207,10 @@ var NumberOption = class extends ConfigurationOption {
201
207
  return [false, "Input is not a number"];
202
208
  }
203
209
  if (Number(input) < this.min || Number(input) > this.max) {
204
- return [false, "Input is not within the range of " + this.min + " and " + this.max];
210
+ return [
211
+ false,
212
+ "Input is not within the range of " + this.min + " and " + this.max
213
+ ];
205
214
  }
206
215
  return [true, ""];
207
216
  }
@@ -245,20 +254,26 @@ var Configuration = class {
245
254
  const erroredKeys = /* @__PURE__ */ new Map();
246
255
  for (const key in this.storedConfigTemplate) {
247
256
  if (this.definiteConfig[key] === null || this.definiteConfig[key] === void 0) {
248
- console.warn("Option " + key + " is not defined. Using default value Value: " + this.definiteConfig[key]);
257
+ console.warn(
258
+ "Option " + key + " is not defined. Using default value Value: " + this.definiteConfig[key]
259
+ );
249
260
  this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue;
250
261
  }
251
262
  if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {
252
263
  throw new Error("Option " + key + " is not of the correct type");
253
264
  }
254
- const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);
265
+ const result = this.storedConfigTemplate[key].validate(
266
+ this.definiteConfig[key]
267
+ );
255
268
  if (!result[0]) {
256
269
  erroredKeys.set(key, result[1]);
257
270
  }
258
271
  }
259
272
  for (const key in this.definiteConfig) {
260
273
  if (!this.storedConfigTemplate[key]) {
261
- throw new Error("Option " + key + " is not defined in the configuration template");
274
+ throw new Error(
275
+ "Option " + key + " is not defined in the configuration template"
276
+ );
262
277
  }
263
278
  }
264
279
  if (erroredKeys.size > 0) {
@@ -302,15 +317,19 @@ var EventResponse = class {
302
317
  resolved = false;
303
318
  progress = 0;
304
319
  logs = [];
320
+ failed = void 0;
305
321
  onInputAsked;
306
322
  constructor(onInputAsked) {
307
323
  this.onInputAsked = onInputAsked;
308
324
  }
309
- defer() {
325
+ defer(promise) {
310
326
  this.deffered = true;
327
+ if (promise) {
328
+ promise();
329
+ }
311
330
  }
312
331
  /**
313
- * Resolve the event with data. This acts like a promise resolve, and will stop the event from being processed further. **You must always call this method when you are done with the event.**
332
+ * Resolve the event with data. This acts like a promise resolve, and will stop the event from being processed further. **You must always call this method when you are done with the event.**
314
333
  * @param data {T}
315
334
  */
316
335
  resolve(data) {
@@ -318,13 +337,17 @@ var EventResponse = class {
318
337
  this.data = data;
319
338
  }
320
339
  /**
321
- * Completes the event and resolves it, but does not return any data. **You must always call this method when you are done with the event.**
340
+ * Completes the event and resolves it, but does not return any data. **You must always call this method when you are done with the event.**
322
341
  */
323
342
  complete() {
324
343
  this.resolved = true;
325
344
  }
345
+ fail(message) {
346
+ this.resolved = true;
347
+ this.failed = message;
348
+ }
326
349
  /**
327
- * Logs a message to the event. This is useful for debugging and logging information to the user.
350
+ * Logs a message to the event. This is useful for debugging and logging information to the user.
328
351
  * @param message {string}
329
352
  */
330
353
  log(message) {
@@ -355,7 +378,7 @@ var package_default = {
355
378
  module: "./build/main.js",
356
379
  type: "module",
357
380
  main: "./build/main.cjs",
358
- version: "1.2.0",
381
+ version: "1.3.0",
359
382
  exports: {
360
383
  ".": {
361
384
  import: {
@@ -398,6 +421,7 @@ var package_default = {
398
421
  devDependencies: {
399
422
  "@types/node": "^20.14.12",
400
423
  "@types/ws": "^8.4.0",
424
+ prettier: "^3.6.0",
401
425
  tsup: "^8.2.3",
402
426
  typescript: "^5.0.0"
403
427
  }
@@ -412,34 +436,45 @@ var OGIAddon = class {
412
436
  addonInfo;
413
437
  config = new Configuration({});
414
438
  constructor(addonInfo) {
415
- this.addonInfo = addonInfo;
439
+ this.addonInfo = { storeFrontServerCapable: false, ...addonInfo };
416
440
  this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);
417
441
  }
418
442
  /**
419
- * Register an event listener for the addon. (See EventListenerTypes)
443
+ * Register an event listener for the addon. (See EventListenerTypes)
420
444
  * @param event {OGIAddonEvent}
421
- * @param listener {EventListenerTypes[OGIAddonEvent]}
445
+ * @param listener {EventListenerTypes[OGIAddonEvent]}
422
446
  */
423
447
  on(event, listener) {
424
448
  this.eventEmitter.on(event, listener);
449
+ if (event === "game-details") {
450
+ this.addonInfo.storeFrontServerCapable = true;
451
+ this.addonWSListener.send("flag", {
452
+ flag: "storeFrontServerCapable",
453
+ value: this.addonInfo.storeFrontServerCapable
454
+ });
455
+ }
425
456
  }
426
457
  emit(event, ...args) {
427
458
  this.eventEmitter.emit(event, ...args);
428
459
  }
429
460
  /**
430
- * Notify the client using a notification. Provide the type of notification, the message, and an ID.
461
+ * Notify the client using a notification. Provide the type of notification, the message, and an ID.
431
462
  * @param notification {Notification}
432
463
  */
433
464
  notify(notification) {
434
465
  this.addonWSListener.send("notification", [notification]);
435
466
  }
436
467
  /**
437
- * Search for items in the OGI Steam-Synced Library. Query can either be a Steam AppID or a Steam Game Name.
438
- * @param query {string}
439
- * @param event {EventResponse<BasicLibraryInfo[]>}
468
+ * Get the app details for a given appID and storefront.
469
+ * @param appID {number}
470
+ * @param storefront {string}
471
+ * @returns {Promise<StoreData>}
440
472
  */
441
- async steamSearch(query, strict = false) {
442
- const id = this.addonWSListener.send("steam-search", { query, strict });
473
+ async getAppDetails(appID, storefront) {
474
+ const id = this.addonWSListener.send("get-app-details", {
475
+ appID,
476
+ storefront
477
+ });
443
478
  return await this.addonWSListener.waitForResponseFromServer(id);
444
479
  }
445
480
  /**
@@ -453,7 +488,13 @@ var OGIAddon = class {
453
488
  const progress = 0;
454
489
  const logs = [];
455
490
  const task = new CustomTask(this.addonWSListener, id, progress, logs);
456
- this.addonWSListener.send("task-update", { id, progress, logs, finished: false });
491
+ this.addonWSListener.send("task-update", {
492
+ id,
493
+ progress,
494
+ logs,
495
+ finished: false,
496
+ failed: void 0
497
+ });
457
498
  return task;
458
499
  }
459
500
  };
@@ -463,6 +504,7 @@ var CustomTask = class {
463
504
  logs;
464
505
  finished = false;
465
506
  ws;
507
+ failed = void 0;
466
508
  constructor(ws2, id, progress, logs) {
467
509
  this.id = id;
468
510
  this.progress = progress;
@@ -477,17 +519,30 @@ var CustomTask = class {
477
519
  this.finished = true;
478
520
  this.update();
479
521
  }
522
+ fail(message) {
523
+ this.failed = message;
524
+ this.update();
525
+ }
480
526
  setProgress(progress) {
481
527
  this.progress = progress;
482
528
  this.update();
483
529
  }
484
530
  update() {
485
- this.ws.send("task-update", { id: this.id, progress: this.progress, logs: this.logs, finished: this.finished });
531
+ this.ws.send("task-update", {
532
+ id: this.id,
533
+ progress: this.progress,
534
+ logs: this.logs,
535
+ finished: this.finished,
536
+ failed: this.failed
537
+ });
486
538
  }
487
539
  };
488
540
  var SearchTool = class {
489
541
  fuse;
490
- constructor(items, keys, options = { threshold: 0.3, includeScore: true }) {
542
+ constructor(items, keys, options = {
543
+ threshold: 0.3,
544
+ includeScore: true
545
+ }) {
491
546
  this.fuse = new Fuse(items, {
492
547
  keys,
493
548
  ...options
@@ -506,7 +561,9 @@ var OGIAddonWSListener = class {
506
561
  addon;
507
562
  constructor(ogiAddon, eventEmitter) {
508
563
  if (process.argv[process.argv.length - 1].split("=")[0] !== "--addonSecret") {
509
- throw new Error("No secret provided. This usually happens because the addon was not started by the OGI Addon Server.");
564
+ throw new Error(
565
+ "No secret provided. This usually happens because the addon was not started by the OGI Addon Server."
566
+ );
510
567
  }
511
568
  this.addon = ogiAddon;
512
569
  this.eventEmitter = eventEmitter;
@@ -527,7 +584,9 @@ var OGIAddonWSListener = class {
527
584
  });
528
585
  this.socket.on("error", (error) => {
529
586
  if (error.message.includes("Failed to connect")) {
530
- throw new Error("OGI Addon Server is not running/is unreachable. Please start the server and try again.");
587
+ throw new Error(
588
+ "OGI Addon Server is not running/is unreachable. Please start the server and try again."
589
+ );
531
590
  }
532
591
  console.error("An error occurred:", error);
533
592
  });
@@ -550,15 +609,17 @@ var OGIAddonWSListener = class {
550
609
  if (!socket) {
551
610
  return {};
552
611
  }
553
- socket.send(JSON.stringify({
554
- event: "input-asked",
555
- args: {
556
- config,
557
- name,
558
- description
559
- },
560
- id
561
- }));
612
+ socket.send(
613
+ JSON.stringify({
614
+ event: "input-asked",
615
+ args: {
616
+ config,
617
+ name,
618
+ description
619
+ },
620
+ id
621
+ })
622
+ );
562
623
  return await this.waitForResponseFromServer(id);
563
624
  }
564
625
  registerMessageReceiver() {
@@ -568,20 +629,39 @@ var OGIAddonWSListener = class {
568
629
  case "config-update":
569
630
  const result = this.addon.config.updateConfig(message.args);
570
631
  if (!result[0]) {
571
- this.respondToMessage(message.id, { success: false, error: result[1] });
632
+ this.respondToMessage(message.id, {
633
+ success: false,
634
+ error: result[1]
635
+ });
572
636
  } else {
573
637
  this.respondToMessage(message.id, { success: true });
574
638
  }
575
639
  break;
576
640
  case "search":
577
- let searchResultEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
641
+ let searchResultEvent = new EventResponse(
642
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
643
+ );
578
644
  this.eventEmitter.emit("search", message.args, searchResultEvent);
579
645
  const searchResult = await this.waitForEventToRespond(searchResultEvent);
580
646
  this.respondToMessage(message.id, searchResult.data);
581
647
  break;
582
648
  case "setup":
583
- let setupEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
584
- this.eventEmitter.emit("setup", { path: message.args.path, appID: message.args.appID, storefront: message.args.storefront, type: message.args.type, name: message.args.name, usedRealDebrid: message.args.usedRealDebrid, multiPartFiles: message.args.multiPartFiles }, setupEvent);
649
+ let setupEvent = new EventResponse(
650
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
651
+ );
652
+ this.eventEmitter.emit(
653
+ "setup",
654
+ {
655
+ path: message.args.path,
656
+ appID: message.args.appID,
657
+ storefront: message.args.storefront,
658
+ type: message.args.type,
659
+ name: message.args.name,
660
+ usedRealDebrid: message.args.usedRealDebrid,
661
+ multiPartFiles: message.args.multiPartFiles
662
+ },
663
+ setupEvent
664
+ );
585
665
  const interval = setInterval(() => {
586
666
  if (setupEvent.resolved) {
587
667
  clearInterval(interval);
@@ -590,45 +670,83 @@ var OGIAddonWSListener = class {
590
670
  this.send("defer-update", {
591
671
  logs: setupEvent.logs,
592
672
  deferID: message.args.deferID,
593
- progress: setupEvent.progress
673
+ progress: setupEvent.progress,
674
+ failed: setupEvent.failed
594
675
  });
595
676
  }, 100);
596
677
  const setupResult = await this.waitForEventToRespond(setupEvent);
597
678
  this.respondToMessage(message.id, setupResult.data);
598
679
  break;
599
680
  case "library-search":
600
- let librarySearchEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
681
+ let librarySearchEvent = new EventResponse(
682
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
683
+ );
601
684
  if (this.eventEmitter.listenerCount("game-details") === 0) {
602
685
  this.respondToMessage(message.id, []);
603
686
  break;
604
687
  }
605
- this.eventEmitter.emit("library-search", message.args, librarySearchEvent);
688
+ this.eventEmitter.emit(
689
+ "library-search",
690
+ message.args,
691
+ librarySearchEvent
692
+ );
606
693
  const librarySearchResult = await this.waitForEventToRespond(librarySearchEvent);
607
694
  this.respondToMessage(message.id, librarySearchResult.data);
608
695
  break;
609
696
  case "game-details":
610
- let gameDetailsEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
697
+ let gameDetailsEvent = new EventResponse(
698
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
699
+ );
611
700
  if (this.eventEmitter.listenerCount("game-details") === 0) {
612
- this.respondToMessage(message.id, { error: "No event listener for game-details" });
701
+ this.respondToMessage(message.id, {
702
+ error: "No event listener for game-details"
703
+ });
613
704
  break;
614
705
  }
615
- this.eventEmitter.emit("game-details", message.args, gameDetailsEvent);
706
+ this.eventEmitter.emit(
707
+ "game-details",
708
+ message.args,
709
+ gameDetailsEvent
710
+ );
616
711
  const gameDetailsResult = await this.waitForEventToRespond(gameDetailsEvent);
617
712
  this.respondToMessage(message.id, gameDetailsResult.data);
618
713
  break;
619
714
  case "request-dl":
620
- let requestDLEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
715
+ let requestDLEvent = new EventResponse(
716
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
717
+ );
621
718
  if (this.eventEmitter.listenerCount("request-dl") === 0) {
622
- this.respondToMessage(message.id, { error: "No event listener for request-dl" });
719
+ this.respondToMessage(message.id, {
720
+ error: "No event listener for request-dl"
721
+ });
623
722
  break;
624
723
  }
625
- this.eventEmitter.emit("request-dl", message.args.appID, message.args.info, requestDLEvent);
724
+ this.eventEmitter.emit(
725
+ "request-dl",
726
+ message.args.appID,
727
+ message.args.info,
728
+ requestDLEvent
729
+ );
626
730
  const requestDLResult = await this.waitForEventToRespond(requestDLEvent);
627
- if (requestDLEvent.data === null || requestDLEvent.data?.downloadType === "request") {
628
- throw new Error("Request DL event did not return a valid result. Please ensure that the event does not resolve with another `request` download type.");
731
+ if (requestDLEvent.failed) {
732
+ this.respondToMessage(message.id, {
733
+ statusError: requestDLEvent.failed
734
+ });
735
+ break;
736
+ }
737
+ if (requestDLEvent.data === void 0 || requestDLEvent.data?.downloadType === "request") {
738
+ throw new Error(
739
+ "Request DL event did not return a valid result. Please ensure that the event does not resolve with another `request` download type."
740
+ );
629
741
  }
630
742
  this.respondToMessage(message.id, requestDLResult.data);
631
743
  break;
744
+ case "catalog":
745
+ let catalogEvent = new EventResponse();
746
+ this.eventEmitter.emit("catalog", catalogEvent);
747
+ const catalogResult = await this.waitForEventToRespond(catalogEvent);
748
+ this.respondToMessage(message.id, catalogResult.data);
749
+ break;
632
750
  }
633
751
  });
634
752
  }
@@ -656,11 +774,13 @@ var OGIAddonWSListener = class {
656
774
  });
657
775
  }
658
776
  respondToMessage(messageID, response) {
659
- this.socket.send(JSON.stringify({
660
- event: "response",
661
- id: messageID,
662
- args: response
663
- }));
777
+ this.socket.send(
778
+ JSON.stringify({
779
+ event: "response",
780
+ id: messageID,
781
+ args: response
782
+ })
783
+ );
664
784
  console.log("dispatched response to " + messageID);
665
785
  }
666
786
  waitForResponseFromServer(messageID) {
@@ -683,11 +803,13 @@ var OGIAddonWSListener = class {
683
803
  }
684
804
  send(event, args) {
685
805
  const id = Math.random().toString(36).substring(7);
686
- this.socket.send(JSON.stringify({
687
- event,
688
- args,
689
- id
690
- }));
806
+ this.socket.send(
807
+ JSON.stringify({
808
+ event,
809
+ args,
810
+ id
811
+ })
812
+ );
691
813
  return id;
692
814
  }
693
815
  close() {