138 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			138 lines
		
	
	
		
			6.1 KiB
		
	
	
	
		
			JavaScript
		
	
	
		
			Executable File
		
	
	
	
	
"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)(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
 |