@ribbon-studios/js-utils 1.1.1 → 1.2.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/README.md CHANGED
@@ -19,6 +19,13 @@ Collection of generic javascript utilities curated by the Rainbow Cafe~
19
19
  - [`assert`](#assert)
20
20
  - [`assert.defined`](#assertdefined)
21
21
  - [`never`](#never)
22
+ - [Fetch](#fetch)
23
+ - [`rfetch`](#rfetch)
24
+ - [`rfetch.get`](#rfetchget)
25
+ - [`rfetch.put`](#rfetchput)
26
+ - [`rfetch.post`](#rfetchpost)
27
+ - [`rfetch.patch`](#rfetchpatch)
28
+ - [`rfetch.remove`](#rfetchremove)
22
29
 
23
30
  ## Promises
24
31
 
@@ -96,6 +103,94 @@ const promise = never(); // Returns a promise that never resolves
96
103
  const promise = never(Promise.resolve('hello')); // Returns a promise that never resolves
97
104
  ```
98
105
 
106
+ ## Fetch
107
+
108
+ ### `rfetch`
109
+
110
+ Lightweight wrapper around fetch that automatically handles:
111
+
112
+ - Query Params
113
+ - Form Data & JSON bodies
114
+ - JSON Responses (fallsback to text)
115
+ - Type Casting
116
+ - Errors
117
+
118
+ ```tsx
119
+ import { rfetch, type RibbonFetchError } from '@ribbon-studios/js-utils';
120
+
121
+ try {
122
+ const response = await rfetch<MyExpectedResponse>('https://ribbonstudios.com', {
123
+ params: {
124
+ hello: 'world',
125
+ },
126
+ body: {
127
+ hallo: 'welt',
128
+ },
129
+ });
130
+
131
+ console.log(response);
132
+ // => MyExpectedResponse
133
+ } catch (error: RibbonFetchError<MyExpectedErrorResponse>) {
134
+ console.error(error);
135
+ // => { status: number; content: MyExpectedErrorResponse; }
136
+ }
137
+ ```
138
+
139
+ ### `rfetch.get`
140
+
141
+ Shorthand for GET requests.
142
+
143
+ ```tsx
144
+ import { rfetch, type RibbonFetchError } from '@ribbon-studios/js-utils';
145
+
146
+ // Shorthand for GET requests.
147
+ await rfetch.get<MyExpectedResponse>('https://ribbonstudios.com');
148
+ ```
149
+
150
+ ### `rfetch.put`
151
+
152
+ Shorthand for PUT requests.
153
+
154
+ ```tsx
155
+ import { rfetch, type RibbonFetchError } from '@ribbon-studios/js-utils';
156
+
157
+ // Shorthand for PUT requests.
158
+ await rfetch.put<MyExpectedResponse>('https://ribbonstudios.com');
159
+ ```
160
+
161
+ ### `rfetch.post`
162
+
163
+ Shorthand for POST requests.
164
+
165
+ ```tsx
166
+ import { rfetch, type RibbonFetchError } from '@ribbon-studios/js-utils';
167
+
168
+ // Shorthand for POST requests.
169
+ await rfetch.post<MyExpectedResponse>('https://ribbonstudios.com');
170
+ ```
171
+
172
+ ### `rfetch.patch`
173
+
174
+ Shorthand for PATCH requests.
175
+
176
+ ```tsx
177
+ import { rfetch, type RibbonFetchError } from '@ribbon-studios/js-utils';
178
+
179
+ // Shorthand for PATCH requests.
180
+ await rfetch.patch<MyExpectedResponse>('https://ribbonstudios.com');
181
+ ```
182
+
183
+ ### `rfetch.remove`
184
+
185
+ Shorthand for DELETE requests.
186
+
187
+ ```tsx
188
+ import { rfetch, type RibbonFetchError } from '@ribbon-studios/js-utils';
189
+
190
+ // Shorthand for DELETE requests.
191
+ await rfetch.remove<MyExpectedResponse>('https://ribbonstudios.com');
192
+ ```
193
+
99
194
  [_**Want to Contribute?**_](/CONTRIBUTING.md)
100
195
 
101
196
  [npm-version-image]: https://img.shields.io/npm/v/@ribbon-studios/js-utils.svg
@@ -0,0 +1 @@
1
+ export {};
package/dist/index.cjs CHANGED
@@ -32,6 +32,84 @@ async function never(p) {
32
32
  return new Promise(() => {
33
33
  });
34
34
  }
35
+ async function rfetch(url, options) {
36
+ var _a, _b;
37
+ const { params, headers, body, ...internalOptions } = {
38
+ method: "GET",
39
+ headers: {},
40
+ ...options
41
+ };
42
+ const internalURL = url instanceof URL ? url : new URL(url, url.startsWith("/") ? location.origin : void 0);
43
+ if (params) {
44
+ for (const [key, values] of Object.entries(params)) {
45
+ if (Array.isArray(values)) {
46
+ for (const value of values) {
47
+ internalURL.searchParams.append(key, value.toString());
48
+ }
49
+ } else {
50
+ internalURL.searchParams.append(key, values.toString());
51
+ }
52
+ }
53
+ }
54
+ let internalBody = void 0;
55
+ if (body) {
56
+ internalBody = body instanceof FormData ? body : JSON.stringify(body);
57
+ }
58
+ const response = await fetch(internalURL, {
59
+ ...internalOptions,
60
+ headers: {
61
+ "Content-Type": internalBody instanceof FormData ? "application/x-www-form-urlencoded" : "application/json",
62
+ ...headers
63
+ },
64
+ body: internalBody
65
+ });
66
+ const content = ((_b = (_a = response.headers.get("Content-Type")) == null ? void 0 : _a.toLowerCase()) == null ? void 0 : _b.includes("json")) ? await response.json() : await response.text();
67
+ if (response.ok) {
68
+ return content;
69
+ }
70
+ return Promise.reject({
71
+ status: response.status,
72
+ content
73
+ });
74
+ }
75
+ ((rfetch2) => {
76
+ async function get(url, options) {
77
+ return rfetch2(url, {
78
+ ...options,
79
+ method: "GET"
80
+ });
81
+ }
82
+ rfetch2.get = get;
83
+ async function put(url, options) {
84
+ return rfetch2(url, {
85
+ ...options,
86
+ method: "PUT"
87
+ });
88
+ }
89
+ rfetch2.put = put;
90
+ async function post(url, options) {
91
+ return rfetch2(url, {
92
+ ...options,
93
+ method: "POST"
94
+ });
95
+ }
96
+ rfetch2.post = post;
97
+ async function patch(url, options) {
98
+ return rfetch2(url, {
99
+ ...options,
100
+ method: "PATCH"
101
+ });
102
+ }
103
+ rfetch2.patch = patch;
104
+ async function remove(url, options) {
105
+ return rfetch2(url, {
106
+ ...options,
107
+ method: "DELETE"
108
+ });
109
+ }
110
+ rfetch2.remove = remove;
111
+ })(rfetch || (rfetch = {}));
35
112
  exports.assert = assert;
36
113
  exports.delay = delay;
37
114
  exports.never = never;
115
+ exports.rfetch = rfetch;
package/dist/index.d.cts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './promises';
2
+ export * from './rfetch';
package/dist/index.d.ts CHANGED
@@ -1 +1,2 @@
1
1
  export * from './promises';
2
+ export * from './rfetch';
package/dist/index.js CHANGED
@@ -30,8 +30,86 @@ async function never(p) {
30
30
  return new Promise(() => {
31
31
  });
32
32
  }
33
+ async function rfetch(url, options) {
34
+ var _a, _b;
35
+ const { params, headers, body, ...internalOptions } = {
36
+ method: "GET",
37
+ headers: {},
38
+ ...options
39
+ };
40
+ const internalURL = url instanceof URL ? url : new URL(url, url.startsWith("/") ? location.origin : void 0);
41
+ if (params) {
42
+ for (const [key, values] of Object.entries(params)) {
43
+ if (Array.isArray(values)) {
44
+ for (const value of values) {
45
+ internalURL.searchParams.append(key, value.toString());
46
+ }
47
+ } else {
48
+ internalURL.searchParams.append(key, values.toString());
49
+ }
50
+ }
51
+ }
52
+ let internalBody = void 0;
53
+ if (body) {
54
+ internalBody = body instanceof FormData ? body : JSON.stringify(body);
55
+ }
56
+ const response = await fetch(internalURL, {
57
+ ...internalOptions,
58
+ headers: {
59
+ "Content-Type": internalBody instanceof FormData ? "application/x-www-form-urlencoded" : "application/json",
60
+ ...headers
61
+ },
62
+ body: internalBody
63
+ });
64
+ const content = ((_b = (_a = response.headers.get("Content-Type")) == null ? void 0 : _a.toLowerCase()) == null ? void 0 : _b.includes("json")) ? await response.json() : await response.text();
65
+ if (response.ok) {
66
+ return content;
67
+ }
68
+ return Promise.reject({
69
+ status: response.status,
70
+ content
71
+ });
72
+ }
73
+ ((rfetch2) => {
74
+ async function get(url, options) {
75
+ return rfetch2(url, {
76
+ ...options,
77
+ method: "GET"
78
+ });
79
+ }
80
+ rfetch2.get = get;
81
+ async function put(url, options) {
82
+ return rfetch2(url, {
83
+ ...options,
84
+ method: "PUT"
85
+ });
86
+ }
87
+ rfetch2.put = put;
88
+ async function post(url, options) {
89
+ return rfetch2(url, {
90
+ ...options,
91
+ method: "POST"
92
+ });
93
+ }
94
+ rfetch2.post = post;
95
+ async function patch(url, options) {
96
+ return rfetch2(url, {
97
+ ...options,
98
+ method: "PATCH"
99
+ });
100
+ }
101
+ rfetch2.patch = patch;
102
+ async function remove(url, options) {
103
+ return rfetch2(url, {
104
+ ...options,
105
+ method: "DELETE"
106
+ });
107
+ }
108
+ rfetch2.remove = remove;
109
+ })(rfetch || (rfetch = {}));
33
110
  export {
34
111
  assert,
35
112
  delay,
36
- never
113
+ never,
114
+ rfetch
37
115
  };
@@ -0,0 +1,65 @@
1
+ type RibbonFetchParamType = string | number | boolean;
2
+ export type RibbonFetchOptions = {
3
+ method?: 'GET' | 'PUT' | 'POST' | 'PATCH' | 'DELETE';
4
+ params?: Record<string, RibbonFetchParamType | RibbonFetchParamType[]>;
5
+ body?: any;
6
+ headers?: HeadersInit;
7
+ } & Omit<RequestInit, 'body' | 'headers' | 'method'>;
8
+ export type RibbonFetchBasicOptions = Omit<RibbonFetchOptions, 'method' | 'body'>;
9
+ export type RibbonFetchBodyOptions = Omit<RibbonFetchOptions, 'method'>;
10
+ export type RibbonFetchError<R> = {
11
+ status: number;
12
+ content: R;
13
+ };
14
+ /**
15
+ * A lightweight wrapper around fetch to simplify its usage.
16
+ *
17
+ * @param url The url you wish to fetch.
18
+ * @param options The request options.
19
+ * @returns The typed response or an error containing the `status` and the `content`
20
+ */
21
+ export declare function rfetch<T = any>(url: string | URL, options?: RibbonFetchOptions): Promise<T>;
22
+ export declare namespace rfetch {
23
+ /**
24
+ * Shorthand method for a GET request
25
+ *
26
+ * @param url The url you wish to fetch.
27
+ * @param options The request options.
28
+ * @returns The typed response or an error containing the `status` and the `content`
29
+ */
30
+ function get<T>(url: string | URL, options?: RibbonFetchBasicOptions): Promise<T>;
31
+ /**
32
+ * Shorthand method for a PUT request
33
+ *
34
+ * @param url The url you wish to fetch.
35
+ * @param options The request options.
36
+ * @returns The typed response or an error containing the `status` and the `content`
37
+ */
38
+ function put<T>(url: string | URL, options?: RibbonFetchBodyOptions): Promise<T>;
39
+ /**
40
+ * Shorthand method for a POST request
41
+ *
42
+ * @param url The url you wish to fetch.
43
+ * @param options The request options.
44
+ * @returns The typed response or an error containing the `status` and the `content`
45
+ */
46
+ function post<T>(url: string | URL, options?: RibbonFetchBodyOptions): Promise<T>;
47
+ /**
48
+ * Shorthand method for a PATCH request
49
+ *
50
+ * @param url The url you wish to fetch.
51
+ * @param options The request options.
52
+ * @returns The typed response or an error containing the `status` and the `content`
53
+ */
54
+ function patch<T>(url: string | URL, options?: RibbonFetchBodyOptions): Promise<T>;
55
+ /**
56
+ * Shorthand method for a DELETE request
57
+ *
58
+ * @param url The url you wish to fetch.
59
+ * @param options The request options.
60
+ * @returns The typed response or an error containing the `status` and the `content`
61
+ * @note This is named `remove` purely because `delete` is a reserved key
62
+ */
63
+ function remove<T>(url: string | URL, options?: RibbonFetchBodyOptions): Promise<T>;
64
+ }
65
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ribbon-studios/js-utils",
3
- "version": "1.1.1",
3
+ "version": "1.2.0",
4
4
  "description": "Collection of generic javascript utilities curated by the Rainbow Cafe~",
5
5
  "type": "module",
6
6
  "source": "src/*.ts",