@data-client/rest 0.1.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.
Files changed (158) hide show
  1. package/LICENSE +201 -0
  2. package/README.md +110 -0
  3. package/dist/index.js +561 -0
  4. package/dist/index.umd.min.js +1 -0
  5. package/dist/next.js +520 -0
  6. package/dist/package.json +1 -0
  7. package/legacy/NetworkError.js +13 -0
  8. package/legacy/OptionsToFunction.js +2 -0
  9. package/legacy/RestEndpoint.js +225 -0
  10. package/legacy/RestEndpointTypeHelp.js +2 -0
  11. package/legacy/RestHelpers.js +33 -0
  12. package/legacy/createResource.js +88 -0
  13. package/legacy/extractCollection.js +14 -0
  14. package/legacy/getArrayPath.js +19 -0
  15. package/legacy/hookifyResource.js +24 -0
  16. package/legacy/index.js +10 -0
  17. package/legacy/mapCollection.js +14 -0
  18. package/legacy/next/OptionsToFunction.js +2 -0
  19. package/legacy/next/RestEndpoint.js +225 -0
  20. package/legacy/next/createResource.js +86 -0
  21. package/legacy/next/index.js +4 -0
  22. package/legacy/next/resourceTypes.js +2 -0
  23. package/legacy/paginatedCollections.js +29 -0
  24. package/legacy/paginationUpdate.js +36 -0
  25. package/legacy/paramsToString.js +6 -0
  26. package/legacy/paramsToString.native.js +9 -0
  27. package/legacy/pathTypes.js +2 -0
  28. package/legacy/test-fixtures.js +111 -0
  29. package/legacy/utiltypes.js +2 -0
  30. package/lib/NetworkError.d.ts +11 -0
  31. package/lib/NetworkError.d.ts.map +1 -0
  32. package/lib/NetworkError.js +13 -0
  33. package/lib/OptionsToFunction.d.ts +7 -0
  34. package/lib/OptionsToFunction.d.ts.map +1 -0
  35. package/lib/OptionsToFunction.js +2 -0
  36. package/lib/RestEndpoint.d.ts +548 -0
  37. package/lib/RestEndpoint.js +229 -0
  38. package/lib/RestEndpointTypeHelp.d.ts +10 -0
  39. package/lib/RestEndpointTypeHelp.d.ts.map +1 -0
  40. package/lib/RestEndpointTypeHelp.js +2 -0
  41. package/lib/RestHelpers.d.ts +7 -0
  42. package/lib/RestHelpers.d.ts.map +1 -0
  43. package/lib/RestHelpers.js +33 -0
  44. package/lib/createResource.d.ts +66 -0
  45. package/lib/createResource.d.ts.map +1 -0
  46. package/lib/createResource.js +104 -0
  47. package/lib/extractCollection.d.ts +11 -0
  48. package/lib/extractCollection.d.ts.map +1 -0
  49. package/lib/extractCollection.js +16 -0
  50. package/lib/getArrayPath.d.ts +3 -0
  51. package/lib/getArrayPath.d.ts.map +1 -0
  52. package/lib/getArrayPath.js +19 -0
  53. package/lib/hookifyResource.d.ts +14 -0
  54. package/lib/hookifyResource.d.ts.map +1 -0
  55. package/lib/hookifyResource.js +24 -0
  56. package/lib/index.d.ts +12 -0
  57. package/lib/index.d.ts.map +1 -0
  58. package/lib/index.js +10 -0
  59. package/lib/mapCollection.d.ts +16 -0
  60. package/lib/mapCollection.d.ts.map +1 -0
  61. package/lib/mapCollection.js +16 -0
  62. package/lib/next/OptionsToFunction.d.ts +7 -0
  63. package/lib/next/OptionsToFunction.d.ts.map +1 -0
  64. package/lib/next/OptionsToFunction.js +2 -0
  65. package/lib/next/RestEndpoint.d.ts +542 -0
  66. package/lib/next/RestEndpoint.js +229 -0
  67. package/lib/next/createResource.d.ts +86 -0
  68. package/lib/next/createResource.d.ts.map +1 -0
  69. package/lib/next/createResource.js +100 -0
  70. package/lib/next/index.d.ts +6 -0
  71. package/lib/next/index.d.ts.map +1 -0
  72. package/lib/next/index.js +4 -0
  73. package/lib/next/resourceTypes.d.ts +31 -0
  74. package/lib/next/resourceTypes.d.ts.map +1 -0
  75. package/lib/next/resourceTypes.js +2 -0
  76. package/lib/paginatedCollections.d.ts +3 -0
  77. package/lib/paginatedCollections.d.ts.map +1 -0
  78. package/lib/paginatedCollections.js +29 -0
  79. package/lib/paginationUpdate.d.ts +8 -0
  80. package/lib/paginationUpdate.d.ts.map +1 -0
  81. package/lib/paginationUpdate.js +40 -0
  82. package/lib/paramsToString.d.ts +2 -0
  83. package/lib/paramsToString.d.ts.map +1 -0
  84. package/lib/paramsToString.js +6 -0
  85. package/lib/paramsToString.native.d.ts +2 -0
  86. package/lib/paramsToString.native.d.ts.map +1 -0
  87. package/lib/paramsToString.native.js +9 -0
  88. package/lib/pathTypes.d.ts +20 -0
  89. package/lib/pathTypes.d.ts.map +1 -0
  90. package/lib/pathTypes.js +2 -0
  91. package/lib/test-fixtures.d.ts +141 -0
  92. package/lib/test-fixtures.d.ts.map +1 -0
  93. package/lib/test-fixtures.js +111 -0
  94. package/lib/utiltypes.d.ts +21 -0
  95. package/lib/utiltypes.d.ts.map +1 -0
  96. package/lib/utiltypes.js +2 -0
  97. package/node.mjs +1 -0
  98. package/package.json +121 -0
  99. package/src/NetworkError.ts +17 -0
  100. package/src/OptionsToFunction.ts +42 -0
  101. package/src/RestEndpoint.d.ts +548 -0
  102. package/src/RestEndpoint.js +262 -0
  103. package/src/RestEndpointTypeHelp.ts +20 -0
  104. package/src/RestHelpers.ts +48 -0
  105. package/src/__tests__/Resource.test.ts +317 -0
  106. package/src/__tests__/RestEndpoint.ts +1304 -0
  107. package/src/__tests__/__snapshots__/RestEndpoint.ts.snap +18 -0
  108. package/src/__tests__/__snapshots__/createResource.test.ts.snap +5 -0
  109. package/src/__tests__/createResource.test.ts +583 -0
  110. package/src/__tests__/getArrayPath.test.ts +30 -0
  111. package/src/__tests__/hookifyResource.ts +197 -0
  112. package/src/__tests__/types.test.ts +309 -0
  113. package/src/createResource.ts +172 -0
  114. package/src/extractCollection.ts +34 -0
  115. package/src/getArrayPath.ts +20 -0
  116. package/src/hookifyResource.ts +36 -0
  117. package/src/index.ts +42 -0
  118. package/src/mapCollection.ts +54 -0
  119. package/src/next/OptionsToFunction.ts +41 -0
  120. package/src/next/RestEndpoint.d.ts +542 -0
  121. package/src/next/RestEndpoint.js +262 -0
  122. package/src/next/__tests__/RestEndpoint.ts +1333 -0
  123. package/src/next/__tests__/__snapshots__/RestEndpoint.ts.snap +18 -0
  124. package/src/next/__tests__/types.test.ts +429 -0
  125. package/src/next/createResource.ts +194 -0
  126. package/src/next/index.ts +5 -0
  127. package/src/next/resourceTypes.ts +32 -0
  128. package/src/package.json +1 -0
  129. package/src/paginatedCollections.ts +32 -0
  130. package/src/paginationUpdate.ts +49 -0
  131. package/src/paramsToString.native.ts +10 -0
  132. package/src/paramsToString.ts +7 -0
  133. package/src/pathTypes.ts +58 -0
  134. package/src/test-fixtures.ts +128 -0
  135. package/src/utiltypes.ts +25 -0
  136. package/ts4.0/NetworkError.d.ts +11 -0
  137. package/ts4.0/OptionsToFunction.d.ts +16 -0
  138. package/ts4.0/RestEndpoint.d.ts +240 -0
  139. package/ts4.0/RestEndpointTypeHelp.d.ts +10 -0
  140. package/ts4.0/RestHelpers.d.ts +7 -0
  141. package/ts4.0/createResource.d.ts +66 -0
  142. package/ts4.0/extractCollection.d.ts +11 -0
  143. package/ts4.0/getArrayPath.d.ts +3 -0
  144. package/ts4.0/hookifyResource.d.ts +19 -0
  145. package/ts4.0/index.d.ts +12 -0
  146. package/ts4.0/mapCollection.d.ts +16 -0
  147. package/ts4.0/next/OptionsToFunction.d.ts +16 -0
  148. package/ts4.0/next/RestEndpoint.d.ts +226 -0
  149. package/ts4.0/next/createResource.d.ts +94 -0
  150. package/ts4.0/next/index.d.ts +6 -0
  151. package/ts4.0/next/resourceTypes.d.ts +31 -0
  152. package/ts4.0/paginatedCollections.d.ts +3 -0
  153. package/ts4.0/paginationUpdate.d.ts +10 -0
  154. package/ts4.0/paramsToString.d.ts +2 -0
  155. package/ts4.0/paramsToString.native.d.ts +2 -0
  156. package/ts4.0/pathTypes.d.ts +20 -0
  157. package/ts4.0/test-fixtures.d.ts +141 -0
  158. package/ts4.0/utiltypes.d.ts +5 -0
