ogi-addon 1.2.2 → 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.cjs CHANGED
@@ -54,7 +54,7 @@ var ConfigurationBuilder = class {
54
54
  /**
55
55
  * 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.
56
56
  * @param option { (option: NumberOption) => NumberOption }
57
- * @returns
57
+ * @returns
58
58
  */
59
59
  addNumberOption(option) {
60
60
  let newOption = new NumberOption();
@@ -65,7 +65,7 @@ var ConfigurationBuilder = class {
65
65
  /**
66
66
  * 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.
67
67
  * @param option { (option: StringOption) => StringOption }
68
- */
68
+ */
69
69
  addStringOption(option) {
70
70
  let newOption = new StringOption();
71
71
  newOption = option(newOption);
@@ -75,7 +75,7 @@ var ConfigurationBuilder = class {
75
75
  /**
76
76
  * 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.
77
77
  * @param option { (option: BooleanOption) => BooleanOption }
78
- */
78
+ */
79
79
  addBooleanOption(option) {
80
80
  let newOption = new BooleanOption();
81
81
  newOption = option(newOption);
@@ -114,9 +114,9 @@ var ConfigurationOption = class {
114
114
  return this;
115
115
  }
116
116
  /**
117
- * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED**
118
- * @param displayName {string} The display name of the option.
119
- * @returns
117
+ * Set the display name of the option. This is used to show the user a human readable version of what the option is. **REQUIRED**
118
+ * @param displayName {string} The display name of the option.
119
+ * @returns
120
120
  */
121
121
  setDisplayName(displayName) {
122
122
  this.displayName = displayName;
@@ -124,8 +124,8 @@ var ConfigurationOption = class {
124
124
  }
125
125
  /**
126
126
  * Set the description of the option. This is to show the user a brief description of what this option does. **REQUIRED**
127
- * @param description {string} The description of the option.
128
- * @returns
127
+ * @param description {string} The description of the option.
128
+ * @returns
129
129
  */
130
130
  setDescription(description) {
131
131
  this.description = description;
@@ -147,7 +147,7 @@ var StringOption = class extends ConfigurationOption {
147
147
  inputType = "text";
148
148
  type = "string";
149
149
  /**
150
- * 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.
150
+ * 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.
151
151
  * @param allowedValues {string[]} An array of allowed values for the string. If the array is empty, any value is allowed.
152
152
  */
153
153
  setAllowedValues(allowedValues) {
@@ -163,15 +163,15 @@ var StringOption = class extends ConfigurationOption {
163
163
  return this;
164
164
  }
165
165
  /**
166
- * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail.
167
- * @param minTextLength {number} The minimum text length for the string.
166
+ * Set the minimum text length for the string. If the user provides a string that is less than this value, the validation will fail.
167
+ * @param minTextLength {number} The minimum text length for the string.
168
168
  */
169
169
  setMinTextLength(minTextLength) {
170
170
  this.minTextLength = minTextLength;
171
171
  return this;
172
172
  }
173
173
  /**
174
- * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail.
174
+ * Set the maximum text length for the string. If the user provides a string that is greater than this value, the validation will fail.
175
175
  * @param maxTextLength {number} The maximum text length for the string.
176
176
  */
177
177
  setMaxTextLength(maxTextLength) {
@@ -179,8 +179,8 @@ var StringOption = class extends ConfigurationOption {
179
179
  return this;
180
180
  }
181
181
  /**
182
- * Set the input type for the string. This will change how the client renders the input.
183
- * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string.
182
+ * Set the input type for the string. This will change how the client renders the input.
183
+ * @param inputType {'text' | 'file' | 'password' | 'folder'} The input type for the string.
184
184
  */
185
185
  setInputType(inputType) {
186
186
  this.inputType = inputType;
@@ -193,9 +193,15 @@ var StringOption = class extends ConfigurationOption {
193
193
  if (this.allowedValues.length === 0 && input.length !== 0)
194
194
  return [true, ""];
195
195
  if (input.length < this.minTextLength || input.length > this.maxTextLength) {
196
- return [false, "Input is not within the text length " + this.minTextLength + " and " + this.maxTextLength + " characters (currently " + input.length + " characters)"];
196
+ return [
197
+ false,
198
+ "Input is not within the text length " + this.minTextLength + " and " + this.maxTextLength + " characters (currently " + input.length + " characters)"
199
+ ];
197
200
  }
198
- return [this.allowedValues.includes(input), "Input is not an allowed value"];
201
+ return [
202
+ this.allowedValues.includes(input),
203
+ "Input is not an allowed value"
204
+ ];
199
205
  }
200
206
  };
201
207
  var NumberOption = class extends ConfigurationOption {
@@ -213,8 +219,8 @@ var NumberOption = class extends ConfigurationOption {
213
219
  return this;
214
220
  }
215
221
  /**
216
- * Set the input type for the number. This will change how the client renders the input.
217
- * @param type {'range' | 'number'} The input type for the number.
222
+ * Set the input type for the number. This will change how the client renders the input.
223
+ * @param type {'range' | 'number'} The input type for the number.
218
224
  */
219
225
  setInputType(type) {
220
226
  this.inputType = type;
@@ -241,7 +247,10 @@ var NumberOption = class extends ConfigurationOption {
241
247
  return [false, "Input is not a number"];
242
248
  }
243
249
  if (Number(input) < this.min || Number(input) > this.max) {
244
- return [false, "Input is not within the range of " + this.min + " and " + this.max];
250
+ return [
251
+ false,
252
+ "Input is not within the range of " + this.min + " and " + this.max
253
+ ];
245
254
  }
246
255
  return [true, ""];
247
256
  }
@@ -285,20 +294,26 @@ var Configuration = class {
285
294
  const erroredKeys = /* @__PURE__ */ new Map();
286
295
  for (const key in this.storedConfigTemplate) {
287
296
  if (this.definiteConfig[key] === null || this.definiteConfig[key] === void 0) {
288
- console.warn("Option " + key + " is not defined. Using default value Value: " + this.definiteConfig[key]);
297
+ console.warn(
298
+ "Option " + key + " is not defined. Using default value Value: " + this.definiteConfig[key]
299
+ );
289
300
  this.definiteConfig[key] = this.storedConfigTemplate[key].defaultValue;
290
301
  }
291
302
  if (this.storedConfigTemplate[key].type !== typeof this.definiteConfig[key]) {
292
303
  throw new Error("Option " + key + " is not of the correct type");
293
304
  }
294
- const result = this.storedConfigTemplate[key].validate(this.definiteConfig[key]);
305
+ const result = this.storedConfigTemplate[key].validate(
306
+ this.definiteConfig[key]
307
+ );
295
308
  if (!result[0]) {
296
309
  erroredKeys.set(key, result[1]);
297
310
  }
298
311
  }
299
312
  for (const key in this.definiteConfig) {
300
313
  if (!this.storedConfigTemplate[key]) {
301
- throw new Error("Option " + key + " is not defined in the configuration template");
314
+ throw new Error(
315
+ "Option " + key + " is not defined in the configuration template"
316
+ );
302
317
  }
303
318
  }
304
319
  if (erroredKeys.size > 0) {
@@ -354,7 +369,7 @@ var EventResponse = class {
354
369
  }
355
370
  }
356
371
  /**
357
- * 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.**
372
+ * 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.**
358
373
  * @param data {T}
359
374
  */
360
375
  resolve(data) {
@@ -362,7 +377,7 @@ var EventResponse = class {
362
377
  this.data = data;
363
378
  }
364
379
  /**
365
- * 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.**
380
+ * 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.**
366
381
  */
367
382
  complete() {
368
383
  this.resolved = true;
@@ -372,7 +387,7 @@ var EventResponse = class {
372
387
  this.failed = message;
373
388
  }
374
389
  /**
375
- * Logs a message to the event. This is useful for debugging and logging information to the user.
390
+ * Logs a message to the event. This is useful for debugging and logging information to the user.
376
391
  * @param message {string}
377
392
  */
378
393
  log(message) {
@@ -403,7 +418,7 @@ var package_default = {
403
418
  module: "./build/main.js",
404
419
  type: "module",
405
420
  main: "./build/main.cjs",
406
- version: "1.2.2",
421
+ version: "1.3.0",
407
422
  exports: {
408
423
  ".": {
409
424
  import: {
@@ -446,6 +461,7 @@ var package_default = {
446
461
  devDependencies: {
447
462
  "@types/node": "^20.14.12",
448
463
  "@types/ws": "^8.4.0",
464
+ prettier: "^3.6.0",
449
465
  tsup: "^8.2.3",
450
466
  typescript: "^5.0.0"
451
467
  }
@@ -460,34 +476,45 @@ var OGIAddon = class {
460
476
  addonInfo;
461
477
  config = new Configuration({});
462
478
  constructor(addonInfo) {
463
- this.addonInfo = addonInfo;
479
+ this.addonInfo = { storeFrontServerCapable: false, ...addonInfo };
464
480
  this.addonWSListener = new OGIAddonWSListener(this, this.eventEmitter);
465
481
  }
466
482
  /**
467
- * Register an event listener for the addon. (See EventListenerTypes)
483
+ * Register an event listener for the addon. (See EventListenerTypes)
468
484
  * @param event {OGIAddonEvent}
469
- * @param listener {EventListenerTypes[OGIAddonEvent]}
485
+ * @param listener {EventListenerTypes[OGIAddonEvent]}
470
486
  */
471
487
  on(event, listener) {
472
488
  this.eventEmitter.on(event, listener);
489
+ if (event === "game-details") {
490
+ this.addonInfo.storeFrontServerCapable = true;
491
+ this.addonWSListener.send("flag", {
492
+ flag: "storeFrontServerCapable",
493
+ value: this.addonInfo.storeFrontServerCapable
494
+ });
495
+ }
473
496
  }
474
497
  emit(event, ...args) {
475
498
  this.eventEmitter.emit(event, ...args);
476
499
  }
477
500
  /**
478
- * Notify the client using a notification. Provide the type of notification, the message, and an ID.
501
+ * Notify the client using a notification. Provide the type of notification, the message, and an ID.
479
502
  * @param notification {Notification}
480
503
  */
481
504
  notify(notification) {
482
505
  this.addonWSListener.send("notification", [notification]);
483
506
  }
484
507
  /**
485
- * Search for items in the OGI Steam-Synced Library. Query can either be a Steam AppID or a Steam Game Name.
486
- * @param query {string}
487
- * @param event {EventResponse<BasicLibraryInfo[]>}
508
+ * Get the app details for a given appID and storefront.
509
+ * @param appID {number}
510
+ * @param storefront {string}
511
+ * @returns {Promise<StoreData>}
488
512
  */
489
- async steamSearch(query, strict = false) {
490
- const id = this.addonWSListener.send("steam-search", { query, strict });
513
+ async getAppDetails(appID, storefront) {
514
+ const id = this.addonWSListener.send("get-app-details", {
515
+ appID,
516
+ storefront
517
+ });
491
518
  return await this.addonWSListener.waitForResponseFromServer(id);
492
519
  }
493
520
  /**
@@ -501,7 +528,13 @@ var OGIAddon = class {
501
528
  const progress = 0;
502
529
  const logs = [];
503
530
  const task = new CustomTask(this.addonWSListener, id, progress, logs);
504
- this.addonWSListener.send("task-update", { id, progress, logs, finished: false, failed: void 0 });
531
+ this.addonWSListener.send("task-update", {
532
+ id,
533
+ progress,
534
+ logs,
535
+ finished: false,
536
+ failed: void 0
537
+ });
505
538
  return task;
506
539
  }
507
540
  };
@@ -535,12 +568,21 @@ var CustomTask = class {
535
568
  this.update();
536
569
  }
537
570
  update() {
538
- this.ws.send("task-update", { id: this.id, progress: this.progress, logs: this.logs, finished: this.finished, failed: this.failed });
571
+ this.ws.send("task-update", {
572
+ id: this.id,
573
+ progress: this.progress,
574
+ logs: this.logs,
575
+ finished: this.finished,
576
+ failed: this.failed
577
+ });
539
578
  }
540
579
  };
541
580
  var SearchTool = class {
542
581
  fuse;
543
- constructor(items, keys, options = { threshold: 0.3, includeScore: true }) {
582
+ constructor(items, keys, options = {
583
+ threshold: 0.3,
584
+ includeScore: true
585
+ }) {
544
586
  this.fuse = new import_fuse.default(items, {
545
587
  keys,
546
588
  ...options
@@ -559,7 +601,9 @@ var OGIAddonWSListener = class {
559
601
  addon;
560
602
  constructor(ogiAddon, eventEmitter) {
561
603
  if (process.argv[process.argv.length - 1].split("=")[0] !== "--addonSecret") {
562
- throw new Error("No secret provided. This usually happens because the addon was not started by the OGI Addon Server.");
604
+ throw new Error(
605
+ "No secret provided. This usually happens because the addon was not started by the OGI Addon Server."
606
+ );
563
607
  }
564
608
  this.addon = ogiAddon;
565
609
  this.eventEmitter = eventEmitter;
@@ -580,7 +624,9 @@ var OGIAddonWSListener = class {
580
624
  });
581
625
  this.socket.on("error", (error) => {
582
626
  if (error.message.includes("Failed to connect")) {
583
- throw new Error("OGI Addon Server is not running/is unreachable. Please start the server and try again.");
627
+ throw new Error(
628
+ "OGI Addon Server is not running/is unreachable. Please start the server and try again."
629
+ );
584
630
  }
585
631
  console.error("An error occurred:", error);
586
632
  });
@@ -603,15 +649,17 @@ var OGIAddonWSListener = class {
603
649
  if (!socket) {
604
650
  return {};
605
651
  }
606
- socket.send(JSON.stringify({
607
- event: "input-asked",
608
- args: {
609
- config,
610
- name,
611
- description
612
- },
613
- id
614
- }));
652
+ socket.send(
653
+ JSON.stringify({
654
+ event: "input-asked",
655
+ args: {
656
+ config,
657
+ name,
658
+ description
659
+ },
660
+ id
661
+ })
662
+ );
615
663
  return await this.waitForResponseFromServer(id);
616
664
  }
617
665
  registerMessageReceiver() {
@@ -621,20 +669,39 @@ var OGIAddonWSListener = class {
621
669
  case "config-update":
622
670
  const result = this.addon.config.updateConfig(message.args);
623
671
  if (!result[0]) {
624
- this.respondToMessage(message.id, { success: false, error: result[1] });
672
+ this.respondToMessage(message.id, {
673
+ success: false,
674
+ error: result[1]
675
+ });
625
676
  } else {
626
677
  this.respondToMessage(message.id, { success: true });
627
678
  }
628
679
  break;
629
680
  case "search":
630
- let searchResultEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
681
+ let searchResultEvent = new EventResponse(
682
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
683
+ );
631
684
  this.eventEmitter.emit("search", message.args, searchResultEvent);
632
685
  const searchResult = await this.waitForEventToRespond(searchResultEvent);
633
686
  this.respondToMessage(message.id, searchResult.data);
634
687
  break;
635
688
  case "setup":
636
- let setupEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
637
- 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);
689
+ let setupEvent = new EventResponse(
690
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
691
+ );
692
+ this.eventEmitter.emit(
693
+ "setup",
694
+ {
695
+ path: message.args.path,
696
+ appID: message.args.appID,
697
+ storefront: message.args.storefront,
698
+ type: message.args.type,
699
+ name: message.args.name,
700
+ usedRealDebrid: message.args.usedRealDebrid,
701
+ multiPartFiles: message.args.multiPartFiles
702
+ },
703
+ setupEvent
704
+ );
638
705
  const interval = setInterval(() => {
639
706
  if (setupEvent.resolved) {
640
707
  clearInterval(interval);
@@ -651,42 +718,75 @@ var OGIAddonWSListener = class {
651
718
  this.respondToMessage(message.id, setupResult.data);
652
719
  break;
653
720
  case "library-search":
654
- let librarySearchEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
721
+ let librarySearchEvent = new EventResponse(
722
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
723
+ );
655
724
  if (this.eventEmitter.listenerCount("game-details") === 0) {
656
725
  this.respondToMessage(message.id, []);
657
726
  break;
658
727
  }
659
- this.eventEmitter.emit("library-search", message.args, librarySearchEvent);
728
+ this.eventEmitter.emit(
729
+ "library-search",
730
+ message.args,
731
+ librarySearchEvent
732
+ );
660
733
  const librarySearchResult = await this.waitForEventToRespond(librarySearchEvent);
661
734
  this.respondToMessage(message.id, librarySearchResult.data);
662
735
  break;
663
736
  case "game-details":
664
- let gameDetailsEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
737
+ let gameDetailsEvent = new EventResponse(
738
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
739
+ );
665
740
  if (this.eventEmitter.listenerCount("game-details") === 0) {
666
- this.respondToMessage(message.id, { error: "No event listener for game-details" });
741
+ this.respondToMessage(message.id, {
742
+ error: "No event listener for game-details"
743
+ });
667
744
  break;
668
745
  }
669
- this.eventEmitter.emit("game-details", message.args, gameDetailsEvent);
746
+ this.eventEmitter.emit(
747
+ "game-details",
748
+ message.args,
749
+ gameDetailsEvent
750
+ );
670
751
  const gameDetailsResult = await this.waitForEventToRespond(gameDetailsEvent);
671
752
  this.respondToMessage(message.id, gameDetailsResult.data);
672
753
  break;
673
754
  case "request-dl":
674
- let requestDLEvent = new EventResponse((screen, name, description) => this.userInputAsked(screen, name, description, this.socket));
755
+ let requestDLEvent = new EventResponse(
756
+ (screen, name, description) => this.userInputAsked(screen, name, description, this.socket)
757
+ );
675
758
  if (this.eventEmitter.listenerCount("request-dl") === 0) {
676
- this.respondToMessage(message.id, { error: "No event listener for request-dl" });
759
+ this.respondToMessage(message.id, {
760
+ error: "No event listener for request-dl"
761
+ });
677
762
  break;
678
763
  }
679
- this.eventEmitter.emit("request-dl", message.args.appID, message.args.info, requestDLEvent);
764
+ this.eventEmitter.emit(
765
+ "request-dl",
766
+ message.args.appID,
767
+ message.args.info,
768
+ requestDLEvent
769
+ );
680
770
  const requestDLResult = await this.waitForEventToRespond(requestDLEvent);
681
771
  if (requestDLEvent.failed) {
682
- this.respondToMessage(message.id, { statusError: requestDLEvent.failed });
772
+ this.respondToMessage(message.id, {
773
+ statusError: requestDLEvent.failed
774
+ });
683
775
  break;
684
776
  }
685
777
  if (requestDLEvent.data === void 0 || requestDLEvent.data?.downloadType === "request") {
686
- 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.");
778
+ throw new Error(
779
+ "Request DL event did not return a valid result. Please ensure that the event does not resolve with another `request` download type."
780
+ );
687
781
  }
688
782
  this.respondToMessage(message.id, requestDLResult.data);
689
783
  break;
784
+ case "catalog":
785
+ let catalogEvent = new EventResponse();
786
+ this.eventEmitter.emit("catalog", catalogEvent);
787
+ const catalogResult = await this.waitForEventToRespond(catalogEvent);
788
+ this.respondToMessage(message.id, catalogResult.data);
789
+ break;
690
790
  }
691
791
  });
692
792
  }
@@ -714,11 +814,13 @@ var OGIAddonWSListener = class {
714
814
  });
715
815
  }
716
816
  respondToMessage(messageID, response) {
717
- this.socket.send(JSON.stringify({
718
- event: "response",
719
- id: messageID,
720
- args: response
721
- }));
817
+ this.socket.send(
818
+ JSON.stringify({
819
+ event: "response",
820
+ id: messageID,
821
+ args: response
822
+ })
823
+ );
722
824
  console.log("dispatched response to " + messageID);
723
825
  }
724
826
  waitForResponseFromServer(messageID) {
@@ -741,11 +843,13 @@ var OGIAddonWSListener = class {
741
843
  }
742
844
  send(event, args) {
743
845
  const id = Math.random().toString(36).substring(7);
744
- this.socket.send(JSON.stringify({
745
- event,
746
- args,
747
- id
748
- }));
846
+ this.socket.send(
847
+ JSON.stringify({
848
+ event,
849
+ args,
850
+ id
851
+ })
852
+ );
749
853
  return id;
750
854
  }
751
855
  close() {