@jax-data-science/api-clients 0.0.1-0 → 0.0.1-a

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/README.md CHANGED
@@ -5,3 +5,17 @@ This library was generated with [Nx](https://nx.dev).
5
5
  ## Running unit tests
6
6
 
7
7
  Run `nx test api-clients` to execute the unit tests.
8
+
9
+
10
+ ## Ontology Service
11
+
12
+ Ontology Service has two implementations JAXOntologyService & OLS Ontology Service. Both converge on the same model that is
13
+ subject to change in releases.
14
+
15
+ To use any particular implementation
16
+
17
+ ```
18
+ providers: [
19
+ {provide: OntologyService, useClass: JAXOntologyService}
20
+ ]
21
+ ```
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, inject, Inject, NgModule } from '@angular/core';
2
+ import { Injectable, inject, InjectionToken, Inject, NgModule } from '@angular/core';
3
3
  import { throwError, map, catchError, Observable, BehaviorSubject, combineLatest, tap } from 'rxjs';
4
4
  import { fetchEventSource } from '@microsoft/fetch-event-source';
5
5
  import * as i1 from '@angular/common/http';
@@ -370,133 +370,134 @@ var WorkflowExecutionStatus;
370
370
  WorkflowExecutionStatus[WorkflowExecutionStatus["TIMED_OUT"] = 7] = "TIMED_OUT";
371
371
  })(WorkflowExecutionStatus || (WorkflowExecutionStatus = {}));
372
372
 
373
- var Ontology;
374
- (function (Ontology) {
375
- Ontology["HP"] = "HP";
376
- Ontology["MONDO"] = "MONDO";
377
- Ontology["MP"] = "MP";
378
- Ontology["CL"] = "CL";
379
- Ontology["MAXO"] = "MAXO";
380
- })(Ontology || (Ontology = {}));
373
+ const ISA_DATA_SERVICE_CONFIG = new InjectionToken('ISA_DATA_SERVICE_CONFIG');
381
374
 
