floppy-disk 2.9.0 → 2.10.0-beta.1

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/esm/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { hashStoreKey } from './utils';
2
+ export * from './utils/fetcher';
2
3
  export * from './vanilla';
3
4
  export * from './react';
package/esm/index.js CHANGED
@@ -1,3 +1,4 @@
1
1
  export { hashStoreKey } from './utils';
2
+ export * from './utils/fetcher';
2
3
  export * from './vanilla';
3
4
  export * from './react';
@@ -0,0 +1,16 @@
1
+ type FetcherOptions<TResponse = any> = {
2
+ url: string;
3
+ query?: string;
4
+ params?: Record<string, string | number | boolean> | null;
5
+ payload?: any;
6
+ validate?: (response: TResponse) => void | Promise<void>;
7
+ } & RequestInit;
8
+ /**
9
+ * Experimental fetcher - a query/mutation function creator.
10
+ *
11
+ * Can be used for REST or GraphQL.
12
+ *
13
+ * @returns A function to fetch data
14
+ */
15
+ export declare const fetcher: <TResponse = any, TInput extends any[] = any[]>(options: FetcherOptions<TResponse> | ((...args: TInput) => FetcherOptions<TResponse>)) => (...args: TInput) => Promise<TResponse>;
16
+ export {};
@@ -0,0 +1,69 @@
1
+ /* eslint-disable no-throw-literal */
2
+ import { getValueOrComputedValue } from '.';
3
+ const encodeParams = (params) => Object.entries(params)
4
+ .map((kv) => kv.map(encodeURIComponent).join('='))
5
+ .join('&');
6
+ /**
7
+ * Experimental fetcher - a query/mutation function creator.
8
+ *
9
+ * Can be used for REST or GraphQL.
10
+ *
11
+ * @returns A function to fetch data
12
+ */
13
+ export const fetcher = (options) => async (...args) => {
14
+ const { url, query, params, payload, headers, validate, ...rest } = getValueOrComputedValue(options, ...args);
15
+ let autoOptions = {};
16
+ let searchParams = params;
17
+ if (query) {
18
+ // GraphQL
19
+ autoOptions = {
20
+ method: 'POST',
21
+ body: JSON.stringify({ query, variables: payload || args[0] }),
22
+ };
23
+ }
24
+ else if (rest.method && rest.method.toLowerCase() !== 'get') {
25
+ // REST - Mutation
26
+ autoOptions = {
27
+ body: JSON.stringify(payload === undefined ? args[0] : payload),
28
+ };
29
+ }
30
+ else {
31
+ // REST - Query
32
+ if (typeof options === 'object' && params === undefined)
33
+ searchParams = args[0];
34
+ }
35
+ const fetchUrl = searchParams ? [url, encodeParams(searchParams)].join('?') : url;
36
+ const res = await fetch(fetchUrl, {
37
+ headers: { 'Content-Type': 'application/json', ...headers },
38
+ ...autoOptions,
39
+ ...rest,
40
+ });
41
+ const contentType = res.headers.get('content-type');
42
+ if (contentType && contentType.includes('application/json')) {
43
+ const resJson = await res.json().catch(() => undefined);
44
+ if (resJson !== undefined) {
45
+ if (query && resJson.errors) {
46
+ throw { status: res.status, statusText: res.statusText, response: resJson };
47
+ }
48
+ if (res.ok) {
49
+ if (validate) {
50
+ try {
51
+ await validate(resJson);
52
+ }
53
+ catch (err) {
54
+ throw {
55
+ status: res.status,
56
+ statusText: res.statusText,
57
+ response: resJson,
58
+ validationError: err,
59
+ };
60
+ }
61
+ }
62
+ return resJson;
63
+ }
64
+ throw { status: res.status, statusText: res.statusText, response: resJson };
65
+ }
66
+ }
67
+ const resText = await res.text().catch(() => undefined);
68
+ throw { status: res.status, statusText: res.statusText, response: resText };
69
+ };
package/lib/index.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  export { hashStoreKey } from './utils';
2
+ export * from './utils/fetcher';
2
3
  export * from './vanilla';
3
4
  export * from './react';