package/dist/next.js ADDED
@@ -0,0 +1,520 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, '__esModule', { value: true });
4
+
5
+ var endpoint = require('@data-client/endpoint');
6
+ var pathToRegexp = require('path-to-regexp');
7
+
8
+ function unwrapExports (x) {
9
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
10
+ }
11
+
12
+ function createCommonjsModule(fn, module) {
13
+ return module = { exports: {} }, fn(module, module.exports), module.exports;
14
+ }
15
+
16
+ var classPrivateFieldLooseBase = createCommonjsModule(function (module) {
17
+ function _classPrivateFieldBase(receiver, privateKey) {
18
+ if (!Object.prototype.hasOwnProperty.call(receiver, privateKey)) {
19
+ throw new TypeError("attempted to use private field on non-instance");
20
+ }
21
+ return receiver;
22
+ }
23
+ module.exports = _classPrivateFieldBase, module.exports.__esModule = true, module.exports["default"] = module.exports;
24
+ });
25
+
26
+ var _classPrivateFieldLooseBase = unwrapExports(classPrivateFieldLooseBase);
27
+
28
+ var classPrivateFieldLooseKey = createCommonjsModule(function (module) {
29
+ var id = 0;
30
+ function _classPrivateFieldKey(name) {
31
+ return "__private_" + id++ + "_" + name;
32
+ }
33
+ module.exports = _classPrivateFieldKey, module.exports.__esModule = true, module.exports["default"] = module.exports;
34
+ });
35
+
36
+ var _classPrivateFieldLooseKey = unwrapExports(classPrivateFieldLooseKey);
37
+
38
+ function extractCollection(s, mapper) {
39
+ if (typeof s !== 'object' || s === undefined || Array.isArray(s)) return;
40
+ if (s instanceof endpoint.schema.Collection) {
41
+ return mapper(s);
42
+ }
43
+ const objCopy = {
44
+ ...(s instanceof endpoint.schema.Object ? s.schema : s)
45
+ };
46
+ for (const k in objCopy) {
47
+ if (!objCopy[k]) continue;
48
+ const collection = extractCollection(objCopy[k], mapper);
49
+ if (collection) return collection;
50
+ }
51
+ }
52
+
53
+ function mapCollection(s, mapper) {
54
+ if (typeof s !== 'object' || s === undefined) return s;
55
+ if (s instanceof endpoint.schema.Collection) {
56
+ return mapper(s);
57
+ }
58
+ const objCopy = {
59
+ ...(s instanceof endpoint.schema.Object ? s.schema : s)
60
+ };
61
+ for (const k in objCopy) {
62
+ if (!objCopy[k]) continue;
63
+ objCopy[k] = mapCollection(objCopy[k], mapper);
64
+ }
65
+ return objCopy;
66
+ }
67
+
68
+ /** An error with a Rest Endpoint fetch
69
+ *
70
+ * @see https://resthooks.io/rest/api/NetworkError
71
+ */
72
+ class NetworkError extends Error {
73
+ constructor(response) {
74
+ super(response.statusText || `Network response not 'ok': ${response.status}`);
75
+ this.name = 'NetworkError';
76
+ this.status = response.status;
77
+ this.response = response;
78
+ }
79
+ }
80
+
81
+ function paginatedMerge(existing, incoming) {
82
+ const existingSet = new Set(existing);
83
+ const mergedList = [...existing];
84
+ for (const pk of incoming) {
85
+ if (!existingSet.has(pk)) mergedList.push(pk);
86
+ }
87
+ return mergedList;
88
+ }
89
+ const paginatedFilter = removeCursor => (...args) => {
90
+ const noCursorArgs = removeCursor(...args);
91
+ return collectionKey => {
92
+ var _noCursorArgs$;
93
+ return shallowEqual(collectionKey, (_noCursorArgs$ = noCursorArgs[0]) != null ? _noCursorArgs$ : {});
94
+ };
95
+ };
96
+ function shallowEqual(object1, object2) {
97
+ const keys1 = Object.keys(object1);
98
+ const keys2 = Object.keys(object2);
99
+ if (keys1.length !== keys2.length) {
100
+ return false;
101
+ }
102
+ for (const key of keys1) {
103
+ if (object1[key] != object2[key]) {
104
+ return false;
105
+ }
106
+ }
107
+ return true;
108
+ }
109
+
110
+ function getArrayPath(s) {
111
+ if (typeof s !== 'object') return false;
112
+ if (s === undefined || s instanceof endpoint.schema.Array || Array.isArray(s)) {
113
+ return [];
114
+ }
115
+ const o = s instanceof endpoint.schema.Object ? s.schema : s;
116
+ for (const k in o) {
117
+ if (!o[k]) continue;
118
+ const path = getArrayPath(o[k]);
119
+ if (path !== false) {
120
+ // mutation is ok because there is only one path
121
+ path.unshift(k);
122
+ return path;
123
+ }
124
+ }
125
+ return false;
126
+ }
127
+
128
+ function paginationUpdate(endpoint, removeCursor) {
129
+ // infer path from schema. if schema is undefined assume array is top level
130
+ const path = getArrayPath(endpoint.schema);
131
+ if (path === false) throw new Error('schema has no array');
132
+ return (newPage, ...args) => ({
133
+ [endpoint.key(...removeCursor(...args))]: existing => {
134
+ const existingList = getIn(existing, path);
135
+ // using set so our lookups are O(1) in case this is large
136
+ const existingSet = new Set(existingList);
137
+ const addedList = getIn(newPage, path).filter(pk => !existingSet.has(pk));
138
+ const mergedResults = [...existingList, ...addedList];
139
+ return setIn(newPage, path, mergedResults);
140
+ }
141
+ });
142
+ }
143
+ const getIn = (results, path) => {
144
+ let cur = results;
145
+ for (const p of path) {
146
+ if (!cur) return [];
147
+ cur = cur[p];
148
+ }
149
+ return cur || [];
150
+ };
151
+ const setIn = (results, path, values) => {
152
+ if (path.length === 0) return values;
153
+ const newResults = {
154
+ ...results
155
+ };
156
+ let cur = newResults;
157
+ for (let i = 0; i < path.length - 1; i++) {
158
+ const p = path[i];
159
+ cur = cur[p] = {
160
+ ...cur[p]
161
+ };
162
+ }
163
+ cur[path[path.length - 1]] = values;
164
+ return newResults;
165
+ };
166
+
167
+ function paramsToString(searchParams) {
168
+ const params = new URLSearchParams(searchParams);
169
+ params.sort();
170
+ return params.toString();
171
+ }
172
+
173
+ const urlBaseCache = Object.create(null);
174
+ function getUrlBase(path) {
175
+ if (!(path in urlBaseCache)) {
176
+ urlBaseCache[path] = pathToRegexp.compile(path, {
177
+ encode: encodeURIComponent,
178
+ validate: false
179
+ });
180
+ }
181
+ return urlBaseCache[path];
182
+ }
183
+ const urlTokensCache = Object.create(null);
184
+ function getUrlTokens(path) {
185
+ if (!(path in urlTokensCache)) {
186
+ urlTokensCache[path] = new Set(pathToRegexp.parse(path).map(t => typeof t === 'string' ? t : `${t['name']}`));
187
+ }
188
+ return urlTokensCache[path];
189
+ }
190
+ const proto = Object.prototype;
191
+ const gpo = Object.getPrototypeOf;
192
+ function isPojo(obj) {
193
+ if (obj === null || typeof obj !== 'object') {
194
+ return false;
195
+ }
196
+ return gpo(obj) === proto;
197
+ }
198
+ function shortenPath(path) {
199
+ // this is for when not specifying a specific item like create/list
200
+ let shortUrlRoot = path.substring(0, path.lastIndexOf(':'));
201
+ if (shortUrlRoot[shortUrlRoot.length - 1] === '/') shortUrlRoot = shortUrlRoot.substring(0, shortUrlRoot.length - 1);
202
+ return shortUrlRoot;
203
+ }
204
+
205
+ /** Simplifies endpoint definitions that follow REST patterns
206
+ *
207
+ * @see https://resthooks.io/rest/api/RestEndpoint
208
+ */
209
+ var _hasBody = /*#__PURE__*/_classPrivateFieldLooseKey("hasBody");
210
+ class RestEndpoint extends endpoint.Endpoint {
211
+ constructor(options) {
212
+ var _options$fetch;
213
+ super((_options$fetch = options.fetch) != null ? _options$fetch : async function (...args) {
214
+ const urlParams = _classPrivateFieldLooseBase(this, _hasBody)[_hasBody] && args.length < 2 ? {} : args[0] || {};
215
+ const body = _classPrivateFieldLooseBase(this, _hasBody)[_hasBody] ? args[args.length - 1] : undefined;
216
+ return this.fetchResponse(this.url(urlParams), await this.getRequestInit(body)).then(response => this.parseResponse(response)).then(res => this.process(res, ...args));
217
+ }, options);
218
+ // we want to use the prototype chain here
219
+ Object.defineProperty(this, _hasBody, {
220
+ writable: true,
221
+ value: void 0
222
+ });
223
+ if (!('sideEffect' in this) || 'method' in options && !('sideEffect' in options)) {
224
+ this.sideEffect = options.method === 'GET' || options.method === undefined ? undefined : true;
225
+ }
226
+ if (this.method === undefined) {
227
+ this.method = this.sideEffect ? 'POST' : 'GET';
228
+ }
229
+ if (this.urlPrefix === undefined) {
230
+ this.urlPrefix = '';
231
+ }
232
+ _classPrivateFieldLooseBase(this, _hasBody)[_hasBody] = (!('body' in this) || this.body !== undefined) && !['GET', 'DELETE'].includes(this.method);
233
+ Object.defineProperty(this, 'name', {
234
+ get() {
235
+ // using 'in' to ensure inheritance lookup
236
+ if ('__name' in this) return this.__name;
237
+ return this.urlPrefix + this.path;
238
+ }
239
+ });
240
+ }
241
+ key(...args) {
242
+ return `${this.method} ${this.url(_classPrivateFieldLooseBase(this, _hasBody)[_hasBody] && args.length < 2 ? {} : args[0] || {})}`;
243
+ }
244
+
245
+ /** Get the url */
246
+ url(urlParams = {}) {
247
+ const urlBase = getUrlBase(this.path)(urlParams);
248
+ const tokens = getUrlTokens(this.path);
249
+ const searchParams = {};
250
+ Object.keys(urlParams).forEach(k => {
251
+ if (!tokens.has(k)) {
252
+ searchParams[k] = urlParams[k];
253
+ }
254
+ });
255
+ if (Object.keys(searchParams).length) {
256
+ return `${this.urlPrefix}${urlBase}?${paramsToString(searchParams)}`;
257
+ }
258
+ return `${this.urlPrefix}${urlBase}`;
259
+ }
260
+ getHeaders(headers) {
261
+ return headers;
262
+ }
263
+
264
+ /** Init options for fetch - run at fetch */
265
+ async getRequestInit(body) {
266
+ const bodyIsPojo = isPojo(body);
267
+ if (bodyIsPojo) {
268
+ body = JSON.stringify(body);
269
+ }
270
+ const init = {
271
+ ...this.requestInit,
272
+ method: this.method,
273
+ signal: this.signal,
274
+ body
275
+ };
276
+ if (!body || bodyIsPojo) {
277
+ init.headers = {
278
+ // default to application/json but allow user explicit overrides
279
+ 'Content-Type': 'application/json',
280
+ ...init.headers
281
+ };
282
+ }
283
+ init.headers = await this.getHeaders(init.headers);
284
+ return init;
285
+ }
286
+
287
+ /** Perform network request and resolve with HTTP Response */
288
+ fetchResponse(input, init) {
289
+ return fetch(input, init).then(response => {
290
+ if (!response.ok) {
291
+ throw new NetworkError(response);
292
+ }
293
+ return response;
294
+ }).catch(error => {
295
+ // ensure CORS, network down, and parse errors are still caught by NetworkErrorBoundary
296
+ if (error instanceof TypeError) {
297
+ error.status = 500;
298
+ }
299
+ throw error;
300
+ });
301
+ }
302
+ parseResponse(response) {
303
+ var _response$headers$get;
304
+ // this should not have any content to read
305
+ if (response.status === 204) return Promise.resolve(null);
306
+ if (!((_response$headers$get = response.headers.get('content-type')) != null && _response$headers$get.includes('json'))) {
307
+ return response.text().then(text => {
308
+ // string or 'not set' schema, are valid
309
+ // when overriding process they might handle other cases, so we don't want to block on our logic
310
+ if (['string', 'undefined'].includes(typeof this.schema) || this.schema === null || this.process !== RestEndpoint.prototype.process) return text;
311
+ const error = new NetworkError(response);
312
+ error.status = 404;
313
+ error.message = `Unexpected text response for schema ${this.schema}`;
314
+ // custom dev-only messages for more detailed cause
315
+ /* istanbul ignore else */
316
+ if (process.env.NODE_ENV !== 'production') {
317
+ var _response$headers$get2;
318
+ if (!((_response$headers$get2 = response.headers.get('content-type')) != null && _response$headers$get2.includes('html') || text.startsWith('<!doctype html>'))) {
319
+ if (tryParse(text) !== undefined) {
320
+ error.message = `"content-type" header does not include "json", but JSON response found.
321
+ See https://www.rfc-editor.org/rfc/rfc4627 for information on JSON responses
322
+
323
+ Using parsed JSON.
324
+ If text content was expected see https://resthooks.io/rest/api/RestEndpoint#parseResponse`;
325
+ }
326
+ } else {
327
+ error.message = `Unexpected html response for schema ${this.schema}
328
+ This likely means no API endpoint was configured for this request, resulting in an HTML fallback.
329
+
330
+ Response (first 300 characters): ${text.substring(0, 300)}`;
331
+ }
332
+ }
333
+ throw error;
334
+ });
335
+ }
336
+ return response.json().catch(error => {
337
+ error.status = 400;
338
+ throw error;
339
+ });
340
+ }
341
+ process(value) {
342
+ return value;
343
+ }
344
+ errorPolicy(error) {
345
+ return error.status >= 500 ? 'soft' : undefined;
346
+ }
347
+ get pathRegex() {
348
+ return pathToRegexp.pathToRegexp(this.path);
349
+ }
350
+ testKey(key) {
351
+ const prefix = this.method + ' ' + this.urlPrefix;
352
+ if (!key.startsWith(prefix)) return false;
353
+ let lastQuestion = key.lastIndexOf('?');
354
+ if (lastQuestion === -1) lastQuestion = undefined;
355
+ return this.pathRegex.test(key.substring(prefix.length, lastQuestion));
356
+ }
357
+ extend(options) {
358
+ // make a constructor/prototype based off this
359
+ // extend from it and init with options sent
360
+ class E extends this.constructor {}
361
+ Object.assign(E.prototype, this);
362
+ const instance = new E(
363
+ // fetch get overridden by function prototype, so we must set it explicitly every time
364
+ {
365
+ fetch: this.fetch,
366
+ ...options
367
+ });
368
+ return instance;
369
+ }
370
+ paginated(removeCursor) {
371
+ if (typeof removeCursor === 'string') {
372
+ const fieldName = removeCursor;
373
+ removeCursor = ({
374
+ ...params
375
+ }) => {
376
+ delete params[fieldName];
377
+ return [params];
378
+ };
379
+ }
380
+ let found = false;
381
+ const createPaginatedSchema = collection => {
382
+ found = true;
383
+ return collection.addWith(paginatedMerge, paginatedFilter(removeCursor));
384
+ };
385
+ const newSchema = mapCollection(this.schema, createPaginatedSchema);
386
+ if (found) {
387
+ return this.extend({
388
+ schema: newSchema
389
+ });
390
+ }
391
+ return this.extend({
392
+ update: paginationUpdate(this, removeCursor)
393
+ });
394
+ }
395
+ get push() {
396
+ return this.extend({
397
+ method: 'POST',
398
+ schema: extractCollection(this.schema, s => s.push)
399
+ });
400
+ }
401
+ get unshift() {
402
+ return this.extend({
403
+ method: 'POST',
404
+ schema: extractCollection(this.schema, s => s.unshift)
405
+ });
406
+ }
407
+ get assign() {
408
+ return this.extend({
409
+ method: 'POST',
410
+ schema: extractCollection(this.schema, s => s.assign)
411
+ });
412
+ }
413
+ }
414
+ const tryParse = input => {
415
+ try {
416
+ return JSON.parse(input);
417
+ } catch (e) {
418
+ return undefined;
419
+ }
420
+ };
421
+
422
+ const {
423
+ Invalidate,
424
+ Collection
425
+ } = endpoint.schema;
426
+
427
+ /** Creates collection of Endpoints for common operations on a given data/schema.
428
+ *
429
+ * @see https://resthooks.io/rest/api/createResource
430
+ */
431
+ function createResource({
432
+ path,
433
+ schema,
434
+ Endpoint = RestEndpoint,
435
+ optimistic,
436
+ ...extraOptions
437
+ }) {
438
+ const shortenedPath = shortenPath(path);
439
+ const getName = name => `${schema == null ? void 0 : schema.name}.${name}`;
440
+ const extraMutateOptions = {
441
+ ...extraOptions
442
+ };
443
+ const extraPartialOptions = {
444
+ ...extraOptions
445
+ };
446
+ const get = new Endpoint({
447
+ ...extraOptions,
448
+ path,
449
+ schema,
450
+ name: getName('get')
451
+ });
452
+ if (optimistic) {
453
+ extraMutateOptions.getOptimisticResponse = optimisticUpdate;
454
+ extraPartialOptions.getOptimisticResponse = optimisticPartial(get);
455
+ }
456
+ const getList = new Endpoint({
457
+ ...extraMutateOptions,
458
+ path: shortenedPath,
459
+ schema: new Collection([schema]),
460
+ name: getName('getList')
461
+ });
462
+ return {
463
+ get,
464
+ getList,
465
+ create: getList.push.extend({
466
+ name: getName('create')
467
+ }),
468
+ update: new Endpoint({
469
+ ...extraMutateOptions,
470
+ path,
471
+ schema,
472
+ method: 'PUT',
473
+ name: getName('update')
474
+ }),
475
+ partialUpdate: new Endpoint({
476
+ ...extraPartialOptions,
477
+ path,
478
+ schema,
479
+ method: 'PATCH',
480
+ name: getName('partialUpdate')
481
+ }),
482
+ delete: new Endpoint({
483
+ ...extraMutateOptions,
484
+ path,
485
+ schema: schema.process ? new Invalidate(schema) : schema,
486
+ method: 'DELETE',
487
+ name: getName('delete'),
488
+ process(res, params) {
489
+ return res && Object.keys(res).length ? res : params;
490
+ },
491
+ getOptimisticResponse: optimistic ? optimisticDelete : undefined
492
+ })
493
+ };
494
+ }
495
+ function optimisticUpdate(snap, params, body) {
496
+ return {
497
+ ...params,
498
+ ...body
499
+ };
500
+ }
501
+ function optimisticPartial(getEndpoint) {
502
+ return function (snap, params, body) {
503
+ const {
504
+ data
505
+ } = snap.getResponse(getEndpoint, params);
506
+ if (!data) throw new endpoint.AbortOptimistic();
507
+ return {
508
+ ...params,
509
+ ...data,
510
+ // even tho we don't always have two arguments, the extra one will simply be undefined which spreads fine
511
+ ...body
512
+ };
513
+ };
514
+ }
515
+ function optimisticDelete(snap, params) {
516
+ return params;
517
+ }
518
+
519
+ exports.RestEndpoint = RestEndpoint;
520
+ exports.createResource = createResource;
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,13 @@
1
+ /** An error with a Rest Endpoint fetch
2
+ *
3
+ * @see https://resthooks.io/rest/api/NetworkError
4
+ */
5
+ export default class NetworkError extends Error {
6
+ constructor(response) {
7
+ super(response.statusText || `Network response not 'ok': ${response.status}`);
8
+ this.name = 'NetworkError';
9
+ this.status = response.status;
10
+ this.response = response;
11
+ }
12
+ }
13
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJOZXR3b3JrRXJyb3IiLCJFcnJvciIsImNvbnN0cnVjdG9yIiwicmVzcG9uc2UiLCJzdGF0dXNUZXh0Iiwic3RhdHVzIiwibmFtZSJdLCJzb3VyY2VzIjpbIi4uL3NyYy9OZXR3b3JrRXJyb3IudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqIEFuIGVycm9yIHdpdGggYSBSZXN0IEVuZHBvaW50IGZldGNoXG4gKlxuICogQHNlZSBodHRwczovL3Jlc3Rob29rcy5pby9yZXN0L2FwaS9OZXR3b3JrRXJyb3JcbiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgTmV0d29ya0Vycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBkZWNsYXJlIHN0YXR1czogbnVtYmVyO1xuICBkZWNsYXJlIHJlc3BvbnNlOiBSZXNwb25zZTtcbiAgbmFtZSA9ICdOZXR3b3JrRXJyb3InO1xuXG4gIGNvbnN0cnVjdG9yKHJlc3BvbnNlOiBSZXNwb25zZSkge1xuICAgIHN1cGVyKFxuICAgICAgcmVzcG9uc2Uuc3RhdHVzVGV4dCB8fCBgTmV0d29yayByZXNwb25zZSBub3QgJ29rJzogJHtyZXNwb25zZS5zdGF0dXN9YCxcbiAgICApO1xuICAgIHRoaXMuc3RhdHVzID0gcmVzcG9uc2Uuc3RhdHVzO1xuICAgIHRoaXMucmVzcG9uc2UgPSByZXNwb25zZTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGVBQWUsTUFBTUEsWUFBWSxTQUFTQyxLQUFLLENBQUM7RUFLOUNDLFdBQVdBLENBQUNDLFFBQWtCLEVBQUU7SUFDOUIsS0FBSyxDQUNIQSxRQUFRLENBQUNDLFVBQVUsSUFBSyw4QkFBNkJELFFBQVEsQ0FBQ0UsTUFBTyxFQUN2RSxDQUFDO0lBQUMsS0FMSkMsSUFBSSxHQUFHLGNBQWM7SUFNbkIsSUFBSSxDQUFDRCxNQUFNLEdBQUdGLFFBQVEsQ0FBQ0UsTUFBTTtJQUM3QixJQUFJLENBQUNGLFFBQVEsR0FBR0EsUUFBUTtFQUMxQjtBQUNGIn0=
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vc3JjL09wdGlvbnNUb0Z1bmN0aW9uLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB0eXBlIHsgRmV0Y2hGdW5jdGlvbiwgUmVzb2x2ZVR5cGUgfSBmcm9tICdAZGF0YS1jbGllbnQvZW5kcG9pbnQnO1xuXG5pbXBvcnQgeyBQYXRoQXJncyB9IGZyb20gJy4vcGF0aFR5cGVzLmpzJztcbmltcG9ydCB7XG4gIFBhcnRpYWxSZXN0R2VuZXJpY3MsXG4gIFJlc3RJbnN0YW5jZSxcbiAgUmVzdEluc3RhbmNlQmFzZSxcbiAgUmVzdEZldGNoLFxufSBmcm9tICcuL1Jlc3RFbmRwb2ludC5qcyc7XG5cbmV4cG9ydCB0eXBlIE9wdGlvbnNUb0Z1bmN0aW9uPFxuICBPIGV4dGVuZHMgUGFydGlhbFJlc3RHZW5lcmljcyxcbiAgRSBleHRlbmRzIFJlc3RJbnN0YW5jZUJhc2UgJiB7IGJvZHk/OiBhbnkgfSxcbiAgRiBleHRlbmRzIEZldGNoRnVuY3Rpb24sXG4+ID0gJ3BhdGgnIGV4dGVuZHMga2V5b2YgT1xuICA/IFJlc3RGZXRjaDxcbiAgICAgICdzZWFyY2hQYXJhbXMnIGV4dGVuZHMga2V5b2YgT1xuICAgICAgICA/IE9bJ3NlYXJjaFBhcmFtcyddICYgUGF0aEFyZ3M8RXhjbHVkZTxPWydwYXRoJ10sIHVuZGVmaW5lZD4+XG4gICAgICAgIDogUGF0aEFyZ3M8RXhjbHVkZTxPWydwYXRoJ10sIHVuZGVmaW5lZD4+LFxuICAgICAgJ2JvZHknIGV4dGVuZHMga2V5b2YgTyA/IE9bJ2JvZHknXSA6IEVbJ2JvZHknXSxcbiAgICAgIE9bJ3Byb2Nlc3MnXSBleHRlbmRzIHt9ID8gUmV0dXJuVHlwZTxPWydwcm9jZXNzJ10+IDogUmVzb2x2ZVR5cGU8Rj5cbiAgICA+XG4gIDogJ2JvZHknIGV4dGVuZHMga2V5b2YgT1xuICA/IFJlc3RGZXRjaDxcbiAgICAgICdzZWFyY2hQYXJhbXMnIGV4dGVuZHMga2V5b2YgT1xuICAgICAgICA/IE9bJ3NlYXJjaFBhcmFtcyddICYgUGF0aEFyZ3M8RXhjbHVkZTxFWydwYXRoJ10sIHVuZGVmaW5lZD4+XG4gICAgICAgIDogUGF0aEFyZ3M8RXhjbHVkZTxFWydwYXRoJ10sIHVuZGVmaW5lZD4+LFxuICAgICAgT1snYm9keSddLFxuICAgICAgT1sncHJvY2VzcyddIGV4dGVuZHMge30gPyBSZXR1cm5UeXBlPE9bJ3Byb2Nlc3MnXT4gOiBSZXNvbHZlVHlwZTxGPlxuICAgID5cbiAgOiAnc2VhcmNoUGFyYW1zJyBleHRlbmRzIGtleW9mIE9cbiAgPyBSZXN0RmV0Y2g8XG4gICAgICBPWydzZWFyY2hQYXJhbXMnXSAmIFBhdGhBcmdzPEV4Y2x1ZGU8RVsncGF0aCddLCB1bmRlZmluZWQ+PixcbiAgICAgIEVbJ2JvZHknXSxcbiAgICAgIE9bJ3Byb2Nlc3MnXSBleHRlbmRzIHt9ID8gUmV0dXJuVHlwZTxPWydwcm9jZXNzJ10+IDogUmVzb2x2ZVR5cGU8Rj5cbiAgICA+XG4gIDogKFxuICAgICAgdGhpczogVGhpc1BhcmFtZXRlclR5cGU8Rj4sXG4gICAgICAuLi5hcmdzOiBQYXJhbWV0ZXJzPEY+XG4gICAgKSA9PiBQcm9taXNlPFxuICAgICAgT1sncHJvY2VzcyddIGV4dGVuZHMge30gPyBSZXR1cm5UeXBlPE9bJ3Byb2Nlc3MnXT4gOiBSZXNvbHZlVHlwZTxGPlxuICAgID47XG4iXSwibWFwcGluZ3MiOiIifQ==