mobx-tanstack-query-api 0.33.0 → 0.34.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/index.js CHANGED
@@ -6,6 +6,11 @@ import { Query, InfiniteQuery, Mutation, QueryClient } from "mobx-tanstack-query
6
6
  import { getMobxAdministration, lazyObserve } from "yummies/mobx";
7
7
  import { stringify } from "qs";
8
8
  class EndpointQuery extends Query {
9
+ /**
10
+ * Creates `EndpointQuery` instance.
11
+ *
12
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-queries/#constructor)
13
+ */
9
14
  constructor(endpoint, inputQueryClient, queryOptionsInput) {
10
15
  const isQueryOptionsInputFn = typeof queryOptionsInput === "function";
11
16
  const unpackedQueryOptionsInput = isQueryOptionsInputFn ? queryOptionsInput() : queryOptionsInput;
@@ -155,12 +160,27 @@ class EndpointQuery extends Query {
155
160
  this._observableData = _observableData;
156
161
  }
157
162
  _observableData;
163
+ /**
164
+ * Current endpoint params used by this query.
165
+ *
166
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-queries/#params)
167
+ */
158
168
  get params() {
159
169
  return this._observableData.params;
160
170
  }
171
+ /**
172
+ * Last raw HTTP response returned by endpoint.
173
+ *
174
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-queries/#response)
175
+ */
161
176
  get response() {
162
177
  return this._observableData.response;
163
178
  }
179
+ /**
180
+ * Updates query options and optionally params.
181
+ *
182
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-queries/#update)
183
+ */
164
184
  update(updateParams) {
165
185
  if ("params" in updateParams) {
166
186
  const { params, ...options } = updateParams;
@@ -188,12 +208,22 @@ class EndpointQuery extends Query {
188
208
  return super.update(updateParams);
189
209
  }
190
210
  }
211
+ /**
212
+ * Refetches query when params are initialized.
213
+ *
214
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-queries/#refetch)
215
+ */
191
216
  refetch(options) {
192
217
  if (this.params) {
193
218
  return super.refetch(options);
194
219
  }
195
220
  return Promise.resolve(this.queryObserver.getCurrentResult());
196
221
  }
222
+ /**
223
+ * Sets params and starts query execution.
224
+ *
225
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-queries/#start)
226
+ */
197
227
  async start(params) {
198
228
  runInAction(() => {
199
229
  this._observableData.params = params;
@@ -323,6 +353,11 @@ class EndpointInfiniteQuery extends InfiniteQuery {
323
353
  }
324
354
  }
325
355
  class EndpointMutation extends Mutation {
356
+ /**
357
+ * Creates `EndpointMutation` instance.
358
+ *
359
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-mutations/#constructor)
360
+ */
326
361
  constructor(endpoint, inputQueryClient, {
327
362
  transform: transformResponse,
328
363
  invalidateEndpoints,
@@ -385,199 +420,67 @@ class EndpointMutation extends Mutation {
385
420
  return await transformResponse?.(response) ?? response.data;
386
421
  }
387
422
  });
388
- this.endpoint = endpoint;
389
423
  }
390
424
  }
391
- const ContentType = {
392
- Json: "application/json",
393
- FormData: "multipart/form-data",
394
- UrlEncoded: "application/x-www-form-urlencoded",
395
- Text: "text/plain",
396
- Binary: "application/octet-stream"
397
- };
398
- const isHttpResponse = (response, status) => !!response && typeof response === "object" && response instanceof Response && "data" in response && (!status || response.status === status);
399
- const isHttpBadResponse = (response) => {
400
- return isHttpResponse(response) && (!response.ok || !!response.error);
401
- };
402
425
  const emptyStatusCodesSet = /* @__PURE__ */ new Set([204, 205, 304]);
403
- class HttpClient {
404
- config;
405
- fetch;
406
- meta;
407
- baseApiParams;
408
- badResponse;
409
- toQueryString;
410
- constructor(config) {
411
- this.config = config ?? {};
412
- this.badResponse = null;
413
- this.meta = config?.meta ?? null;
414
- this.fetch = config?.fetch ?? ((...fetchParams) => globalThis.fetch(...fetchParams));
415
- this.toQueryString = config?.toQueryString ?? ((query) => stringify(query, config?.queryStringifyOptions));
416
- this.baseApiParams = {
417
- credentials: "same-origin",
418
- headers: {},
419
- redirect: "follow",
420
- referrerPolicy: "no-referrer"
421
- };
422
- this.updateConfig(this.config);
423
- observable.ref(this, "badResponse");
424
- observable.ref(this, "meta");
425
- action(this, "setMeta");
426
- action(this, "setBadResponse");
427
- makeObservable(this);
428
- }
429
- get baseUrl() {
430
- return this.config.baseUrl ?? "";
431
- }
432
- updateConfig(update) {
433
- Object.assign(this.config, update);
434
- if (update.baseApiParams) {
435
- Object.assign(this.baseApiParams, update.baseApiParams);
436
- }
437
- if (update.contentFormatters) {
438
- Object.assign(this.contentFormatters, update.contentFormatters);
439
- }
440
- if (update.fetch) {
441
- this.fetch = update.fetch;
442
- }
443
- }
444
- setMeta = (data) => {
445
- this.meta = data;
446
- };
447
- setBadResponse = (response) => {
448
- this.badResponse = response;
449
- };
450
- contentFormatters = {
451
- "application/json": (input) => input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input,
452
- "text/plain": (input) => input !== null && typeof input !== "string" ? JSON.stringify(input) : input,
453
- "multipart/form-data": (input) => Object.keys(input || {}).reduce((formData, key) => {
454
- const property = input[key];
455
- if (property instanceof Blob) {
456
- formData.append(key, property);
457
- } else if (typeof property === "object" && property !== null) {
458
- formData.append(key, JSON.stringify(property));
459
- } else {
460
- formData.append(key, `${property}`);
461
- }
462
- return formData;
463
- }, new FormData()),
464
- "application/x-www-form-urlencoded": (input) => this.toQueryString(input),
465
- "application/octet-stream": (input) => input
466
- };
467
- mergeRequestParams(params1, params2) {
468
- return {
469
- ...this.baseApiParams,
470
- ...params1,
471
- ...params2,
472
- headers: {
473
- ...this.baseApiParams.headers,
474
- ...params1.headers,
475
- ...params2?.headers
476
- }
477
- };
478
- }
479
- isEmptyResponseBody(response) {
480
- if (emptyStatusCodesSet.has(response.status)) {
426
+ class HttpResponse {
427
+ constructor(originalResponse, request) {
428
+ this.originalResponse = originalResponse;
429
+ this.request = request;
430
+ this.headers = originalResponse.headers;
431
+ this.ok = originalResponse.ok;
432
+ this.body = originalResponse.body;
433
+ this.redirected = originalResponse.redirected;
434
+ this.status = originalResponse.status;
435
+ this.statusText = originalResponse.statusText;
436
+ this.type = originalResponse.type;
437
+ this.url = originalResponse.url;
438
+ this.data = null;
439
+ this.error = null;
440
+ }
441
+ headers;
442
+ ok;
443
+ redirected;
444
+ statusText;
445
+ type;
446
+ url;
447
+ body;
448
+ data;
449
+ error;
450
+ status;
451
+ clone() {
452
+ return new HttpResponse(this.originalResponse.clone(), this.request);
453
+ }
454
+ isEmpty() {
455
+ if (emptyStatusCodesSet.has(this.status)) {
481
456
  return true;
482
457
  }
483
- const contentLength = response.headers.get("content-length");
458
+ const contentLength = this.headers.get("content-length");
484
459
  if (contentLength !== null && contentLength === "0") {
485
460
  return true;
486
461
  }
487
- if (response.body === null) {
462
+ if (this.body === null) {
488
463
  return true;
489
464
  }
490
465
  return false;
491
466
  }
492
- async createResponse(responseFormat = "json", raw, url, params) {
493
- const response = raw;
494
- response.request = { url, params };
495
- response.data = null;
496
- response.error = null;
497
- if (this.isEmptyResponseBody(response)) {
498
- return response;
499
- }
467
+ async resolveBody(responseFormat) {
500
468
  try {
501
- const formatted = await response[responseFormat]();
502
- if (response.ok) {
503
- response.data = formatted;
504
- } else {
505
- response.error = formatted;
506
- }
507
- } catch (error) {
508
- response.error = error;
509
- }
510
- if (!response.ok || response.error) {
511
- this.setBadResponse(response);
512
- }
513
- return response;
514
- }
515
- buildUrl = (params) => {
516
- const baseUrl = params.baseUrl ?? this.baseUrl ?? "";
517
- const path = params.path;
518
- const queryString = params.query && this.toQueryString(params.query);
519
- const query = queryString ? `?${queryString}` : "";
520
- if (this.config.buildUrl) {
521
- return this.config.buildUrl(params, { baseUrl, path, query }, this.meta);
522
- }
523
- const url = baseUrl + path + query;
524
- return url;
525
- };
526
- async request(fullParams, endpoint) {
527
- this.setBadResponse(null);
528
- const { body, contentType, format, ...params } = fullParams;
529
- let requestParams = this.mergeRequestParams(params);
530
- if (this.config.interceptor) {
531
- requestParams = await this.config.interceptor(requestParams, this.meta, endpoint) ?? requestParams;
532
- }
533
- const responseFormat = format || requestParams.format;
534
- const url = this.buildUrl(fullParams);
535
- let headers;
536
- if (requestParams.headers instanceof Headers) {
537
- headers = requestParams.headers;
538
- } else if (Array.isArray(requestParams.headers)) {
539
- headers = new Headers(requestParams.headers);
540
- } else {
541
- headers = new Headers(requestParams.headers);
542
- }
543
- let bodyToSend;
544
- if (contentType) {
545
- if (contentType !== ContentType.FormData && !headers.has("Content-Type")) {
546
- headers.set("Content-Type", contentType);
547
- }
548
- const payloadFormatter = this.contentFormatters[contentType];
549
- if (body == null) {
550
- bodyToSend = null;
551
- } else if (payloadFormatter) {
552
- bodyToSend = payloadFormatter(body);
469
+ const formatted = await this.originalResponse[responseFormat]();
470
+ if (this.ok) {
471
+ this.data = formatted;
553
472
  } else {
554
- bodyToSend = body;
473
+ this.error = formatted;
555
474
  }
556
- }
557
- const fetchUrl = url;
558
- const fetchParams = {
559
- ...requestParams,
560
- headers,
561
- body: bodyToSend
562
- };
563
- let response;
564
- try {
565
- response = await this.fetch(fetchUrl, fetchParams);
566
475
  } catch (error) {
567
- response = error;
568
- }
569
- const httpResponse = await this.createResponse(
570
- responseFormat,
571
- response,
572
- fetchUrl,
573
- fetchParams
574
- );
575
- if (!httpResponse.ok || httpResponse.error) {
576
- throw httpResponse;
476
+ this.error = error;
577
477
  }
578
- return httpResponse;
579
478
  }
580
479
  }
480
+ const isHttpResponse = (response, status) => typeof response === "object" && response instanceof HttpResponse && "data" in response && (!status || response.status === status);
481
+ const isHttpBadResponse = (response) => {
482
+ return isHttpResponse(response) && (!response.ok || !!response.error);
483
+ };
581
484
  class Endpoint {
582
485
  constructor(configuration, queryClient, httpClient) {
583
486
  this.configuration = configuration;
@@ -704,6 +607,11 @@ class Endpoint {
704
607
  }
705
608
  }
706
609
  class EndpointQueryClient extends QueryClient {
610
+ /**
611
+ * Creates `EndpointQueryClient` instance.
612
+ *
613
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-query-client/#constructor)
614
+ */
707
615
  constructor(config) {
708
616
  super({
709
617
  ...config,
@@ -716,6 +624,11 @@ class EndpointQueryClient extends QueryClient {
716
624
  }
717
625
  });
718
626
  }
627
+ /**
628
+ * Invalidates endpoint queries by endpoint metadata filters.
629
+ *
630
+ * [**Documentation**](https://js2me.github.io/mobx-tanstack-query-api/endpoint-query-client/#invalidateendpoints)
631
+ */
719
632
  invalidateEndpoints({
720
633
  group,
721
634
  namespace,
@@ -785,6 +698,166 @@ const applyStringFilter = (filter, value) => {
785
698
  }
786
699
  return values.includes(filter);
787
700
  };
701
+ const ContentType = {
702
+ Json: "application/json",
703
+ FormData: "multipart/form-data",
704
+ UrlEncoded: "application/x-www-form-urlencoded",
705
+ Text: "text/plain",
706
+ Binary: "application/octet-stream"
707
+ };
708
+ class HttpClient {
709
+ config;
710
+ fetch;
711
+ meta;
712
+ baseApiParams;
713
+ badResponse;
714
+ toQueryString;
715
+ constructor(config) {
716
+ this.config = config ?? {};
717
+ this.badResponse = null;
718
+ this.meta = config?.meta ?? null;
719
+ this.fetch = config?.fetch ?? ((...fetchParams) => globalThis.fetch(...fetchParams));
720
+ this.toQueryString = config?.toQueryString ?? ((query) => stringify(query, config?.queryStringifyOptions));
721
+ this.baseApiParams = {
722
+ credentials: "same-origin",
723
+ headers: {},
724
+ redirect: "follow",
725
+ referrerPolicy: "no-referrer"
726
+ };
727
+ this.updateConfig(this.config);
728
+ observable.ref(this, "badResponse");
729
+ observable.ref(this, "meta");
730
+ action(this, "setMeta");
731
+ action(this, "setBadResponse");
732
+ makeObservable(this);
733
+ }
734
+ get baseUrl() {
735
+ return this.config.baseUrl ?? "";
736
+ }
737
+ updateConfig(update) {
738
+ Object.assign(this.config, update);
739
+ if (update.baseApiParams) {
740
+ Object.assign(this.baseApiParams, update.baseApiParams);
741
+ }
742
+ if (update.contentFormatters) {
743
+ Object.assign(this.contentFormatters, update.contentFormatters);
744
+ }
745
+ if (update.fetch) {
746
+ this.fetch = update.fetch;
747
+ }
748
+ }
749
+ setMeta = (data) => {
750
+ this.meta = data;
751
+ };
752
+ setBadResponse = (response) => {
753
+ this.badResponse = response;
754
+ };
755
+ contentFormatters = {
756
+ "application/json": (input) => input !== null && (typeof input === "object" || typeof input === "string") ? JSON.stringify(input) : input,
757
+ "text/plain": (input) => input !== null && typeof input !== "string" ? JSON.stringify(input) : input,
758
+ "multipart/form-data": (input) => Object.keys(input || {}).reduce((formData, key) => {
759
+ const property = input[key];
760
+ if (property instanceof Blob) {
761
+ formData.append(key, property);
762
+ } else if (typeof property === "object" && property !== null) {
763
+ formData.append(key, JSON.stringify(property));
764
+ } else {
765
+ formData.append(key, `${property}`);
766
+ }
767
+ return formData;
768
+ }, new FormData()),
769
+ "application/x-www-form-urlencoded": (input) => this.toQueryString(input),
770
+ "application/octet-stream": (input) => input
771
+ };
772
+ mergeRequestParams(params1, params2) {
773
+ return {
774
+ ...this.baseApiParams,
775
+ ...params1,
776
+ ...params2,
777
+ headers: {
778
+ ...this.baseApiParams.headers,
779
+ ...params1.headers,
780
+ ...params2?.headers
781
+ }
782
+ };
783
+ }
784
+ async createResponse(responseFormat = "json", raw, url, params) {
785
+ const response = new HttpResponse(raw, { url, params });
786
+ if (response.isEmpty()) {
787
+ return response;
788
+ }
789
+ await response.resolveBody(responseFormat);
790
+ if (!response.ok || response.error) {
791
+ this.setBadResponse(response);
792
+ }
793
+ return response;
794
+ }
795
+ buildUrl = (params) => {
796
+ const baseUrl = params.baseUrl ?? this.baseUrl ?? "";
797
+ const path = params.path;
798
+ const queryString = params.query && this.toQueryString(params.query);
799
+ const query = queryString ? `?${queryString}` : "";
800
+ if (this.config.buildUrl) {
801
+ return this.config.buildUrl(params, { baseUrl, path, query }, this.meta);
802
+ }
803
+ const url = baseUrl + path + query;
804
+ return url;
805
+ };
806
+ async request(fullParams, endpoint) {
807
+ this.setBadResponse(null);
808
+ const { body, contentType, format, ...params } = fullParams;
809
+ let requestParams = this.mergeRequestParams(params);
810
+ if (this.config.interceptor) {
811
+ requestParams = await this.config.interceptor(requestParams, this.meta, endpoint) ?? requestParams;
812
+ }
813
+ const responseFormat = format || requestParams.format;
814
+ const url = this.buildUrl(fullParams);
815
+ let headers;
816
+ if (requestParams.headers instanceof Headers) {
817
+ headers = requestParams.headers;
818
+ } else if (Array.isArray(requestParams.headers)) {
819
+ headers = new Headers(requestParams.headers);
820
+ } else {
821
+ headers = new Headers(requestParams.headers);
822
+ }
823
+ let bodyToSend;
824
+ if (contentType) {
825
+ if (contentType !== ContentType.FormData && !headers.has("Content-Type")) {
826
+ headers.set("Content-Type", contentType);
827
+ }
828
+ const payloadFormatter = this.contentFormatters[contentType];
829
+ if (body == null) {
830
+ bodyToSend = null;
831
+ } else if (payloadFormatter) {
832
+ bodyToSend = payloadFormatter(body);
833
+ } else {
834
+ bodyToSend = body;
835
+ }
836
+ }
837
+ const fetchUrl = url;
838
+ const fetchParams = {
839
+ ...requestParams,
840
+ headers,
841
+ body: bodyToSend
842
+ };
843
+ let response;
844
+ try {
845
+ response = await this.fetch(fetchUrl, fetchParams);
846
+ } catch (error) {
847
+ response = error;
848
+ }
849
+ const httpResponse = await this.createResponse(
850
+ responseFormat,
851
+ response,
852
+ fetchUrl,
853
+ fetchParams
854
+ );
855
+ if (!httpResponse.ok || httpResponse.error) {
856
+ throw httpResponse;
857
+ }
858
+ return httpResponse;
859
+ }
860
+ }
788
861
  export {
789
862
  ContentType,
790
863
  Endpoint,
@@ -792,6 +865,7 @@ export {
792
865
  EndpointQuery,
793
866
  EndpointQueryClient,
794
867
  HttpClient,
868
+ HttpResponse,
795
869
  buildOptionsFromParams,
796
870
  emptyStatusCodesSet,
797
871
  getParamsFromContext,