package/lib/index.js CHANGED
@@ -4,5 +4,6 @@ exports.hashStoreKey = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  var utils_1 = require("./utils");
6
6
  Object.defineProperty(exports, "hashStoreKey", { enumerable: true, get: function () { return utils_1.hashStoreKey; } });
7
+ tslib_1.__exportStar(require("./utils/fetcher"), exports);
7
8
  tslib_1.__exportStar(require("./vanilla"), exports);
8
9
  tslib_1.__exportStar(require("./react"), exports);
@@ -0,0 +1,16 @@
1
+ type FetcherOptions<TResponse = any> = {
2
+ url: string;
3
+ query?: string;
4
+ params?: Record<string, string | number | boolean> | null;
5
+ payload?: any;
6
+ validate?: (response: TResponse) => void | Promise<void>;
7
+ } & RequestInit;
8
+ /**
9
+ * Experimental fetcher - a query/mutation function creator.
10
+ *
11
+ * Can be used for REST or GraphQL.
12
+ *
13
+ * @returns A function to fetch data
14
+ */
15
+ export declare const fetcher: <TResponse = any, TInput extends any[] = any[]>(options: FetcherOptions<TResponse> | ((...args: TInput) => FetcherOptions<TResponse>)) => (...args: TInput) => Promise<TResponse>;
16
+ export {};
@@ -0,0 +1,73 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetcher = void 0;
4
+ /* eslint-disable no-throw-literal */
5
+ const _1 = require(".");
6
+ const encodeParams = (params) => Object.entries(params)
7
+ .map((kv) => kv.map(encodeURIComponent).join('='))
8
+ .join('&');
9
+ /**
10
+ * Experimental fetcher - a query/mutation function creator.
11
+ *
12
+ * Can be used for REST or GraphQL.
13
+ *
14
+ * @returns A function to fetch data
15
+ */
16
+ const fetcher = (options) => async (...args) => {
17
+ const { url, query, params, payload, headers, validate, ...rest } = (0, _1.getValueOrComputedValue)(options, ...args);
18
+ let autoOptions = {};
19
+ let searchParams = params;
20
+ if (query) {
21
+ // GraphQL
22
+ autoOptions = {
23
+ method: 'POST',
24
+ body: JSON.stringify({ query, variables: payload || args[0] }),
25
+ };
26
+ }
27
+ else if (rest.method && rest.method.toLowerCase() !== 'get') {
28
+ // REST - Mutation
29
+ autoOptions = {
30
+ body: JSON.stringify(payload === undefined ? args[0] : payload),
31
+ };
32
+ }
33
+ else {
34
+ // REST - Query
35
+ if (typeof options === 'object' && params === undefined)
36
+ searchParams = args[0];
37
+ }
38
+ const fetchUrl = searchParams ? [url, encodeParams(searchParams)].join('?') : url;
39
+ const res = await fetch(fetchUrl, {
40
+ headers: { 'Content-Type': 'application/json', ...headers },
41
+ ...autoOptions,
42
+ ...rest,
43
+ });
44
+ const contentType = res.headers.get('content-type');
45
+ if (contentType && contentType.includes('application/json')) {
46
+ const resJson = await res.json().catch(() => undefined);
47
+ if (resJson !== undefined) {
48
+ if (query && resJson.errors) {
49
+ throw { status: res.status, statusText: res.statusText, response: resJson };
50
+ }
51
+ if (res.ok) {
52
+ if (validate) {
53
+ try {
54
+ await validate(resJson);
55
+ }
56
+ catch (err) {
57
+ throw {
58
+ status: res.status,
59
+ statusText: res.statusText,
60
+ response: resJson,
61
+ validationError: err,
62
+ };
63
+ }
64
+ }
65
+ return resJson;
66
+ }
67
+ throw { status: res.status, statusText: res.statusText, response: resJson };
68
+ }
69
+ }
70
+ const resText = await res.text().catch(() => undefined);
71
+ throw { status: res.status, statusText: res.statusText, response: resText };
72
+ };
73
+ exports.fetcher = fetcher;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "floppy-disk",
3
- "version": "2.9.0",
3
+ "version": "2.10.0-beta.1",
4
4
  "description": "FloppyDisk - lightweight, simple, and powerful state management library",
5
5
  "keywords": [
6
6
  "state",