382
- class OntologyService {
383
- httpClient;
384
- config_location = 'https://raw.githubusercontent.com/TheJacksonLaboratory/ontology-service/refs/heads/main/config/ontologies-internal.json';
385
- config;
386
- /**
387
- * Get the configuration file from the source for the backend api service
388
- */
389
- constructor(httpClient) {
390
- this.httpClient = httpClient;
391
- this.httpClient.get(this.config_location).subscribe({
392
- next: (config) => this.config = config,
393
- error: () => {
394
- this.config = [];
395
- }
396
- });
375
+ /**
376
+ * service for interacting with ISA (Investigation-Study-Assay) data model API.
377
+ */
378
+ class ISADataService {
379
+ apiConfig = inject(ISA_DATA_SERVICE_CONFIG);
380
+ apiServiceFactory = inject(ApiBaseServiceFactory);
381
+ apiBaseService;
382
+ constructor() {
383
+ this.apiBaseService = this.apiServiceFactory.create(this.apiConfig.baseUrl);
397
384
  }
398
- /**
399
- * Search for terms in an ontology
400
- * @param query - the search query
401
- * @param limit - the number of results to return
402
- * @param ontology - the ontology to search
403
- */
404
- search(query, limit, ontology) {
405
- return this.httpClient.get(`${this.ontologyBaseResolver(ontology)}/search?q=${query}&limit=${limit}`);
385
+ getApiBaseUrl() {
386
+ return this.apiConfig.baseUrl;
406
387
  }
388
+ // measure operations
407
389
  /**
408
- * Get a term by its ID
409
- * @param id - the term ID
390
+ * Fetches measure series metadata for the given measure series IDs and study IDs.
391
+ *
392
+ * @param measureSeriesIds - measure series identifiers to fetch metadata for. ONLY ONE ID IS SUPPORTED.
393
+ * @param studyIds - ONLY ONE ID IS SUPPORTED. REQUIRED!! WILL BE REMOVED IN THE FUTURE.
394
+ *
395
+ * @return Observable<Response<MeasureSeriesMetadata>> - an observable containing the measure series metadata.
410
396
  */
411
- term(id) {
412
- try {
413
- const url = `${this.ontologyBaseResolver(this.ontologyFromCurie(id))}/${id}`;
414
- return this.httpClient.get(url);
415
- }
416
- catch (error) {
417
- return throwError(error);
397
+ getMeasureSeriesMetadata(measureSeriesIds, studyIds) {
398
+ if (!measureSeriesIds?.length) {
399
+ const errorResponse = {
400
+ code: 'BAD_REQUEST',
401
+ num_code: 400,
402
+ message: 'missing required parameter: measureSeriesIds',
403
+ };
404
+ throw errorResponse;
418
405
  }
406
+ const url = this.buildUrl('/visualization/measures/metadata', {
407
+ measureSeriesIds: measureSeriesIds.join(','),
408
+ studyId: studyIds.join(',')
409
+ });
410
+ return this.apiBaseService.get(url);
419
411
  }
420
412
  /**
421
- * Get the parents of a term
422
- * @param id - the term ID
413
+ * THIS METHOD SHOULD NOT BE USED. PLACEHOLDER FOR FUTURE IMPLEMENTATION ONCE THE API GROWS.
423
414
  */
424
- parents(id) {
425
- try {
426
- const url = `${this.ontologyBaseResolver(this.ontologyFromCurie(id))}/${id}/parents`;
427
- return this.httpClient.get(url);
428
- }
429
- catch (error) {
430
- return throwError(error);
431
- }
415
+ getMeasuresMetadata(measureIds, studyIds) {
416
+ const reqUrl = '';
417
+ return this.apiBaseService.get(reqUrl);
432
418
  }
433
419
  /**
434
- * Get the children of a term
435
- * @param id - the term ID
420
+ * Fetches measure series characteristics for the given measure series IDs and study IDs.
421
+ *
422
+ * @param measureSeriesIds - measure series identifiers to fetch metadata for. ONLY ONE ID IS SUPPORTED.
423
+ * @param studyIds - ONLY ONE ID IS SUPPORTED. REQUIRED!! WILL BE REMOVED IN THE FUTURE.
424
+ *
425
+ * @return Observable<Response<MeasureSeriesMetadata>> - an observable containing the measure series metadata.
436
426
  */
437
- children(id) {
438
- try {
439
- const url = `${this.ontologyBaseResolver(this.ontologyFromCurie(id))}/${id}/children`;
440
- return this.httpClient.get(url);
441
- }
442
- catch (error) {
443
- return throwError(error);
427
+ getMeasureSeriesCharacteristics(measureSeriesIds, studyIds) {
428
+ if (!measureSeriesIds?.length) {
429
+ const errorResponse = {
430
+ code: 'BAD_REQUEST',
431
+ num_code: 400,
432
+ message: 'missing required parameter: measureSeriesIds',
433
+ };
434
+ throw errorResponse;
444
435
  }
436
+ const url = this.buildUrl('/visualization/measures/characteristics', {
437
+ measureSeriesIds: measureSeriesIds.join(','),
438
+ studyIds: studyIds.join(',')
439
+ });
440
+ return this.apiBaseService.get(url);
445
441
  }
442
+ // ASSAYS: to-be-implemented
446
443
  /**
447
- * Get the ancestors of a term
448
- * @param id - the term ID
444
+ * Placeholder for assay operations
445
+ * TODO: Implement assay-related methods
449
446
  */
450
- ancestors(id) {
451
- try {
452
- const url = `${this.ontologyBaseResolver(this.ontologyFromCurie(id))}/${id}/ancestors`;
453
- return this.httpClient.get(url);
454
- }
455
- catch (error) {
456
- return throwError(error);
457
- }
458
- }
447
+ // STUDIES: to-be-implemented
459
448
  /**
460
- * Get the descendants of a term
461
- * @param id - the term ID
449
+ * Placeholder for study operations
450
+ * TODO: Implement study-related methods
462
451
  */
463
- descendants(id) {
464
- try {
465
- const url = `${this.ontologyBaseResolver(this.ontologyFromCurie(id))}/${id}/descendants`;
466
- return this.httpClient.get(url);
467
- }
468
- catch (error) {
469
- return throwError(error);
470
- }
471
- }
452
+ // INVESTIGATIONS: to-be-implemented
472
453
  /**
473
- * Get the ontology from curie
454
+ * Placeholder for investigation operations
455
+ * TODO: Implement investigation-related methods
474
456
  */
475
- ontologyFromCurie(curie) {
476
- return Ontology[curie.split(':')[0]];
477
- }
478
457
  /**
479
- * Get the ontology api base url configuration
480
- **/
481
- ontologyBaseResolver(ontology) {
482
- if (!this.config || this.config.length === 0) {
483
- throw new Error('No ontology configuration found.');
484
- }
485
- const ontology_config = this.config.find((config) => config.prefix.toUpperCase() === ontology);
486
- if (!ontology_config) {
487
- throw new Error('Ontology not found in configuration.');
488
- }
489
- return ontology_config.api.base;
458
+ * Builds the URL for the ISA data service.
459
+ *
460
+ * @param endpoint - the API endpoint path.
461
+ * @param params - optional query parameters as key-value pairs.
462
+ *
463
+ * @return complete URL with query string parameters.
464
+ */
465
+ buildUrl(endpoint, params) {
466
+ const queryParams = new URLSearchParams(params).toString();
467
+ return queryParams ? `${endpoint}?${queryParams}` : endpoint;
490
468
  }
491
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: OntologyService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
492
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: OntologyService, providedIn: 'root' });
469
+ // HEALTH CHECK
470
+ // TO-DO [GIK 05/30/2025]: should be moved outside this service
471
+ getHealthCheck() {
472
+ return this.apiBaseService.get('/monitors/servers/health');
473
+ }
474
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ISADataService, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
475
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ISADataService, providedIn: 'root' });
493
476
  }
494
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: OntologyService, decorators: [{
477
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: ISADataService, decorators: [{
495
478
  type: Injectable,
496
479
  args: [{
497
480
  providedIn: 'root'
498
481
  }]
499
- }], ctorParameters: () => [{ type: i1.HttpClient }] });
482
+ }], ctorParameters: () => [] });
483
+
484
+ /**
485
+ * This module defines the data models for representing the Investigation-Study-Assay (ISA)
486
+ * data model, which is a standard for describing life science experiments and their results.
487
+ *
488
+ * Key Concepts:
489
+ * - Investigation: The overall research project or study.
490
+ * - Study: A specific experimental design within an investigation.
491
+ * - Assay: A specific test or measurement performed on samples within a study.
492
+ *
493
+ * Measures represent the actual data points collected from assay executions, including:
494
+ * - Measure: a single assay results with unique identifier
495
+ * - MeasureSeries: a collection of measures that share common metadata and characteristics
496
+ *
497
+ * Each measure/series contains values, metadata about the experimental conditions,
498
+ * and characteristics that describe sample properties or experimental parameters.
499
+ */
500
+ ;
500
501
 
501
502
  // TODO - move to constants file/library
502
503
  const MUS_CHRS = [
@@ -670,6 +671,272 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImpor
670
671
  }]
