Spaces:
Running
Running
File size: 6,406 Bytes
c592d77 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | "use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
Object.defineProperty(exports, "AfterContext", {
enumerable: true,
get: function() {
return AfterContext;
}
});
const _pqueue = /*#__PURE__*/ _interop_require_default(require("next/dist/compiled/p-queue"));
const _invarianterror = require("../../shared/lib/invariant-error");
const _isthenable = require("../../shared/lib/is-thenable");
const _workasyncstorageexternal = require("../app-render/work-async-storage.external");
const _revalidationutils = require("../revalidation-utils");
const _asynclocalstorage = require("../app-render/async-local-storage");
const _workunitasyncstorageexternal = require("../app-render/work-unit-async-storage.external");
const _aftertaskasyncstorageexternal = require("../app-render/after-task-async-storage.external");
function _interop_require_default(obj) {
return obj && obj.__esModule ? obj : {
default: obj
};
}
class AfterContext {
constructor({ waitUntil, onClose, onTaskError }){
this.workUnitStores = new Set();
this.waitUntil = waitUntil;
this.onClose = onClose;
this.onTaskError = onTaskError;
this.callbackQueue = new _pqueue.default();
this.callbackQueue.pause();
}
after(task) {
if ((0, _isthenable.isThenable)(task)) {
if (!this.waitUntil) {
errorWaitUntilNotAvailable();
}
this.waitUntil(task.catch((error)=>this.reportTaskError('promise', error)));
} else if (typeof task === 'function') {
// TODO(after): implement tracing
this.addCallback(task);
} else {
throw Object.defineProperty(new Error('`after()`: Argument must be a promise or a function'), "__NEXT_ERROR_CODE", {
value: "E50",
enumerable: false,
configurable: true
});
}
}
addCallback(callback) {
// if something is wrong, throw synchronously, bubbling up to the `after` callsite.
if (!this.waitUntil) {
errorWaitUntilNotAvailable();
}
const workUnitStore = _workunitasyncstorageexternal.workUnitAsyncStorage.getStore();
if (workUnitStore) {
this.workUnitStores.add(workUnitStore);
}
const afterTaskStore = _aftertaskasyncstorageexternal.afterTaskAsyncStorage.getStore();
// This is used for checking if request APIs can be called inside `after`.
// Note that we need to check the phase in which the *topmost* `after` was called (which should be "action"),
// not the current phase (which might be "after" if we're in a nested after).
// Otherwise, we might allow `after(() => headers())`, but not `after(() => after(() => headers()))`.
const rootTaskSpawnPhase = afterTaskStore ? afterTaskStore.rootTaskSpawnPhase // nested after
: workUnitStore == null ? void 0 : workUnitStore.phase // topmost after
;
// this should only happen once.
if (!this.runCallbacksOnClosePromise) {
this.runCallbacksOnClosePromise = this.runCallbacksOnClose();
this.waitUntil(this.runCallbacksOnClosePromise);
}
// Bind the callback to the current execution context (i.e. preserve all currently available ALS-es).
// We do this because we want all of these to be equivalent in every regard except timing:
// after(() => x())
// after(x())
// await x()
const wrappedCallback = (0, _asynclocalstorage.bindSnapshot)(// WARNING: Don't make this a named function. It must be anonymous.
// See: https://github.com/facebook/react/pull/34911
async ()=>{
try {
await _aftertaskasyncstorageexternal.afterTaskAsyncStorage.run({
rootTaskSpawnPhase
}, ()=>callback());
} catch (error) {
this.reportTaskError('function', error);
}
});
this.callbackQueue.add(wrappedCallback);
}
async runCallbacksOnClose() {
await new Promise((resolve)=>this.onClose(resolve));
return this.runCallbacks();
}
async runCallbacks() {
if (this.callbackQueue.size === 0) return;
for (const workUnitStore of this.workUnitStores){
workUnitStore.phase = 'after';
}
const workStore = _workasyncstorageexternal.workAsyncStorage.getStore();
if (!workStore) {
throw Object.defineProperty(new _invarianterror.InvariantError('Missing workStore in AfterContext.runCallbacks'), "__NEXT_ERROR_CODE", {
value: "E547",
enumerable: false,
configurable: true
});
}
return (0, _revalidationutils.withExecuteRevalidates)(workStore, ()=>{
this.callbackQueue.start();
return this.callbackQueue.onIdle();
});
}
reportTaskError(taskKind, error) {
// TODO(after): this is fine for now, but will need better intergration with our error reporting.
// TODO(after): should we log this if we have a onTaskError callback?
console.error(taskKind === 'promise' ? `A promise passed to \`after()\` rejected:` : `An error occurred in a function passed to \`after()\`:`, error);
if (this.onTaskError) {
// this is very defensive, but we really don't want anything to blow up in an error handler
try {
this.onTaskError == null ? void 0 : this.onTaskError.call(this, error);
} catch (handlerError) {
console.error(Object.defineProperty(new _invarianterror.InvariantError('`onTaskError` threw while handling an error thrown from an `after` task', {
cause: handlerError
}), "__NEXT_ERROR_CODE", {
value: "E569",
enumerable: false,
configurable: true
}));
}
}
}
}
function errorWaitUntilNotAvailable() {
throw Object.defineProperty(new Error('`after()` will not work correctly, because `waitUntil` is not available in the current environment.'), "__NEXT_ERROR_CODE", {
value: "E91",
enumerable: false,
configurable: true
});
}
//# sourceMappingURL=after-context.js.map |