@khanacademy/wonder-blocks-data 2.3.1 → 3.0.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/CHANGELOG.md +7 -0
- package/dist/es/index.js +212 -446
- package/dist/index.js +553 -729
- package/docs.md +19 -13
- package/package.json +6 -7
- package/src/__tests__/__snapshots__/generated-snapshot.test.js.snap +40 -160
- package/src/__tests__/generated-snapshot.test.js +15 -195
- package/src/components/__tests__/data.test.js +159 -965
- package/src/components/__tests__/intercept-data.test.js +9 -66
- package/src/components/__tests__/track-data.test.js +6 -5
- package/src/components/data.js +9 -119
- package/src/components/data.md +38 -60
- package/src/components/intercept-context.js +2 -3
- package/src/components/intercept-data.js +2 -34
- package/src/components/intercept-data.md +7 -105
- package/src/hooks/__tests__/use-data.test.js +790 -0
- package/src/hooks/use-data.js +138 -0
- package/src/index.js +1 -3
- package/src/util/__tests__/memory-cache.test.js +134 -35
- package/src/util/__tests__/request-fulfillment.test.js +21 -36
- package/src/util/__tests__/request-handler.test.js +30 -30
- package/src/util/__tests__/request-tracking.test.js +29 -30
- package/src/util/__tests__/response-cache.test.js +521 -561
- package/src/util/__tests__/result-from-cache-entry.test.js +68 -0
- package/src/util/memory-cache.js +20 -15
- package/src/util/request-fulfillment.js +4 -0
- package/src/util/request-handler.js +4 -28
- package/src/util/request-handler.md +0 -32
- package/src/util/request-tracking.js +2 -3
- package/src/util/response-cache.js +50 -110
- package/src/util/result-from-cache-entry.js +38 -0
- package/src/util/types.js +14 -35
- package/LICENSE +0 -21
- package/src/components/__tests__/intercept-cache.test.js +0 -124
- package/src/components/__tests__/internal-data.test.js +0 -1030
- package/src/components/intercept-cache.js +0 -79
- package/src/components/intercept-cache.md +0 -103
- package/src/components/internal-data.js +0 -219
- package/src/util/__tests__/no-cache.test.js +0 -112
- package/src/util/no-cache.js +0 -66
- package/src/util/no-cache.md +0 -66
package/dist/index.js
CHANGED
|
@@ -82,7 +82,7 @@ module.exports =
|
|
|
82
82
|
/******/
|
|
83
83
|
/******/
|
|
84
84
|
/******/ // Load entry module and return exports
|
|
85
|
-
/******/ return __webpack_require__(__webpack_require__.s =
|
|
85
|
+
/******/ return __webpack_require__(__webpack_require__.s = 13);
|
|
86
86
|
/******/ })
|
|
87
87
|
/************************************************************************/
|
|
88
88
|
/******/ ([
|
|
@@ -99,225 +99,13 @@ module.exports = require("@khanacademy/wonder-blocks-core");
|
|
|
99
99
|
|
|
100
100
|
/***/ }),
|
|
101
101
|
/* 2 */
|
|
102
|
-
/***/ (function(module, exports) {
|
|
103
|
-
|
|
104
|
-
function _extends() {
|
|
105
|
-
module.exports = _extends = Object.assign || function (target) {
|
|
106
|
-
for (var i = 1; i < arguments.length; i++) {
|
|
107
|
-
var source = arguments[i];
|
|
108
|
-
|
|
109
|
-
for (var key in source) {
|
|
110
|
-
if (Object.prototype.hasOwnProperty.call(source, key)) {
|
|
111
|
-
target[key] = source[key];
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
return target;
|
|
117
|
-
};
|
|
118
|
-
|
|
119
|
-
module.exports["default"] = module.exports, module.exports.__esModule = true;
|
|
120
|
-
return _extends.apply(this, arguments);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
module.exports = _extends;
|
|
124
|
-
module.exports["default"] = module.exports, module.exports.__esModule = true;
|
|
125
|
-
|
|
126
|
-
/***/ }),
|
|
127
|
-
/* 3 */
|
|
128
102
|
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
129
103
|
|
|
130
104
|
"use strict";
|
|
131
|
-
|
|
132
|
-
__webpack_require__
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
__webpack_require__.d(__webpack_exports__, "initializeCache", function() { return /* binding */ initializeCache; });
|
|
136
|
-
__webpack_require__.d(__webpack_exports__, "fulfillAllDataRequests", function() { return /* binding */ fulfillAllDataRequests; });
|
|
137
|
-
__webpack_require__.d(__webpack_exports__, "hasUnfulfilledRequests", function() { return /* binding */ hasUnfulfilledRequests; });
|
|
138
|
-
__webpack_require__.d(__webpack_exports__, "removeFromCache", function() { return /* binding */ removeFromCache; });
|
|
139
|
-
__webpack_require__.d(__webpack_exports__, "removeAllFromCache", function() { return /* binding */ removeAllFromCache; });
|
|
140
|
-
__webpack_require__.d(__webpack_exports__, "RequestHandler", function() { return /* reexport */ RequestHandler; });
|
|
141
|
-
__webpack_require__.d(__webpack_exports__, "TrackData", function() { return /* reexport */ track_data_TrackData; });
|
|
142
|
-
__webpack_require__.d(__webpack_exports__, "Data", function() { return /* reexport */ data_Data; });
|
|
143
|
-
__webpack_require__.d(__webpack_exports__, "InterceptData", function() { return /* reexport */ intercept_data_InterceptData; });
|
|
144
|
-
__webpack_require__.d(__webpack_exports__, "InterceptCache", function() { return /* reexport */ intercept_cache_InterceptCache; });
|
|
145
|
-
__webpack_require__.d(__webpack_exports__, "NoCache", function() { return /* reexport */ NoCache; });
|
|
146
|
-
|
|
147
|
-
// EXTERNAL MODULE: external "@khanacademy/wonder-blocks-core"
|
|
148
|
-
var wonder_blocks_core_ = __webpack_require__(1);
|
|
149
|
-
|
|
150
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/util/memory-cache.js
|
|
151
|
-
function deepClone(source) {
|
|
152
|
-
/**
|
|
153
|
-
* We want to deep clone the source cache to dodge mutations by external
|
|
154
|
-
* references. So we serialize the source cache to JSON and parse it
|
|
155
|
-
* back into a new object.
|
|
156
|
-
*
|
|
157
|
-
* NOTE: This doesn't work for get/set property accessors.
|
|
158
|
-
*/
|
|
159
|
-
const serializedInitCache = JSON.stringify(source);
|
|
160
|
-
const cloneInitCache = JSON.parse(serializedInitCache);
|
|
161
|
-
return Object.freeze(cloneInitCache);
|
|
162
|
-
}
|
|
163
|
-
/**
|
|
164
|
-
* INTERNAL USE ONLY
|
|
165
|
-
*
|
|
166
|
-
* Special case cache implementation for the memory cache.
|
|
167
|
-
*
|
|
168
|
-
* This is only used within our framework. Handlers don't need to
|
|
169
|
-
* provide this as a custom cache as the framework will default to this in the
|
|
170
|
-
* absence of a custom cache. We use this for SSR too (see ./response-cache.js).
|
|
171
|
-
*/
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
class MemoryCache {
|
|
175
|
-
constructor(source = null) {
|
|
176
|
-
this.store = (handler, options, entry) => {
|
|
177
|
-
const requestType = handler.type;
|
|
178
|
-
const frozenEntry = Object.isFrozen(entry) ? entry : Object.freeze(entry); // Ensure we have a cache location for this handler type.
|
|
179
|
-
|
|
180
|
-
this._cache[requestType] = this._cache[requestType] || {}; // Cache the data.
|
|
181
|
-
|
|
182
|
-
const key = handler.getKey(options);
|
|
183
|
-
this._cache[requestType][key] = frozenEntry;
|
|
184
|
-
};
|
|
185
|
-
|
|
186
|
-
this.retrieve = (handler, options) => {
|
|
187
|
-
const requestType = handler.type; // Get the internal subcache for the handler.
|
|
188
|
-
|
|
189
|
-
const handlerCache = this._cache[requestType];
|
|
190
|
-
|
|
191
|
-
if (!handlerCache) {
|
|
192
|
-
return null;
|
|
193
|
-
} // Get the response.
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
const key = handler.getKey(options);
|
|
197
|
-
const internalEntry = handlerCache[key];
|
|
198
|
-
|
|
199
|
-
if (internalEntry == null) {
|
|
200
|
-
return null;
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
return internalEntry;
|
|
204
|
-
};
|
|
205
|
-
|
|
206
|
-
this.remove = (handler, options) => {
|
|
207
|
-
const requestType = handler.type; // NOTE(somewhatabstract): We could invoke removeAll with a predicate
|
|
208
|
-
// to match the key of the entry we're removing, but that's an
|
|
209
|
-
// inefficient way to remove a single item, so let's not do that.
|
|
210
|
-
// Get the internal subcache for the handler.
|
|
211
|
-
|
|
212
|
-
const handlerCache = this._cache[requestType];
|
|
213
|
-
|
|
214
|
-
if (!handlerCache) {
|
|
215
|
-
return false;
|
|
216
|
-
} // Get the entry.
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
const key = handler.getKey(options);
|
|
220
|
-
const internalEntry = handlerCache[key];
|
|
221
|
-
|
|
222
|
-
if (internalEntry == null) {
|
|
223
|
-
return false;
|
|
224
|
-
} // Delete the entry.
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
delete handlerCache[key];
|
|
228
|
-
return true;
|
|
229
|
-
};
|
|
230
|
-
|
|
231
|
-
this.removeAll = (handler, predicate) => {
|
|
232
|
-
const requestType = handler.type; // Get the internal subcache for the handler.
|
|
233
|
-
|
|
234
|
-
const handlerCache = this._cache[requestType];
|
|
235
|
-
|
|
236
|
-
if (!handlerCache) {
|
|
237
|
-
return 0;
|
|
238
|
-
} // Apply the predicate to what we have cached.
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
let removedCount = 0;
|
|
242
|
-
|
|
243
|
-
for (const [key, entry] of Object.entries(handlerCache)) {
|
|
244
|
-
if (typeof predicate !== "function" || predicate(key, entry)) {
|
|
245
|
-
removedCount++;
|
|
246
|
-
delete handlerCache[key];
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
return removedCount;
|
|
251
|
-
};
|
|
252
|
-
|
|
253
|
-
this.cloneData = () => {
|
|
254
|
-
try {
|
|
255
|
-
return deepClone(this._cache);
|
|
256
|
-
} catch (e) {
|
|
257
|
-
throw new Error(`An error occurred while trying to clone the cache: ${e}`);
|
|
258
|
-
}
|
|
259
|
-
};
|
|
260
|
-
|
|
261
|
-
this._cache = {};
|
|
262
|
-
|
|
263
|
-
if (source != null) {
|
|
264
|
-
try {
|
|
265
|
-
/**
|
|
266
|
-
* Object.assign only performs a shallow clone.
|
|
267
|
-
* So we deep clone it and then assign the clone values to our
|
|
268
|
-
* internal cache.
|
|
269
|
-
*/
|
|
270
|
-
const cloneInitCache = deepClone(source);
|
|
271
|
-
Object.assign(this._cache, cloneInitCache);
|
|
272
|
-
} catch (e) {
|
|
273
|
-
throw new Error(`An error occurred trying to initialize from a response cache snapshot: ${e}`);
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
get inUse() {
|
|
279
|
-
return Object.keys(this._cache).length > 0;
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/util/no-cache.js
|
|
284
|
-
let defaultInstance = null;
|
|
285
|
-
/**
|
|
286
|
-
* This is a cache implementation to use when no caching is wanted.
|
|
287
|
-
*
|
|
288
|
-
* Use this with your request handler if you want to support server-side
|
|
289
|
-
* rendering of your data requests, but want to ensure data is never cached
|
|
290
|
-
* on the client-side.
|
|
291
|
-
*
|
|
292
|
-
* This is better than having `shouldRefreshCache` always return `true` in the
|
|
293
|
-
* handler as this ensures that cache space and memory are never used for the
|
|
294
|
-
* requested data after hydration has finished.
|
|
295
|
-
*/
|
|
296
|
-
|
|
297
|
-
class NoCache {
|
|
298
|
-
constructor() {
|
|
299
|
-
this.store = (handler, options, entry) => {
|
|
300
|
-
/* empty */
|
|
301
|
-
};
|
|
302
|
-
|
|
303
|
-
this.retrieve = (handler, options) => null;
|
|
304
|
-
|
|
305
|
-
this.remove = (handler, options) => false;
|
|
306
|
-
|
|
307
|
-
this.removeAll = (handler, predicate) => 0;
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
static get Default() {
|
|
311
|
-
if (defaultInstance == null) {
|
|
312
|
-
defaultInstance = new NoCache();
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
return defaultInstance;
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
}
|
|
319
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/util/response-cache.js
|
|
320
|
-
|
|
105
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ResponseCache; });
|
|
106
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
107
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
108
|
+
/* harmony import */ var _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(7);
|
|
321
109
|
|
|
322
110
|
|
|
323
111
|
|
|
@@ -333,33 +121,31 @@ let _default;
|
|
|
333
121
|
*/
|
|
334
122
|
|
|
335
123
|
|
|
336
|
-
class
|
|
124
|
+
class ResponseCache {
|
|
337
125
|
static get Default() {
|
|
338
126
|
if (!_default) {
|
|
339
|
-
_default = new
|
|
127
|
+
_default = new ResponseCache();
|
|
340
128
|
}
|
|
341
129
|
|
|
342
130
|
return _default;
|
|
343
131
|
}
|
|
344
132
|
|
|
345
|
-
constructor(
|
|
133
|
+
constructor(hydrationCache = null, ssrOnlyCache = null) {
|
|
346
134
|
this.initialize = source => {
|
|
347
|
-
if (this.
|
|
135
|
+
if (this._hydrationCache.inUse) {
|
|
348
136
|
throw new Error("Cannot initialize data response cache more than once");
|
|
349
137
|
}
|
|
350
138
|
|
|
351
139
|
try {
|
|
352
|
-
this.
|
|
140
|
+
this._hydrationCache = new _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"](source);
|
|
353
141
|
} catch (e) {
|
|
354
142
|
throw new Error(`An error occurred trying to initialize the data response cache: ${e}`);
|
|
355
143
|
}
|
|
356
144
|
};
|
|
357
145
|
|
|
358
|
-
this.cacheData = (handler, options, data) => {
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
});
|
|
362
|
-
};
|
|
146
|
+
this.cacheData = (handler, options, data) => this._setCacheEntry(handler, options, {
|
|
147
|
+
data
|
|
148
|
+
});
|
|
363
149
|
|
|
364
150
|
this.cacheError = (handler, options, error) => {
|
|
365
151
|
const errorMessage = typeof error === "string" ? error : error.message;
|
|
@@ -369,110 +155,64 @@ class response_cache_ResponseCache {
|
|
|
369
155
|
};
|
|
370
156
|
|
|
371
157
|
this.getEntry = (handler, options) => {
|
|
372
|
-
//
|
|
373
|
-
//
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
// This allows us to use our hydrated cache during hydration.
|
|
383
|
-
// If we just returned null when the custom cache didn't have it,
|
|
384
|
-
// we would never hydrate properly.
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
const internalEntry = this._defaultCache(handler).retrieve(handler, options); // If we are not server-side and we hydrated something that the custom
|
|
388
|
-
// cache didn't have, we need to make sure the custom cache contains
|
|
389
|
-
// that value.
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
if (this._ssrOnlyCache == null && handler.cache != null && internalEntry != null) {
|
|
393
|
-
// Yes, if this throws, we will have a problem. We want that.
|
|
394
|
-
// Bad cache implementations should be overt.
|
|
395
|
-
handler.cache.store(handler, options, internalEntry); // We now delete this from our in-memory cache as we don't need it.
|
|
158
|
+
// Get the cached entry for this value.
|
|
159
|
+
// If the handler wants WB Data to hydrate (i.e. handler.hydrate is
|
|
160
|
+
// true), we use our hydration cache. Otherwise, if we're server-side
|
|
161
|
+
// we use our SSR-only cache. Otherwise, there's no entry to return.
|
|
162
|
+
const cache = handler.hydrate ? this._hydrationCache : _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? this._ssrOnlyCache : undefined;
|
|
163
|
+
const internalEntry = cache == null ? void 0 : cache.retrieve(handler, options); // If we are not server-side and we hydrated something, let's clear
|
|
164
|
+
// that from the hydration cache to save memory.
|
|
165
|
+
|
|
166
|
+
if (this._ssrOnlyCache == null && internalEntry != null) {
|
|
167
|
+
// We now delete this from our hydration cache as we don't need it.
|
|
396
168
|
// This does mean that if another handler of the same type but
|
|
397
|
-
// without
|
|
398
|
-
//
|
|
399
|
-
//
|
|
400
|
-
|
|
401
|
-
this.
|
|
169
|
+
// without some sort of linked cache won't get the value, but
|
|
170
|
+
// that's not an expected use-case. If two different places use the
|
|
171
|
+
// same handler and options (i.e. the same request), then the
|
|
172
|
+
// handler should cater to that to ensure they share the result.
|
|
173
|
+
this._hydrationCache.remove(handler, options);
|
|
402
174
|
}
|
|
403
175
|
|
|
404
176
|
return internalEntry;
|
|
405
177
|
};
|
|
406
178
|
|
|
407
179
|
this.remove = (handler, options) => {
|
|
180
|
+
var _this$_ssrOnlyCache$r, _this$_ssrOnlyCache;
|
|
181
|
+
|
|
408
182
|
// NOTE(somewhatabstract): We could invoke removeAll with a predicate
|
|
409
183
|
// to match the key of the entry we're removing, but that's an
|
|
410
184
|
// inefficient way to remove a single item, so let's not do that.
|
|
411
|
-
//
|
|
412
|
-
|
|
413
|
-
const customCache = this._ssrOnlyCache == null ? handler.cache : null;
|
|
414
|
-
const removedCustom = !!(customCache != null && customCache.remove(handler, options)); // Delete the entry from our internal cache.
|
|
415
|
-
// Even if we have a custom cache, we want to make sure we still
|
|
416
|
-
// removed the same value from internal cache since this could be
|
|
417
|
-
// getting called before hydration for some complex advanced usage
|
|
418
|
-
// reason.
|
|
419
|
-
|
|
420
|
-
return this._defaultCache(handler).remove(handler, options) || removedCustom;
|
|
185
|
+
// Delete the entry from the appropriate cache.
|
|
186
|
+
return handler.hydrate ? this._hydrationCache.remove(handler, options) : (_this$_ssrOnlyCache$r = (_this$_ssrOnlyCache = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache.remove(handler, options)) != null ? _this$_ssrOnlyCache$r : false;
|
|
421
187
|
};
|
|
422
188
|
|
|
423
189
|
this.removeAll = (handler, predicate) => {
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
// Even if we have a custom cache, we want to make sure we still
|
|
429
|
-
// removed the same value from internal cache since this could be
|
|
430
|
-
// getting called before hydration for some complex advanced usage
|
|
431
|
-
// reason.
|
|
432
|
-
|
|
433
|
-
const removedCount = this._defaultCache(handler).removeAll(handler, predicate); // We have no idea which keys were removed from which caches,
|
|
434
|
-
// so we can't dedupe the remove counts based on keys.
|
|
435
|
-
// That's why we return the total records deleted rather than the
|
|
436
|
-
// total keys deleted.
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
return removedCount + removedCountCustom;
|
|
190
|
+
var _this$_ssrOnlyCache$r2, _this$_ssrOnlyCache2;
|
|
191
|
+
|
|
192
|
+
// Apply the predicate to what we have in the appropriate cache.
|
|
193
|
+
return handler.hydrate ? this._hydrationCache.removeAll(handler, predicate) : (_this$_ssrOnlyCache$r2 = (_this$_ssrOnlyCache2 = this._ssrOnlyCache) == null ? void 0 : _this$_ssrOnlyCache2.removeAll(handler, predicate)) != null ? _this$_ssrOnlyCache$r2 : 0;
|
|
440
194
|
};
|
|
441
195
|
|
|
442
196
|
this.cloneHydratableData = () => {
|
|
443
197
|
// We return our hydration cache only.
|
|
444
|
-
return this.
|
|
198
|
+
return this._hydrationCache.cloneData();
|
|
445
199
|
};
|
|
446
200
|
|
|
447
|
-
this._ssrOnlyCache =
|
|
448
|
-
this.
|
|
449
|
-
}
|
|
450
|
-
/**
|
|
451
|
-
* Returns the default cache to use for the given handler.
|
|
452
|
-
*/
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
_defaultCache(handler) {
|
|
456
|
-
if (handler.hydrate) {
|
|
457
|
-
return this._hydrationAndDefaultCache;
|
|
458
|
-
} // If the handler doesn't want to hydrate, we return the SSR-only cache.
|
|
459
|
-
// If we are client-side, we return our non-caching implementation.
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
return this._ssrOnlyCache || NoCache.Default;
|
|
201
|
+
this._ssrOnlyCache = _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide() ? ssrOnlyCache || new _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"]() : undefined;
|
|
202
|
+
this._hydrationCache = hydrationCache || new _memory_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"]();
|
|
463
203
|
}
|
|
464
204
|
|
|
465
205
|
_setCacheEntry(handler, options, entry) {
|
|
466
206
|
const frozenEntry = Object.freeze(entry);
|
|
467
207
|
|
|
468
|
-
if (this._ssrOnlyCache
|
|
469
|
-
// We are
|
|
470
|
-
//
|
|
471
|
-
handler.
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
208
|
+
if (this._ssrOnlyCache != null) {
|
|
209
|
+
// We are server-side.
|
|
210
|
+
// We need to store this value.
|
|
211
|
+
if (handler.hydrate) {
|
|
212
|
+
this._hydrationCache.store(handler, options, frozenEntry);
|
|
213
|
+
} else {
|
|
214
|
+
this._ssrOnlyCache.store(handler, options, frozenEntry);
|
|
215
|
+
}
|
|
476
216
|
}
|
|
477
217
|
|
|
478
218
|
return frozenEntry;
|
|
@@ -485,89 +225,18 @@ class response_cache_ResponseCache {
|
|
|
485
225
|
|
|
486
226
|
|
|
487
227
|
}
|
|
488
|
-
// EXTERNAL MODULE: external "react"
|
|
489
|
-
var external_react_ = __webpack_require__(0);
|
|
490
|
-
|
|
491
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/util/request-fulfillment.js
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
let request_fulfillment_default;
|
|
495
|
-
|
|
496
|
-
class request_fulfillment_RequestFulfillment {
|
|
497
|
-
static get Default() {
|
|
498
|
-
if (!request_fulfillment_default) {
|
|
499
|
-
request_fulfillment_default = new request_fulfillment_RequestFulfillment();
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
return request_fulfillment_default;
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
constructor(responseCache = undefined) {
|
|
506
|
-
this._requests = {};
|
|
507
|
-
|
|
508
|
-
this._getHandlerSubcache = handler => {
|
|
509
|
-
if (!this._requests[handler.type]) {
|
|
510
|
-
this._requests[handler.type] = {};
|
|
511
|
-
}
|
|
512
|
-
|
|
513
|
-
return this._requests[handler.type];
|
|
514
|
-
};
|
|
515
|
-
|
|
516
|
-
this.fulfill = (handler, options) => {
|
|
517
|
-
const handlerRequests = this._getHandlerSubcache(handler);
|
|
518
|
-
|
|
519
|
-
const key = handler.getKey(options);
|
|
520
|
-
/**
|
|
521
|
-
* If we have an inflight request, we'll provide that.
|
|
522
|
-
*/
|
|
523
|
-
|
|
524
|
-
const inflight = handlerRequests[key];
|
|
525
|
-
|
|
526
|
-
if (inflight) {
|
|
527
|
-
return inflight;
|
|
528
|
-
}
|
|
529
|
-
/**
|
|
530
|
-
* We don't have an inflight request, so let's set one up.
|
|
531
|
-
*/
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
const {
|
|
535
|
-
cacheData,
|
|
536
|
-
cacheError
|
|
537
|
-
} = this._responseCache;
|
|
538
|
-
|
|
539
|
-
try {
|
|
540
|
-
const request = handler.fulfillRequest(options).then(data => {
|
|
541
|
-
delete handlerRequests[key];
|
|
542
|
-
/**
|
|
543
|
-
* Let's cache the data!
|
|
544
|
-
*/
|
|
545
|
-
|
|
546
|
-
return cacheData(handler, options, data);
|
|
547
|
-
}).catch(error => {
|
|
548
|
-
delete handlerRequests[key];
|
|
549
|
-
/**
|
|
550
|
-
* Let's cache the error!
|
|
551
|
-
*/
|
|
552
|
-
|
|
553
|
-
return cacheError(handler, options, error);
|
|
554
|
-
});
|
|
555
|
-
handlerRequests[key] = request;
|
|
556
|
-
return request;
|
|
557
|
-
} catch (e) {
|
|
558
|
-
/**
|
|
559
|
-
* In this case, we don't cache an inflight request, because there
|
|
560
|
-
* really isn't one.
|
|
561
|
-
*/
|
|
562
|
-
return Promise.resolve(cacheError(handler, options, e));
|
|
563
|
-
}
|
|
564
|
-
};
|
|
565
228
|
|
|
566
|
-
|
|
567
|
-
|
|
229
|
+
/***/ }),
|
|
230
|
+
/* 3 */
|
|
231
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
568
232
|
|
|
569
|
-
|
|
570
|
-
|
|
233
|
+
"use strict";
|
|
234
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "b", function() { return TrackerContext; });
|
|
235
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RequestTracker; });
|
|
236
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
237
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
238
|
+
/* harmony import */ var _response_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
239
|
+
/* harmony import */ var _request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
|
|
571
240
|
|
|
572
241
|
|
|
573
242
|
|
|
@@ -577,13 +246,13 @@ class request_fulfillment_RequestFulfillment {
|
|
|
577
246
|
*
|
|
578
247
|
* INTERNAL USE ONLY
|
|
579
248
|
*/
|
|
580
|
-
const TrackerContext = new
|
|
249
|
+
const TrackerContext = new react__WEBPACK_IMPORTED_MODULE_0__["createContext"](null);
|
|
581
250
|
/**
|
|
582
251
|
* The default instance is stored here.
|
|
583
252
|
* It's created below in the Default() static property.
|
|
584
253
|
*/
|
|
585
254
|
|
|
586
|
-
let
|
|
255
|
+
let _default;
|
|
587
256
|
/**
|
|
588
257
|
* Implements request tracking and fulfillment.
|
|
589
258
|
*
|
|
@@ -591,13 +260,13 @@ let request_tracking_default;
|
|
|
591
260
|
*/
|
|
592
261
|
|
|
593
262
|
|
|
594
|
-
class
|
|
263
|
+
class RequestTracker {
|
|
595
264
|
static get Default() {
|
|
596
|
-
if (!
|
|
597
|
-
|
|
265
|
+
if (!_default) {
|
|
266
|
+
_default = new RequestTracker();
|
|
598
267
|
}
|
|
599
268
|
|
|
600
|
-
return
|
|
269
|
+
return _default;
|
|
601
270
|
}
|
|
602
271
|
/**
|
|
603
272
|
* These are the caches for tracked requests, their handlers, and responses.
|
|
@@ -675,8 +344,8 @@ class request_tracking_RequestTracker {
|
|
|
675
344
|
return Promise.all(promises).then(() => this._responseCache.cloneHydratableData());
|
|
676
345
|
};
|
|
677
346
|
|
|
678
|
-
this._responseCache = responseCache ||
|
|
679
|
-
this._requestFulfillment = new
|
|
347
|
+
this._responseCache = responseCache || _response_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* ResponseCache */ "a"].Default;
|
|
348
|
+
this._requestFulfillment = new _request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestFulfillment */ "a"](responseCache);
|
|
680
349
|
}
|
|
681
350
|
/**
|
|
682
351
|
* Track a request.
|
|
@@ -708,369 +377,499 @@ class request_tracking_RequestTracker {
|
|
|
708
377
|
|
|
709
378
|
|
|
710
379
|
}
|
|
711
|
-
|
|
380
|
+
|
|
381
|
+
/***/ }),
|
|
382
|
+
/* 4 */
|
|
383
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
384
|
+
|
|
385
|
+
"use strict";
|
|
386
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
387
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
388
|
+
|
|
389
|
+
|
|
712
390
|
/**
|
|
713
|
-
*
|
|
391
|
+
* InterceptContext defines a map from handler type to interception methods.
|
|
714
392
|
*
|
|
715
|
-
*
|
|
716
|
-
* use with the Wonder Blocks Data framework.
|
|
393
|
+
* INTERNAL USE ONLY
|
|
717
394
|
*/
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
this._type = type;
|
|
721
|
-
this._cache = cache || null;
|
|
722
|
-
this._hydrate = !!hydrate;
|
|
723
|
-
}
|
|
395
|
+
const InterceptContext = /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createContext"]({});
|
|
396
|
+
/* harmony default export */ __webpack_exports__["a"] = (InterceptContext);
|
|
724
397
|
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
398
|
+
/***/ }),
|
|
399
|
+
/* 5 */
|
|
400
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
728
401
|
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
402
|
+
"use strict";
|
|
403
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return useData; });
|
|
404
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
405
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
406
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(0);
|
|
407
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_1__);
|
|
408
|
+
/* harmony import */ var _util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(6);
|
|
409
|
+
/* harmony import */ var _components_intercept_context_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(4);
|
|
410
|
+
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(3);
|
|
411
|
+
/* harmony import */ var _util_result_from_cache_entry_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(12);
|
|
412
|
+
/* harmony import */ var _util_response_cache_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(2);
|
|
732
413
|
|
|
733
|
-
get hydrate() {
|
|
734
|
-
return this._hydrate;
|
|
735
|
-
}
|
|
736
414
|
|
|
737
|
-
shouldRefreshCache(options, cachedEntry) {
|
|
738
|
-
/**
|
|
739
|
-
* By default, the cache needs a refresh if the current entry is an
|
|
740
|
-
* error.
|
|
741
|
-
*
|
|
742
|
-
* This means that an error will cause a re-request on render.
|
|
743
|
-
* Useful if the server rendered an error, as it means the client
|
|
744
|
-
* will update after rehydration.
|
|
745
|
-
*/
|
|
746
|
-
return cachedEntry == null || cachedEntry.error != null;
|
|
747
|
-
}
|
|
748
415
|
|
|
749
|
-
getKey(options) {
|
|
750
|
-
try {
|
|
751
|
-
return options === undefined ? "undefined" : JSON.stringify(options);
|
|
752
|
-
} catch (e) {
|
|
753
|
-
throw new Error(`Failed to auto-generate key: ${e}`);
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
416
|
|
|
757
|
-
fulfillRequest(options) {
|
|
758
|
-
throw new Error("Not implemented");
|
|
759
|
-
}
|
|
760
417
|
|
|
761
|
-
}
|
|
762
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/components/track-data.js
|
|
763
418
|
|
|
764
419
|
|
|
420
|
+
const useData = (handler, options) => {
|
|
421
|
+
// If we're server-side or hydrating, we'll have a cached entry to use.
|
|
422
|
+
// So we get that and use it to initialize our state.
|
|
423
|
+
// This works in both hydration and SSR because the very first call to
|
|
424
|
+
// this will have cached data in those cases as it will be present on the
|
|
425
|
+
// initial render - and subsequent renders on the client it will be null.
|
|
426
|
+
const cachedResult = _util_response_cache_js__WEBPACK_IMPORTED_MODULE_6__[/* ResponseCache */ "a"].Default.getEntry(handler, options);
|
|
427
|
+
const [result, setResult] = Object(react__WEBPACK_IMPORTED_MODULE_1__["useState"])(cachedResult); // We only track data requests when we are server-side and we don't
|
|
428
|
+
// already have a result, as given by the cachedData (which is also the
|
|
429
|
+
// initial value for the result state).
|
|
765
430
|
|
|
431
|
+
const maybeTrack = Object(react__WEBPACK_IMPORTED_MODULE_1__["useContext"])(_util_request_tracking_js__WEBPACK_IMPORTED_MODULE_4__[/* TrackerContext */ "b"]);
|
|
766
432
|
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
if (!wonder_blocks_core_["Server"].isServerSide()) {
|
|
773
|
-
throw new Error("This component is not for use during client-side rendering");
|
|
774
|
-
}
|
|
433
|
+
if (result == null && _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide()) {
|
|
434
|
+
maybeTrack == null ? void 0 : maybeTrack(handler, options);
|
|
435
|
+
} // Lookup to see if there's an interceptor for the handler.
|
|
436
|
+
// If we have one, we need to replace the handler with one that
|
|
437
|
+
// uses the interceptor.
|
|
775
438
|
|
|
776
|
-
return /*#__PURE__*/external_react_["createElement"](TrackerContext.Provider, {
|
|
777
|
-
value: request_tracking_RequestTracker.Default.trackDataRequest
|
|
778
|
-
}, this.props.children);
|
|
779
|
-
}
|
|
780
439
|
|
|
781
|
-
|
|
782
|
-
//
|
|
440
|
+
const interceptorMap = Object(react__WEBPACK_IMPORTED_MODULE_1__["useContext"])(_components_intercept_context_js__WEBPACK_IMPORTED_MODULE_3__[/* default */ "a"]);
|
|
441
|
+
const interceptor = interceptorMap[handler.type]; // We need to update our request when the handler changes or the key
|
|
442
|
+
// to the options change, so we keep track of those.
|
|
443
|
+
// However, even if we are hydrating from cache, we still need to make the
|
|
444
|
+
// request at least once, so we do not initialize these references.
|
|
783
445
|
|
|
446
|
+
const handlerRef = Object(react__WEBPACK_IMPORTED_MODULE_1__["useRef"])();
|
|
447
|
+
const keyRef = Object(react__WEBPACK_IMPORTED_MODULE_1__["useRef"])();
|
|
448
|
+
const interceptorRef = Object(react__WEBPACK_IMPORTED_MODULE_1__["useRef"])(); // This effect will ensure that we fulfill the request as desired.
|
|
784
449
|
|
|
450
|
+
Object(react__WEBPACK_IMPORTED_MODULE_1__["useEffect"])(() => {
|
|
451
|
+
// If we are server-side, then just skip the effect. We track requests
|
|
452
|
+
// during SSR and fulfill them outside of the React render cycle.
|
|
453
|
+
// NOTE: This shouldn't happen since effects would not run on the server
|
|
454
|
+
// but let's be defensive - I think it makes the code clearer.
|
|
785
455
|
|
|
456
|
+
/* istanbul ignore next */
|
|
457
|
+
if (_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide()) {
|
|
458
|
+
return;
|
|
459
|
+
} // Update our refs to the current handler and key.
|
|
786
460
|
|
|
787
461
|
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
* INTERNAL USE ONLY
|
|
793
|
-
*/
|
|
794
|
-
class internal_data_InternalData extends external_react_["Component"] {
|
|
795
|
-
constructor(props) {
|
|
796
|
-
super(props);
|
|
797
|
-
this.state = this._buildStateAndfulfillNeeds(props);
|
|
798
|
-
}
|
|
799
|
-
|
|
800
|
-
componentDidMount() {
|
|
801
|
-
this._mounted = true;
|
|
802
|
-
}
|
|
462
|
+
handlerRef.current = handler;
|
|
463
|
+
keyRef.current = handler.getKey(options);
|
|
464
|
+
interceptorRef.current = interceptor; // If we're not hydrating a result, we want to make sure we set our
|
|
465
|
+
// result to null so that we're in the loading state.
|
|
803
466
|
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
*
|
|
808
|
-
* And we only update the state if props changed
|
|
809
|
-
* or we got new data/error.
|
|
810
|
-
*/
|
|
811
|
-
if (!this._propsMatch(nextProps)) {
|
|
812
|
-
const newState = this._buildStateAndfulfillNeeds(nextProps);
|
|
813
|
-
|
|
814
|
-
this.setState(newState);
|
|
467
|
+
if (cachedResult == null) {
|
|
468
|
+
// Mark ourselves as loading.
|
|
469
|
+
setResult(null);
|
|
815
470
|
}
|
|
816
471
|
|
|
817
|
-
|
|
818
|
-
|
|
472
|
+
const getMaybeInterceptedHandler = () => {
|
|
473
|
+
if (interceptor == null) {
|
|
474
|
+
return handler;
|
|
475
|
+
}
|
|
819
476
|
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
}
|
|
477
|
+
const fulfillRequestFn = options => {
|
|
478
|
+
var _interceptor$fulfillR;
|
|
823
479
|
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
480
|
+
return (_interceptor$fulfillR = interceptor.fulfillRequest(options)) != null ? _interceptor$fulfillR : handler.fulfillRequest(options);
|
|
481
|
+
};
|
|
482
|
+
|
|
483
|
+
return {
|
|
484
|
+
fulfillRequest: fulfillRequestFn,
|
|
485
|
+
getKey: options => handler.getKey(options),
|
|
486
|
+
type: handler.type,
|
|
487
|
+
hydrate: handler.hydrate
|
|
488
|
+
};
|
|
489
|
+
}; // We aren't server-side, so let's make the request.
|
|
490
|
+
// The request handler is in control of whether that request actually
|
|
491
|
+
// happens or not.
|
|
835
492
|
|
|
836
|
-
_buildStateAndfulfillNeeds(propsAtFulfillment) {
|
|
837
|
-
const {
|
|
838
|
-
getEntry,
|
|
839
|
-
handler,
|
|
840
|
-
options
|
|
841
|
-
} = propsAtFulfillment;
|
|
842
|
-
const cachedData = getEntry(handler, options);
|
|
843
493
|
|
|
844
|
-
|
|
494
|
+
let cancel = false;
|
|
495
|
+
_util_request_fulfillment_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestFulfillment */ "a"].Default.fulfill(getMaybeInterceptedHandler(), options).then(updateEntry => {
|
|
496
|
+
if (cancel) {
|
|
497
|
+
return;
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
setResult(updateEntry);
|
|
501
|
+
return;
|
|
502
|
+
}).catch(e => {
|
|
503
|
+
if (cancel) {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
845
506
|
/**
|
|
846
|
-
* We
|
|
847
|
-
*
|
|
848
|
-
*
|
|
849
|
-
* Therefore, we need to request data.
|
|
850
|
-
*
|
|
851
|
-
* We have to do this here from the constructor so that this
|
|
852
|
-
* data request is tracked when performing server-side rendering.
|
|
507
|
+
* We should never get here as errors in fulfillment are part
|
|
508
|
+
* of the `then`, but if we do.
|
|
853
509
|
*/
|
|
854
|
-
|
|
855
|
-
/**
|
|
856
|
-
* We get here, we should have updated the cache.
|
|
857
|
-
* However, we need to update the component, but we
|
|
858
|
-
* should only do that if the props are the same as they
|
|
859
|
-
* were when this was called.
|
|
860
|
-
*/
|
|
861
|
-
if (this._mounted && this._propsMatch(propsAtFulfillment)) {
|
|
862
|
-
this.setState({
|
|
863
|
-
loading: false,
|
|
864
|
-
data: cacheEntry.data,
|
|
865
|
-
error: cacheEntry.error
|
|
866
|
-
});
|
|
867
|
-
}
|
|
510
|
+
// eslint-disable-next-line no-console
|
|
868
511
|
|
|
869
|
-
return null;
|
|
870
|
-
}).catch(e => {
|
|
871
|
-
/**
|
|
872
|
-
* We should never get here, but if we do.
|
|
873
|
-
*/
|
|
874
|
-
// eslint-disable-next-line no-console
|
|
875
|
-
console.error(`Unexpected error occurred during data fulfillment: ${e}`);
|
|
876
|
-
|
|
877
|
-
if (this._mounted && this._propsMatch(propsAtFulfillment)) {
|
|
878
|
-
this.setState({
|
|
879
|
-
loading: false,
|
|
880
|
-
data: null,
|
|
881
|
-
error: typeof e === "string" ? e : e.message
|
|
882
|
-
});
|
|
883
|
-
}
|
|
884
512
|
|
|
885
|
-
|
|
513
|
+
console.error(`Unexpected error occurred during data fulfillment: ${e}`);
|
|
514
|
+
setResult({
|
|
515
|
+
data: null,
|
|
516
|
+
error: typeof e === "string" ? e : e.message
|
|
886
517
|
});
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
518
|
+
return;
|
|
519
|
+
});
|
|
520
|
+
return () => {
|
|
521
|
+
cancel = true;
|
|
522
|
+
}; // - handler.getKey is a proxy for options
|
|
523
|
+
// - We don't want to trigger on cachedResult changing, we're
|
|
524
|
+
// just using that as a flag for render state if the other things
|
|
525
|
+
// trigger this effect.
|
|
526
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
527
|
+
}, [handler, handler.getKey(options), interceptor]);
|
|
528
|
+
return Object(_util_result_from_cache_entry_js__WEBPACK_IMPORTED_MODULE_5__[/* resultFromCacheEntry */ "a"])(result);
|
|
529
|
+
};
|
|
896
530
|
|
|
531
|
+
/***/ }),
|
|
532
|
+
/* 6 */
|
|
533
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
897
534
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
error: cachedData && cachedData.error
|
|
902
|
-
};
|
|
903
|
-
}
|
|
535
|
+
"use strict";
|
|
536
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RequestFulfillment; });
|
|
537
|
+
/* harmony import */ var _response_cache_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(2);
|
|
904
538
|
|
|
905
|
-
_resultFromState() {
|
|
906
|
-
const {
|
|
907
|
-
loading,
|
|
908
|
-
data,
|
|
909
|
-
error
|
|
910
|
-
} = this.state;
|
|
911
539
|
|
|
912
|
-
|
|
913
|
-
return {
|
|
914
|
-
loading: true
|
|
915
|
-
};
|
|
916
|
-
}
|
|
540
|
+
let _default;
|
|
917
541
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
};
|
|
542
|
+
class RequestFulfillment {
|
|
543
|
+
static get Default() {
|
|
544
|
+
if (!_default) {
|
|
545
|
+
_default = new RequestFulfillment();
|
|
923
546
|
}
|
|
924
547
|
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
throw new Error("Loaded result has invalid state where data and error are missing");
|
|
928
|
-
}
|
|
548
|
+
return _default;
|
|
549
|
+
}
|
|
929
550
|
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
551
|
+
constructor(responseCache = undefined) {
|
|
552
|
+
this._requests = {};
|
|
553
|
+
|
|
554
|
+
this._getHandlerSubcache = handler => {
|
|
555
|
+
if (!this._requests[handler.type]) {
|
|
556
|
+
this._requests[handler.type] = {};
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
return this._requests[handler.type];
|
|
933
560
|
};
|
|
934
|
-
}
|
|
935
561
|
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
children
|
|
939
|
-
} = this.props;
|
|
940
|
-
return children(result);
|
|
941
|
-
}
|
|
562
|
+
this.fulfill = (handler, options) => {
|
|
563
|
+
const handlerRequests = this._getHandlerSubcache(handler);
|
|
942
564
|
|
|
943
|
-
|
|
944
|
-
return /*#__PURE__*/external_react_["createElement"](TrackerContext.Consumer, null, track => {
|
|
565
|
+
const key = handler.getKey(options);
|
|
945
566
|
/**
|
|
946
|
-
* If
|
|
567
|
+
* If we have an inflight request, we'll provide that.
|
|
947
568
|
*/
|
|
948
|
-
|
|
949
|
-
|
|
569
|
+
|
|
570
|
+
const inflight = handlerRequests[key];
|
|
571
|
+
|
|
572
|
+
if (inflight) {
|
|
573
|
+
return inflight;
|
|
950
574
|
}
|
|
575
|
+
/**
|
|
576
|
+
* We don't have an inflight request, so let's set one up.
|
|
577
|
+
*/
|
|
951
578
|
|
|
952
|
-
return this._renderContent(result);
|
|
953
|
-
});
|
|
954
|
-
}
|
|
955
579
|
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
580
|
+
const {
|
|
581
|
+
cacheData,
|
|
582
|
+
cacheError
|
|
583
|
+
} = this._responseCache;
|
|
960
584
|
|
|
585
|
+
try {
|
|
586
|
+
const request = handler.fulfillRequest(options).then(data => {
|
|
587
|
+
delete handlerRequests[key];
|
|
588
|
+
/**
|
|
589
|
+
* Let's cache the data!
|
|
590
|
+
*
|
|
591
|
+
* NOTE: This only caches when we're server side.
|
|
592
|
+
*/
|
|
961
593
|
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
594
|
+
return cacheData(handler, options, data);
|
|
595
|
+
}).catch(error => {
|
|
596
|
+
delete handlerRequests[key];
|
|
597
|
+
/**
|
|
598
|
+
* Let's cache the error!
|
|
599
|
+
*
|
|
600
|
+
* NOTE: This only caches when we're server side.
|
|
601
|
+
*/
|
|
965
602
|
|
|
966
|
-
|
|
603
|
+
return cacheError(handler, options, error);
|
|
604
|
+
});
|
|
605
|
+
handlerRequests[key] = request;
|
|
606
|
+
return request;
|
|
607
|
+
} catch (e) {
|
|
608
|
+
/**
|
|
609
|
+
* In this case, we don't cache an inflight request, because there
|
|
610
|
+
* really isn't one.
|
|
611
|
+
*/
|
|
612
|
+
return Promise.resolve(cacheError(handler, options, e));
|
|
613
|
+
}
|
|
614
|
+
};
|
|
615
|
+
|
|
616
|
+
this._responseCache = responseCache || _response_cache_js__WEBPACK_IMPORTED_MODULE_0__[/* ResponseCache */ "a"].Default;
|
|
967
617
|
}
|
|
968
618
|
|
|
969
619
|
}
|
|
970
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/components/intercept-context.js
|
|
971
620
|
|
|
621
|
+
/***/ }),
|
|
622
|
+
/* 7 */
|
|
623
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
972
624
|
|
|
625
|
+
"use strict";
|
|
626
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return MemoryCache; });
|
|
627
|
+
function deepClone(source) {
|
|
628
|
+
/**
|
|
629
|
+
* We want to deep clone the source cache to dodge mutations by external
|
|
630
|
+
* references. So we serialize the source cache to JSON and parse it
|
|
631
|
+
* back into a new object.
|
|
632
|
+
*
|
|
633
|
+
* NOTE: This doesn't work for get/set property accessors.
|
|
634
|
+
*/
|
|
635
|
+
const serializedInitCache = JSON.stringify(source);
|
|
636
|
+
const cloneInitCache = JSON.parse(serializedInitCache);
|
|
637
|
+
return Object.freeze(cloneInitCache);
|
|
638
|
+
}
|
|
973
639
|
/**
|
|
974
|
-
* InterceptContext defines a map from handler type to interception methods.
|
|
975
|
-
*
|
|
976
640
|
* INTERNAL USE ONLY
|
|
641
|
+
*
|
|
642
|
+
* Special case cache implementation for the memory cache.
|
|
643
|
+
*
|
|
644
|
+
* This is only used within our framework for SSR (see ./response-cache.js).
|
|
977
645
|
*/
|
|
978
|
-
const InterceptContext = /*#__PURE__*/external_react_["createContext"]({});
|
|
979
|
-
/* harmony default export */ var intercept_context = (InterceptContext);
|
|
980
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/components/data.js
|
|
981
646
|
|
|
982
647
|
|
|
648
|
+
class MemoryCache {
|
|
649
|
+
constructor(source = null) {
|
|
650
|
+
this.store = (handler, options, entry) => {
|
|
651
|
+
const requestType = handler.type;
|
|
652
|
+
const frozenEntry = Object.freeze(entry); // Ensure we have a cache location for this handler type.
|
|
653
|
+
|
|
654
|
+
this._cache[requestType] = this._cache[requestType] || {}; // Cache the data.
|
|
655
|
+
|
|
656
|
+
const key = handler.getKey(options);
|
|
657
|
+
this._cache[requestType][key] = frozenEntry;
|
|
658
|
+
};
|
|
659
|
+
|
|
660
|
+
this.retrieve = (handler, options) => {
|
|
661
|
+
const requestType = handler.type; // Get the internal subcache for the handler.
|
|
662
|
+
|
|
663
|
+
const handlerCache = this._cache[requestType];
|
|
664
|
+
|
|
665
|
+
if (!handlerCache) {
|
|
666
|
+
return null;
|
|
667
|
+
} // Get the response.
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
const key = handler.getKey(options);
|
|
671
|
+
const internalEntry = handlerCache[key];
|
|
672
|
+
|
|
673
|
+
if (internalEntry == null) {
|
|
674
|
+
return null;
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
return internalEntry;
|
|
678
|
+
};
|
|
679
|
+
|
|
680
|
+
this.remove = (handler, options) => {
|
|
681
|
+
const requestType = handler.type; // NOTE(somewhatabstract): We could invoke removeAll with a predicate
|
|
682
|
+
// to match the key of the entry we're removing, but that's an
|
|
683
|
+
// inefficient way to remove a single item, so let's not do that.
|
|
684
|
+
// Get the internal subcache for the handler.
|
|
685
|
+
|
|
686
|
+
const handlerCache = this._cache[requestType];
|
|
687
|
+
|
|
688
|
+
if (!handlerCache) {
|
|
689
|
+
return false;
|
|
690
|
+
} // Get the entry.
|
|
691
|
+
|
|
692
|
+
|
|
693
|
+
const key = handler.getKey(options);
|
|
694
|
+
const internalEntry = handlerCache[key];
|
|
695
|
+
|
|
696
|
+
if (internalEntry == null) {
|
|
697
|
+
return false;
|
|
698
|
+
} // Delete the entry.
|
|
699
|
+
|
|
700
|
+
|
|
701
|
+
delete handlerCache[key];
|
|
702
|
+
return true;
|
|
703
|
+
};
|
|
983
704
|
|
|
705
|
+
this.removeAll = (handler, predicate) => {
|
|
706
|
+
const requestType = handler.type; // Get the internal subcache for the handler.
|
|
984
707
|
|
|
708
|
+
const handlerCache = this._cache[requestType];
|
|
709
|
+
|
|
710
|
+
if (!handlerCache) {
|
|
711
|
+
return 0;
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
let removedCount = 0;
|
|
985
715
|
|
|
716
|
+
if (typeof predicate === "function") {
|
|
717
|
+
// Apply the predicate to what we have cached.
|
|
718
|
+
for (const [key, entry] of Object.entries(handlerCache)) {
|
|
719
|
+
if (predicate(key, entry)) {
|
|
720
|
+
removedCount++;
|
|
721
|
+
delete handlerCache[key];
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
} else {
|
|
725
|
+
// We're removing everything so delete the entire subcache.
|
|
726
|
+
removedCount = Object.keys(handlerCache).length;
|
|
727
|
+
delete this._cache[requestType];
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
return removedCount;
|
|
731
|
+
};
|
|
732
|
+
|
|
733
|
+
this.cloneData = () => {
|
|
734
|
+
try {
|
|
735
|
+
return deepClone(this._cache);
|
|
736
|
+
} catch (e) {
|
|
737
|
+
throw new Error(`An error occurred while trying to clone the cache: ${e}`);
|
|
738
|
+
}
|
|
739
|
+
};
|
|
740
|
+
|
|
741
|
+
this._cache = {};
|
|
742
|
+
|
|
743
|
+
if (source != null) {
|
|
744
|
+
try {
|
|
745
|
+
/**
|
|
746
|
+
* Object.assign only performs a shallow clone.
|
|
747
|
+
* So we deep clone it and then assign the clone values to our
|
|
748
|
+
* internal cache.
|
|
749
|
+
*/
|
|
750
|
+
const cloneInitCache = deepClone(source);
|
|
751
|
+
Object.assign(this._cache, cloneInitCache);
|
|
752
|
+
} catch (e) {
|
|
753
|
+
throw new Error(`An error occurred trying to initialize from a response cache snapshot: ${e}`);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
/**
|
|
758
|
+
* Indicate if this cache is being used or now.
|
|
759
|
+
*
|
|
760
|
+
* When the cache has entries, returns `true`; otherwise, returns `false`.
|
|
761
|
+
*/
|
|
762
|
+
|
|
763
|
+
|
|
764
|
+
get inUse() {
|
|
765
|
+
return Object.keys(this._cache).length > 0;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/***/ }),
|
|
771
|
+
/* 8 */
|
|
772
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
773
|
+
|
|
774
|
+
"use strict";
|
|
775
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return RequestHandler; });
|
|
986
776
|
/**
|
|
987
|
-
*
|
|
988
|
-
*
|
|
989
|
-
*
|
|
777
|
+
* Base implementation for creating a request handler.
|
|
778
|
+
*
|
|
779
|
+
* Provides a base implementation of the `IRequestHandler` base class for
|
|
780
|
+
* use with the Wonder Blocks Data framework.
|
|
990
781
|
*/
|
|
991
|
-
class
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
if (!interceptor) {
|
|
998
|
-
return handler;
|
|
999
|
-
}
|
|
782
|
+
class RequestHandler {
|
|
783
|
+
constructor(type, hydrate = true) {
|
|
784
|
+
this._type = type;
|
|
785
|
+
this._hydrate = !!hydrate;
|
|
786
|
+
}
|
|
1000
787
|
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
shouldRefreshCache
|
|
1004
|
-
} = interceptor;
|
|
1005
|
-
const fulfillRequestFn = fulfillRequest ? options => {
|
|
1006
|
-
const interceptedResult = fulfillRequest(options);
|
|
1007
|
-
return interceptedResult != null ? interceptedResult : handler.fulfillRequest(options);
|
|
1008
|
-
} : options => handler.fulfillRequest(options);
|
|
1009
|
-
const shouldRefreshCacheFn = shouldRefreshCache ? (options, cacheEntry) => {
|
|
1010
|
-
const interceptedResult = shouldRefreshCache(options, cacheEntry);
|
|
1011
|
-
return interceptedResult != null ? interceptedResult : handler.shouldRefreshCache(options, cacheEntry);
|
|
1012
|
-
} : (options, cacheEntry) => handler.shouldRefreshCache(options, cacheEntry);
|
|
1013
|
-
return {
|
|
1014
|
-
fulfillRequest: fulfillRequestFn,
|
|
1015
|
-
shouldRefreshCache: shouldRefreshCacheFn,
|
|
1016
|
-
getKey: options => handler.getKey(options),
|
|
1017
|
-
type: handler.type,
|
|
1018
|
-
cache: handler.cache,
|
|
1019
|
-
hydrate: handler.hydrate
|
|
1020
|
-
};
|
|
788
|
+
get type() {
|
|
789
|
+
return this._type;
|
|
1021
790
|
}
|
|
1022
791
|
|
|
1023
|
-
|
|
1024
|
-
|
|
792
|
+
get hydrate() {
|
|
793
|
+
return this._hydrate;
|
|
794
|
+
}
|
|
1025
795
|
|
|
1026
|
-
|
|
1027
|
-
|
|
796
|
+
getKey(options) {
|
|
797
|
+
try {
|
|
798
|
+
return options === undefined ? "undefined" : JSON.stringify(options);
|
|
799
|
+
} catch (e) {
|
|
800
|
+
throw new Error(`Failed to auto-generate key: ${e}`);
|
|
1028
801
|
}
|
|
802
|
+
}
|
|
1029
803
|
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
804
|
+
fulfillRequest(options) {
|
|
805
|
+
throw new Error("Not implemented");
|
|
806
|
+
}
|
|
1033
807
|
|
|
1034
|
-
|
|
808
|
+
}
|
|
1035
809
|
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
810
|
+
/***/ }),
|
|
811
|
+
/* 9 */
|
|
812
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1039
813
|
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
814
|
+
"use strict";
|
|
815
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return TrackData; });
|
|
816
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
817
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
818
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(1);
|
|
819
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__);
|
|
820
|
+
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
1044
821
|
|
|
1045
|
-
const handler = this._getHandlerFromInterceptor(interceptor);
|
|
1046
822
|
|
|
1047
|
-
const getEntry = this._getCacheLookupFnFromInterceptor(interceptor);
|
|
1048
|
-
/**
|
|
1049
|
-
* Need to share our types with InternalData so Flow
|
|
1050
|
-
* doesn't need to infer them and find mismatches.
|
|
1051
|
-
* However, just deriving a new component creates issues
|
|
1052
|
-
* where InternalData starts rerendering too often.
|
|
1053
|
-
* Couldn't track down why, so suppressing the error
|
|
1054
|
-
* instead.
|
|
1055
|
-
*/
|
|
1056
823
|
|
|
1057
824
|
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
825
|
+
/**
|
|
826
|
+
* Component to enable data request tracking when server-side rendering.
|
|
827
|
+
*/
|
|
828
|
+
class TrackData extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
829
|
+
render() {
|
|
830
|
+
if (!_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_1__["Server"].isServerSide()) {
|
|
831
|
+
throw new Error("This component is not for use during client-side rendering");
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__[/* TrackerContext */ "b"].Provider, {
|
|
835
|
+
value: _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestTracker */ "a"].Default.trackDataRequest
|
|
836
|
+
}, this.props.children);
|
|
1065
837
|
}
|
|
1066
838
|
|
|
1067
839
|
}
|
|
1068
|
-
// EXTERNAL MODULE: ./node_modules/@babel/runtime/helpers/extends.js
|
|
1069
|
-
var helpers_extends = __webpack_require__(2);
|
|
1070
|
-
var extends_default = /*#__PURE__*/__webpack_require__.n(helpers_extends);
|
|
1071
840
|
|
|
1072
|
-
|
|
841
|
+
/***/ }),
|
|
842
|
+
/* 10 */
|
|
843
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1073
844
|
|
|
845
|
+
"use strict";
|
|
846
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
847
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
848
|
+
/* harmony import */ var _hooks_use_data_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(5);
|
|
849
|
+
|
|
850
|
+
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* This component is the main component of Wonder Blocks Data. With this, data
|
|
854
|
+
* requirements can be placed in a React application in a manner that will
|
|
855
|
+
* support server-side rendering and efficient caching.
|
|
856
|
+
*/
|
|
857
|
+
const Data = props => {
|
|
858
|
+
const data = Object(_hooks_use_data_js__WEBPACK_IMPORTED_MODULE_1__[/* useData */ "a"])(props.handler, props.options);
|
|
859
|
+
return props.children(data);
|
|
860
|
+
};
|
|
861
|
+
|
|
862
|
+
/* harmony default export */ __webpack_exports__["a"] = (Data);
|
|
863
|
+
|
|
864
|
+
/***/ }),
|
|
865
|
+
/* 11 */
|
|
866
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
867
|
+
|
|
868
|
+
"use strict";
|
|
869
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return InterceptData; });
|
|
870
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(0);
|
|
871
|
+
/* harmony import */ var react__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(react__WEBPACK_IMPORTED_MODULE_0__);
|
|
872
|
+
/* harmony import */ var _intercept_context_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(4);
|
|
1074
873
|
|
|
1075
874
|
|
|
1076
875
|
|
|
@@ -1079,9 +878,6 @@ var extends_default = /*#__PURE__*/__webpack_require__.n(helpers_extends);
|
|
|
1079
878
|
* type of a given handler and provide alternative results. This is mostly
|
|
1080
879
|
* useful for testing.
|
|
1081
880
|
*
|
|
1082
|
-
* Results from this interceptor will end up in the cache. If you
|
|
1083
|
-
* wish to only override the cache, use `InterceptCache` instead.
|
|
1084
|
-
*
|
|
1085
881
|
* This component is not recommended for use in production code as it
|
|
1086
882
|
* can prevent predictable functioning of the Wonder Blocks Data framework.
|
|
1087
883
|
* One possible side-effect is that inflight requests from the interceptor could
|
|
@@ -1093,88 +889,117 @@ var extends_default = /*#__PURE__*/__webpack_require__.n(helpers_extends);
|
|
|
1093
889
|
* new instance will replace this interceptor for its children. All methods
|
|
1094
890
|
* will be replaced.
|
|
1095
891
|
*/
|
|
1096
|
-
class
|
|
892
|
+
class InterceptData extends react__WEBPACK_IMPORTED_MODULE_0__["Component"] {
|
|
1097
893
|
render() {
|
|
1098
|
-
return /*#__PURE__*/
|
|
894
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_intercept_context_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"].Consumer, null, value => {
|
|
1099
895
|
const handlerType = this.props.handler.type;
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
});
|
|
1105
|
-
|
|
1106
|
-
const newValue = extends_default()({}, value, {
|
|
896
|
+
const interceptor = { ...value[handlerType],
|
|
897
|
+
fulfillRequest: this.props.fulfillRequest
|
|
898
|
+
};
|
|
899
|
+
const newValue = { ...value,
|
|
1107
900
|
[handlerType]: interceptor
|
|
1108
|
-
}
|
|
1109
|
-
|
|
1110
|
-
return /*#__PURE__*/external_react_["createElement"](intercept_context.Provider, {
|
|
901
|
+
};
|
|
902
|
+
return /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_0__["createElement"](_intercept_context_js__WEBPACK_IMPORTED_MODULE_1__[/* default */ "a"].Provider, {
|
|
1111
903
|
value: newValue
|
|
1112
904
|
}, this.props.children);
|
|
1113
905
|
});
|
|
1114
906
|
}
|
|
1115
907
|
|
|
1116
908
|
}
|
|
1117
|
-
// CONCATENATED MODULE: ./packages/wonder-blocks-data/src/components/intercept-cache.js
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
909
|
|
|
910
|
+
/***/ }),
|
|
911
|
+
/* 12 */
|
|
912
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
1121
913
|
|
|
914
|
+
"use strict";
|
|
915
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return resultFromCacheEntry; });
|
|
1122
916
|
/**
|
|
1123
|
-
*
|
|
1124
|
-
* type of a given handler and provide alternative values. This is mostly
|
|
1125
|
-
* useful for testing.
|
|
1126
|
-
*
|
|
1127
|
-
* This does not modify the cache in any way. If you want to intercept
|
|
1128
|
-
* requests and cache based on the intercept, then use `InterceptData`.
|
|
1129
|
-
*
|
|
1130
|
-
* This component is generally not suitable for use in production code as it
|
|
1131
|
-
* can prevent predictable functioning of the Wonder Blocks Data framework.
|
|
1132
|
-
*
|
|
1133
|
-
* These components do not chain. If a different `InterceptCache` instance is
|
|
1134
|
-
* rendered within this one that intercepts the same handler type, then that
|
|
1135
|
-
* new instance will replace this interceptor for its children.
|
|
917
|
+
* Turns a cache entry into a stateful result.
|
|
1136
918
|
*/
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
919
|
+
const resultFromCacheEntry = cacheEntry => {
|
|
920
|
+
// No cache entry means we didn't load one yet.
|
|
921
|
+
if (cacheEntry == null) {
|
|
922
|
+
return {
|
|
923
|
+
status: "loading"
|
|
924
|
+
};
|
|
925
|
+
}
|
|
1141
926
|
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
927
|
+
const {
|
|
928
|
+
data,
|
|
929
|
+
error
|
|
930
|
+
} = cacheEntry;
|
|
1145
931
|
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
932
|
+
if (data != null) {
|
|
933
|
+
return {
|
|
934
|
+
status: "success",
|
|
935
|
+
data
|
|
936
|
+
};
|
|
937
|
+
}
|
|
1149
938
|
|
|
1150
|
-
|
|
1151
|
-
|
|
1152
|
-
|
|
1153
|
-
|
|
939
|
+
if (error == null) {
|
|
940
|
+
// We should never get here ever.
|
|
941
|
+
return {
|
|
942
|
+
status: "error",
|
|
943
|
+
error: "Loaded result has invalid state where data and error are missing"
|
|
944
|
+
};
|
|
1154
945
|
}
|
|
1155
946
|
|
|
1156
|
-
|
|
1157
|
-
|
|
947
|
+
return {
|
|
948
|
+
status: "error",
|
|
949
|
+
error
|
|
950
|
+
};
|
|
951
|
+
};
|
|
1158
952
|
|
|
953
|
+
/***/ }),
|
|
954
|
+
/* 13 */
|
|
955
|
+
/***/ (function(module, __webpack_exports__, __webpack_require__) {
|
|
956
|
+
|
|
957
|
+
"use strict";
|
|
958
|
+
__webpack_require__.r(__webpack_exports__);
|
|
959
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "initializeCache", function() { return initializeCache; });
|
|
960
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "fulfillAllDataRequests", function() { return fulfillAllDataRequests; });
|
|
961
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "hasUnfulfilledRequests", function() { return hasUnfulfilledRequests; });
|
|
962
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeFromCache", function() { return removeFromCache; });
|
|
963
|
+
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "removeAllFromCache", function() { return removeAllFromCache; });
|
|
964
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(1);
|
|
965
|
+
/* harmony import */ var _khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__);
|
|
966
|
+
/* harmony import */ var _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(2);
|
|
967
|
+
/* harmony import */ var _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(3);
|
|
968
|
+
/* harmony import */ var _util_request_handler_js__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(8);
|
|
969
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "RequestHandler", function() { return _util_request_handler_js__WEBPACK_IMPORTED_MODULE_3__["a"]; });
|
|
970
|
+
|
|
971
|
+
/* harmony import */ var _components_track_data_js__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(9);
|
|
972
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "TrackData", function() { return _components_track_data_js__WEBPACK_IMPORTED_MODULE_4__["a"]; });
|
|
1159
973
|
|
|
974
|
+
/* harmony import */ var _components_data_js__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(10);
|
|
975
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "Data", function() { return _components_data_js__WEBPACK_IMPORTED_MODULE_5__["a"]; });
|
|
1160
976
|
|
|
1161
|
-
|
|
977
|
+
/* harmony import */ var _components_intercept_data_js__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(11);
|
|
978
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "InterceptData", function() { return _components_intercept_data_js__WEBPACK_IMPORTED_MODULE_6__["a"]; });
|
|
979
|
+
|
|
980
|
+
/* harmony import */ var _hooks_use_data_js__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(5);
|
|
981
|
+
/* harmony reexport (safe) */ __webpack_require__.d(__webpack_exports__, "useData", function() { return _hooks_use_data_js__WEBPACK_IMPORTED_MODULE_7__["a"]; });
|
|
982
|
+
|
|
983
|
+
|
|
984
|
+
|
|
985
|
+
|
|
986
|
+
const initializeCache = source => _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* ResponseCache */ "a"].Default.initialize(source);
|
|
1162
987
|
const fulfillAllDataRequests = () => {
|
|
1163
|
-
if (!
|
|
988
|
+
if (!_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide()) {
|
|
1164
989
|
return Promise.reject(new Error("Data requests are not tracked when client-side"));
|
|
1165
990
|
}
|
|
1166
991
|
|
|
1167
|
-
return
|
|
992
|
+
return _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestTracker */ "a"].Default.fulfillTrackedRequests();
|
|
1168
993
|
};
|
|
1169
994
|
const hasUnfulfilledRequests = () => {
|
|
1170
|
-
if (!
|
|
995
|
+
if (!_khanacademy_wonder_blocks_core__WEBPACK_IMPORTED_MODULE_0__["Server"].isServerSide()) {
|
|
1171
996
|
throw new Error("Data requests are not tracked when client-side");
|
|
1172
997
|
}
|
|
1173
998
|
|
|
1174
|
-
return
|
|
999
|
+
return _util_request_tracking_js__WEBPACK_IMPORTED_MODULE_2__[/* RequestTracker */ "a"].Default.hasUnfulfilledRequests;
|
|
1175
1000
|
};
|
|
1176
|
-
const removeFromCache = (handler, options) =>
|
|
1177
|
-
const removeAllFromCache = (handler, predicate) =>
|
|
1001
|
+
const removeFromCache = (handler, options) => _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* ResponseCache */ "a"].Default.remove(handler, options);
|
|
1002
|
+
const removeAllFromCache = (handler, predicate) => _util_response_cache_js__WEBPACK_IMPORTED_MODULE_1__[/* ResponseCache */ "a"].Default.removeAll(handler, predicate);
|
|
1178
1003
|
/**
|
|
1179
1004
|
* TODO(somewhatabstract): Export each cache type we implement.
|
|
1180
1005
|
*
|
|
@@ -1187,6 +1012,5 @@ const removeAllFromCache = (handler, predicate) => response_cache_ResponseCache.
|
|
|
1187
1012
|
|
|
1188
1013
|
|
|
1189
1014
|
|
|
1190
|
-
|
|
1191
1015
|
/***/ })
|
|
1192
1016
|
/******/ ]);
|