671
672
  }] });
672
673
 
674
+ class OntologyService {
675
+ }
676
+
677
+ var Ontology;
678
+ (function (Ontology) {
679
+ Ontology["HP"] = "HP";
680
+ Ontology["MONDO"] = "MONDO";
681
+ Ontology["MP"] = "MP";
682
+ Ontology["CL"] = "CL";
683
+ Ontology["MAXO"] = "MAXO";
684
+ })(Ontology || (Ontology = {}));
685
+
686
+ /**
687
+ * Get the ontology from curie
688
+ */
689
+ function ontologyFromCurie(curie) {
690
+ return Ontology[curie.split(':')[0]];
691
+ }
692
+
693
+ class JaxOntologyService extends OntologyService {
694
+ httpClient;
695
+ config_location = 'https://raw.githubusercontent.com/TheJacksonLaboratory/ontology-service/refs/heads/main/config/ontologies-internal.json';
696
+ config;
697
+ /**
698
+ * Get the configuration file from the source for the backend api service
699
+ */
700
+ constructor(httpClient) {
701
+ super();
702
+ this.httpClient = httpClient;
703
+ this.httpClient.get(this.config_location).subscribe({
704
+ next: (config) => this.config = config,
705
+ error: () => {
706
+ this.config = [];
707
+ }
708
+ });
709
+ }
710
+ /**
711
+ * Search for terms in an ontology
712
+ * @param query - the search query
713
+ * @param limit - the number of results to return
714
+ * @param ontology - the ontology to search
715
+ */
716
+ search(query, limit, ontology) {
717
+ return this.httpClient.get(`${this.ontologyBaseResolver(ontology)}/search?q=${query}&limit=${limit}`);
718
+ }
719
+ /**
720
+ * Get a term by its ID
721
+ * @param id - the term ID
722
+ */
723
+ term(id) {
724
+ try {
725
+ const url = `${this.ontologyBaseResolver(ontologyFromCurie(id))}/${id}`;
726
+ return this.httpClient.get(url);
727
+ }
728
+ catch (error) {
729
+ return throwError(() => error);
730
+ }
731
+ }
732
+ /**
733
+ * Get the parents of a term
734
+ * @param id - the term ID
735
+ */
736
+ parents(id) {
737
+ try {
738
+ const url = `${this.ontologyBaseResolver(ontologyFromCurie(id))}/${id}/parents`;
739
+ return this.httpClient.get(url);
740
+ }
741
+ catch (error) {
742
+ return throwError(() => error);
743
+ }
744
+ }
745
+ /**
746
+ * Get the children of a term
747
+ * @param id - the term ID
748
+ */
749
+ children(id) {
750
+ try {
751
+ const url = `${this.ontologyBaseResolver(ontologyFromCurie(id))}/${id}/children`;
752
+ return this.httpClient.get(url);
753
+ }
754
+ catch (error) {
755
+ return throwError(() => error);
756
+ }
757
+ }
758
+ /**
759
+ * Get the ancestors of a term
760
+ * @param id - the term ID
761
+ */
762
+ ancestors(id) {
763
+ try {
764
+ const url = `${this.ontologyBaseResolver(ontologyFromCurie(id))}/${id}/ancestors`;
765
+ return this.httpClient.get(url);
766
+ }
767
+ catch (error) {
768
+ return throwError(() => error);
769
+ }
770
+ }
771
+ /**
772
+ * Get the descendants of a term
773
+ * @param id - the term ID
774
+ */
775
+ descendants(id) {
776
+ try {
777
+ const url = `${this.ontologyBaseResolver(ontologyFromCurie(id))}/${id}/descendants`;
778
+ return this.httpClient.get(url);
779
+ }
780
+ catch (error) {
781
+ return throwError(() => error);
782
+ }
783
+ }
784
+ /**
785
+ * Get the ontology api base url configuration
786
+ **/
787
+ ontologyBaseResolver(ontology) {
788
+ if (!this.config || this.config.length === 0) {
789
+ throw new Error('No ontology configuration found.');
790
+ }
791
+ const ontology_config = this.config.find((config) => config.prefix.toUpperCase() === ontology);
792
+ if (!ontology_config) {
793
+ throw new Error('Ontology not found in configuration.');
794
+ }
795
+ return ontology_config.api.base;
796
+ }
797
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: JaxOntologyService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
798
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: JaxOntologyService, providedIn: 'root' });
799
+ }
800
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: JaxOntologyService, decorators: [{
801
+ type: Injectable,
802
+ args: [{
803
+ providedIn: 'root'
804
+ }]
805
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
806
+
807
+ // ols-ontology.service.ts
808
+ class OLSOntologyService extends OntologyService {
809
+ httpClient;
810
+ OLS_SEARCH_BASE = 'https://www.ebi.ac.uk/ols4/api/v2/entities';
811
+ OLS_ENTITY_BASE = 'https://www.ebi.ac.uk/ols4/api/v2/ontologies';
812
+ PURL_BASE = 'http://purl.obolibrary.org/obo';
813
+ constructor(httpClient) {
814
+ super();
815
+ this.httpClient = httpClient;
816
+ }
817
+ term(id) {
818
+ const ontology = ontologyFromCurie(id);
819
+ const params = new URLSearchParams;
820
+ params.set('includeObsoleteEntities', 'false');
821
+ return this.httpClient.get(`${this.OLS_ENTITY_BASE}/${ontology.toLowerCase()}/classes/${this.PURL_BASE}/${id.replace(':', '_')}?${params.toString()}`).pipe(map(olsResponse => {
822
+ return {
823
+ object: this.mapOLSTermToOntologyTerm(olsResponse)
824
+ };
825
+ }));
826
+ }
827
+ search(query, limit, ontology) {
828
+ const params = new URLSearchParams;
829
+ params.set('search', query);
830
+ params.set('size', limit.toString());
831
+ params.set('ontologyId', ontology.toLowerCase());
832
+ params.set('includeObsoleteEntities', 'false');
833
+ return this.httpClient.get(`${this.OLS_SEARCH_BASE}?${params.toString()}`).pipe(map(olsResponse => {
834
+ const collectionResponse = {
835
+ data: olsResponse.elements.filter((olsTerm) => olsTerm.definedBy.includes(ontology.toLowerCase())).map(olsTerm => this.mapOLSTermToOntologyTerm(olsTerm)),
836
+ paging: {
837
+ page: olsResponse.page,
838
+ total_pages: olsResponse.totalPages,
839
+ total_items: olsResponse.totalElements
840
+ }
841
+ };
842
+ return collectionResponse;
843
+ }));
844
+ }
845
+ parents(id) {
846
+ const ontology = ontologyFromCurie(id);
847
+ const params = new URLSearchParams;
848
+ params.set('includeObsoleteEntities', 'false');
849
+ return this.httpClient.get(`${this.OLS_ENTITY_BASE}/${ontology.toLowerCase()}/classes/${this.PURL_BASE}/${id.replace(':', '_')}?${params.toString()}`).pipe(map(olsTerm => {
850
+ const data = olsTerm.directParent
851
+ ? olsTerm.directParent
852
+ .map(parent => olsTerm.linkedEntities && olsTerm.linkedEntities[parent]
853
+ ? this.mapOLSTermToOntologyTerm(olsTerm.linkedEntities[parent])
854
+ : "").filter(parent => parent !== "")
855
+ : [];
856
+ return {
857
+ data: data,
858
+ paging: {
859
+ page: 1,
860
+ total_pages: 1,
861
+ total_items: data.length
862
+ }
863
+ };
864
+ }));
865
+ }
866
+ children(id) {
867
+ const ontology = ontologyFromCurie(id);
868
+ const params = new URLSearchParams;
869
+ params.set('includeObsoleteEntities', 'false');
870
+ params.set('size', '100');
871
+ params.set('lang', 'en');
872
+ return this.httpClient.get(`${this.OLS_ENTITY_BASE}/${ontology.toLowerCase()}/classes/${this.PURL_BASE}/${id.replace(':', '_')}/children?${params.toString()}`).pipe(map(childrenResponse => {
873
+ const data = childrenResponse.elements.map(olsTerm => this.mapOLSTermToOntologyTerm(olsTerm));
874
+ return {
875
+ data: data,
876
+ paging: {
877
+ page: childrenResponse.page,
878
+ total_pages: childrenResponse.totalPages,
879
+ total_items: data.length
880
+ }
881
+ };
882
+ }));
883
+ }
884
+ ancestors(id) {
885
+ const ontology = ontologyFromCurie(id);
886
+ const params = new URLSearchParams;
887
+ params.set('includeObsoleteEntities', 'false');
888
+ return this.httpClient.get(`${this.OLS_ENTITY_BASE}/${ontology.toLowerCase()}/classes/${this.PURL_BASE}/${id.replace(':', '_')}?${params.toString()}`).pipe(map(olsTerm => {
889
+ const data = olsTerm.directAncestor
890
+ ? olsTerm.directAncestor
891
+ .map(ancestor => olsTerm.linkedEntities && olsTerm.linkedEntities[ancestor]
892
+ ? this.mapOLSTermToOntologyTerm(olsTerm.linkedEntities[ancestor])
893
+ : "").filter(ancestor => ancestor !== "")
894
+ : [];
895
+ return {
896
+ data: data,
897
+ paging: {
898
+ page: 1,
899
+ total_pages: 1,
900
+ total_items: data.length
901
+ }
902
+ };
903
+ }));
904
+ }
905
+ // finish testing this method
906
+ descendants(id) {
907
+ const ontology = ontologyFromCurie(id);
908
+ const params = new URLSearchParams;
909
+ params.set('includeObsoleteEntities', 'false');
910
+ params.set('size', '100'); // max size for children endpoint
911
+ params.set('lang', 'en');
912
+ return this.httpClient.get(`${this.OLS_ENTITY_BASE}/${ontology.toLowerCase()}/classes/${this.PURL_BASE}/${id.replace(':', '_')}/hierarchicalChildren?${params.toString()}`).pipe(map(childrenResponse => {
913
+ const data = childrenResponse.elements.map(olsTerm => this.mapOLSTermToOntologyTerm(olsTerm));
914
+ return {
915
+ data: data,
916
+ paging: {
917
+ page: childrenResponse.page,
918
+ total_pages: childrenResponse.totalPages,
919
+ total_items: data.length
920
+ }
921
+ };
922
+ }));
923
+ }
924
+ mapOLSTermToOntologyTerm(olsTerm) {
925
+ return {
926
+ id: olsTerm.curie,
927
+ name: olsTerm.label && olsTerm.label.length > 0 ? olsTerm.label[0] : 'No label'
928
+ };
929
+ }
930
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: OLSOntologyService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
931
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: OLSOntologyService, providedIn: 'root' });
932
+ }
933
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.1.5", ngImport: i0, type: OLSOntologyService, decorators: [{
934
+ type: Injectable,
935
+ args: [{
936
+ providedIn: 'root'
937
+ }]
938
+ }], ctorParameters: () => [{ type: i1.HttpClient }] });
939
+
673
940
  class SnpGridService {
674
941
  http;
675
942
  environment;
@@ -907,5 +1174,5 @@ var DatasetStatus;
907
1174
  * Generated bundle index. Do not edit.
908
1175
  */
909
1176
 
910
- export { AsyncTaskService, DatasetStatus, MUS_CHRS, MVarService, MvarClientModule, OntologyService, SnpGridClientModule, SnpGridService, WorkflowExecutionStatus };
1177
+ export { AsyncTaskService, DatasetStatus, ISADataService, ISA_DATA_SERVICE_CONFIG, JaxOntologyService, MUS_CHRS, MVarService, MvarClientModule, OLSOntologyService, OntologyService, SnpGridClientModule, SnpGridService, WorkflowExecutionStatus };
911
1178
  //# sourceMappingURL=jax-data-science-api-clients.mjs.map