File size: 22,740 Bytes
f9f0fec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
/**
 * We strongly discourage the use of the `async_hooks` API.
 * Other APIs that can cover most of its use cases include:
 *
 * * `AsyncLocalStorage` tracks async context
 * * `process.getActiveResourcesInfo()` tracks active resources
 *
 * The `node:async_hooks` module provides an API to track asynchronous resources.
 * It can be accessed using:
 *
 * ```js
 * import async_hooks from 'node:async_hooks';
 * ```
 * @experimental
 * @see [source](https://github.com/nodejs/node/blob/v20.2.0/lib/async_hooks.js)
 */
declare module "async_hooks" {
    /**
     * ```js
     * import { executionAsyncId } from 'node:async_hooks';
     * import fs from 'node:fs';
     *
     * console.log(executionAsyncId());  // 1 - bootstrap
     * const path = '.';
     * fs.open(path, 'r', (err, fd) => {
     *   console.log(executionAsyncId());  // 6 - open()
     * });
     * ```
     *
     * The ID returned from `executionAsyncId()` is related to execution timing, not
     * causality (which is covered by `triggerAsyncId()`):
     *
     * ```js
     * const server = net.createServer((conn) => {
     *   // Returns the ID of the server, not of the new connection, because the
     *   // callback runs in the execution scope of the server's MakeCallback().
     *   async_hooks.executionAsyncId();
     *
     * }).listen(port, () => {
     *   // Returns the ID of a TickObject (process.nextTick()) because all
     *   // callbacks passed to .listen() are wrapped in a nextTick().
     *   async_hooks.executionAsyncId();
     * });
     * ```
     *
     * Promise contexts may not get precise `executionAsyncIds` by default.
     * See the section on `promise execution tracking`.
     * @since v8.1.0
     * @return The `asyncId` of the current execution context. Useful to track when something calls.
     */
    function executionAsyncId(): number;
    /**
     * Resource objects returned by `executionAsyncResource()` are most often internal
     * Node.js handle objects with undocumented APIs. Using any functions or properties
     * on the object is likely to crash your application and should be avoided.
     *
     * Using `executionAsyncResource()` in the top-level execution context will
     * return an empty object as there is no handle or request object to use,
     * but having an object representing the top-level can be helpful.
     *
     * ```js
     * import { open } from 'node:fs';
     * import { executionAsyncId, executionAsyncResource } from 'node:async_hooks';
     *
     * console.log(executionAsyncId(), executionAsyncResource());  // 1 {}
     * open(new URL(import.meta.url), 'r', (err, fd) => {
     *   console.log(executionAsyncId(), executionAsyncResource());  // 7 FSReqWrap
     * });
     * ```
     *
     * This can be used to implement continuation local storage without the
     * use of a tracking `Map` to store the metadata:
     *
     * ```js
     * import { createServer } from 'node:http';
     * import {
     *   executionAsyncId,
     *   executionAsyncResource,
     *   createHook,
     * } from 'async_hooks';
     * const sym = Symbol('state'); // Private symbol to avoid pollution
     *
     * createHook({
     *   init(asyncId, type, triggerAsyncId, resource) {
     *     const cr = executionAsyncResource();
     *     if (cr) {
     *       resource[sym] = cr[sym];
     *     }
     *   },
     * }).enable();
     *
     * const server = createServer((req, res) => {
     *   executionAsyncResource()[sym] = { state: req.url };
     *   setTimeout(function() {
     *     res.end(JSON.stringify(executionAsyncResource()[sym]));
     *   }, 100);
     * }).listen(3000);
     * ```
     * @since v13.9.0, v12.17.0
     * @return The resource representing the current execution. Useful to store data within the resource.
     */
    function executionAsyncResource(): object;
    /**
     * ```js
     * const server = net.createServer((conn) => {
     *   // The resource that caused (or triggered) this callback to be called
     *   // was that of the new connection. Thus the return value of triggerAsyncId()
     *   // is the asyncId of "conn".
     *   async_hooks.triggerAsyncId();
     *
     * }).listen(port, () => {
     *   // Even though all callbacks passed to .listen() are wrapped in a nextTick()
     *   // the callback itself exists because the call to the server's .listen()
     *   // was made. So the return value would be the ID of the server.
     *   async_hooks.triggerAsyncId();
     * });
     * ```
     *
     * Promise contexts may not get valid `triggerAsyncId`s by default. See
     * the section on `promise execution tracking`.
     * @return The ID of the resource responsible for calling the callback that is currently being executed.
     */
    function triggerAsyncId(): number;
    interface HookCallbacks {
        /**
         * Called when a class is constructed that has the possibility to emit an asynchronous event.
         * @param asyncId a unique ID for the async resource
         * @param type the type of the async resource
         * @param triggerAsyncId the unique ID of the async resource in whose execution context this async resource was created
         * @param resource reference to the resource representing the async operation, needs to be released during destroy
         */
        init?(asyncId: number, type: string, triggerAsyncId: number, resource: object): void;
        /**
         * When an asynchronous operation is initiated or completes a callback is called to notify the user.
         * The before callback is called just before said callback is executed.
         * @param asyncId the unique identifier assigned to the resource about to execute the callback.
         */
        before?(asyncId: number): void;
        /**
         * Called immediately after the callback specified in before is completed.
         * @param asyncId the unique identifier assigned to the resource which has executed the callback.
         */
        after?(asyncId: number): void;
        /**
         * Called when a promise has resolve() called. This may not be in the same execution id
         * as the promise itself.
         * @param asyncId the unique id for the promise that was resolve()d.
         */
        promiseResolve?(asyncId: number): void;
        /**
         * Called after the resource corresponding to asyncId is destroyed
         * @param asyncId a unique ID for the async resource
         */
        destroy?(asyncId: number): void;
    }
    interface AsyncHook {
        /**
         * Enable the callbacks for a given AsyncHook instance. If no callbacks are provided enabling is a noop.
         */
        enable(): this;
        /**
         * Disable the callbacks for a given AsyncHook instance from the global pool of AsyncHook callbacks to be executed. Once a hook has been disabled it will not be called again until enabled.
         */
        disable(): this;
    }
    /**
     * Registers functions to be called for different lifetime events of each async
     * operation.
     *
     * The callbacks `init()`/`before()`/`after()`/`destroy()` are called for the
     * respective asynchronous event during a resource's lifetime.
     *
     * All callbacks are optional. For example, if only resource cleanup needs to
     * be tracked, then only the `destroy` callback needs to be passed. The
     * specifics of all functions that can be passed to `callbacks` is in the `Hook Callbacks` section.
     *
     * ```js
     * import { createHook } from 'node:async_hooks';
     *
     * const asyncHook = createHook({
     *   init(asyncId, type, triggerAsyncId, resource) { },
     *   destroy(asyncId) { },
     * });
     * ```
     *
     * The callbacks will be inherited via the prototype chain:
     *
     * ```js
     * class MyAsyncCallbacks {
     *   init(asyncId, type, triggerAsyncId, resource) { }
     *   destroy(asyncId) {}
     * }
     *
     * class MyAddedCallbacks extends MyAsyncCallbacks {
     *   before(asyncId) { }
     *   after(asyncId) { }
     * }
     *
     * const asyncHook = async_hooks.createHook(new MyAddedCallbacks());
     * ```
     *
     * Because promises are asynchronous resources whose lifecycle is tracked
     * via the async hooks mechanism, the `init()`, `before()`, `after()`, and`destroy()` callbacks _must not_ be async functions that return promises.
     * @since v8.1.0
     * @param callbacks The `Hook Callbacks` to register
     * @return Instance used for disabling and enabling hooks
     */
    function createHook(callbacks: HookCallbacks): AsyncHook;
    interface AsyncResourceOptions {
        /**
         * The ID of the execution context that created this async event.
         * @default executionAsyncId()
         */
        triggerAsyncId?: number | undefined;
        /**
         * Disables automatic `emitDestroy` when the object is garbage collected.
         * This usually does not need to be set (even if `emitDestroy` is called
         * manually), unless the resource's `asyncId` is retrieved and the
         * sensitive API's `emitDestroy` is called with it.
         * @default false
         */
        requireManualDestroy?: boolean | undefined;
    }
    /**
     * The class `AsyncResource` is designed to be extended by the embedder's async
     * resources. Using this, users can easily trigger the lifetime events of their
     * own resources.
     *
     * The `init` hook will trigger when an `AsyncResource` is instantiated.
     *
     * The following is an overview of the `AsyncResource` API.
     *
     * ```js
     * import { AsyncResource, executionAsyncId } from 'node:async_hooks';
     *
     * // AsyncResource() is meant to be extended. Instantiating a
     * // new AsyncResource() also triggers init. If triggerAsyncId is omitted then
     * // async_hook.executionAsyncId() is used.
     * const asyncResource = new AsyncResource(
     *   type, { triggerAsyncId: executionAsyncId(), requireManualDestroy: false },
     * );
     *
     * // Run a function in the execution context of the resource. This will
     * // * establish the context of the resource
     * // * trigger the AsyncHooks before callbacks
     * // * call the provided function `fn` with the supplied arguments
     * // * trigger the AsyncHooks after callbacks
     * // * restore the original execution context
     * asyncResource.runInAsyncScope(fn, thisArg, ...args);
     *
     * // Call AsyncHooks destroy callbacks.
     * asyncResource.emitDestroy();
     *
     * // Return the unique ID assigned to the AsyncResource instance.
     * asyncResource.asyncId();
     *
     * // Return the trigger ID for the AsyncResource instance.
     * asyncResource.triggerAsyncId();
     * ```
     */
    class AsyncResource {
        /**
         * AsyncResource() is meant to be extended. Instantiating a
         * new AsyncResource() also triggers init. If triggerAsyncId is omitted then
         * async_hook.executionAsyncId() is used.
         * @param type The type of async event.
         * @param triggerAsyncId The ID of the execution context that created
         *   this async event (default: `executionAsyncId()`), or an
         *   AsyncResourceOptions object (since v9.3.0)
         */
        constructor(type: string, triggerAsyncId?: number | AsyncResourceOptions);
        /**
         * Binds the given function to the current execution context.
         * @since v14.8.0, v12.19.0
         * @param fn The function to bind to the current execution context.
         * @param type An optional name to associate with the underlying `AsyncResource`.
         */
        static bind<Func extends (this: ThisArg, ...args: any[]) => any, ThisArg>(
            fn: Func,
            type?: string,
            thisArg?: ThisArg,
        ): Func;
        /**
         * Binds the given function to execute to this `AsyncResource`'s scope.
         * @since v14.8.0, v12.19.0
         * @param fn The function to bind to the current `AsyncResource`.
         */
        bind<Func extends (...args: any[]) => any>(fn: Func): Func;
        /**
         * Call the provided function with the provided arguments in the execution context
         * of the async resource. This will establish the context, trigger the AsyncHooks
         * before callbacks, call the function, trigger the AsyncHooks after callbacks, and
         * then restore the original execution context.
         * @since v9.6.0
         * @param fn The function to call in the execution context of this async resource.
         * @param thisArg The receiver to be used for the function call.
         * @param args Optional arguments to pass to the function.
         */
        runInAsyncScope<This, Result>(
            fn: (this: This, ...args: any[]) => Result,
            thisArg?: This,
            ...args: any[]
        ): Result;
        /**
         * Call all `destroy` hooks. This should only ever be called once. An error will
         * be thrown if it is called more than once. This **must** be manually called. If
         * the resource is left to be collected by the GC then the `destroy` hooks will
         * never be called.
         * @return A reference to `asyncResource`.
         */
        emitDestroy(): this;
        /**
         * @return The unique `asyncId` assigned to the resource.
         */
        asyncId(): number;
        /**
         * @return The same `triggerAsyncId` that is passed to the `AsyncResource` constructor.
         */
        triggerAsyncId(): number;
    }
    /**
     * This class creates stores that stay coherent through asynchronous operations.
     *
     * While you can create your own implementation on top of the `node:async_hooks`module, `AsyncLocalStorage` should be preferred as it is a performant and memory
     * safe implementation that involves significant optimizations that are non-obvious
     * to implement.
     *
     * The following example uses `AsyncLocalStorage` to build a simple logger
     * that assigns IDs to incoming HTTP requests and includes them in messages
     * logged within each request.
     *
     * ```js
     * import http from 'node:http';
     * import { AsyncLocalStorage } from 'node:async_hooks';
     *
     * const asyncLocalStorage = new AsyncLocalStorage();
     *
     * function logWithId(msg) {
     *   const id = asyncLocalStorage.getStore();
     *   console.log(`${id !== undefined ? id : '-'}:`, msg);
     * }
     *
     * let idSeq = 0;
     * http.createServer((req, res) => {
     *   asyncLocalStorage.run(idSeq++, () => {
     *     logWithId('start');
     *     // Imagine any chain of async operations here
     *     setImmediate(() => {
     *       logWithId('finish');
     *       res.end();
     *     });
     *   });
     * }).listen(8080);
     *
     * http.get('http://localhost:8080');
     * http.get('http://localhost:8080');
     * // Prints:
     * //   0: start
     * //   1: start
     * //   0: finish
     * //   1: finish
     * ```
     *
     * Each instance of `AsyncLocalStorage` maintains an independent storage context.
     * Multiple instances can safely exist simultaneously without risk of interfering
     * with each other's data.
     * @since v13.10.0, v12.17.0
     */
    class AsyncLocalStorage<T> {
        /**
         * Binds the given function to the current execution context.
         * @since v19.8.0
         * @experimental
         * @param fn The function to bind to the current execution context.
         * @return A new function that calls `fn` within the captured execution context.
         */
        static bind<Func extends (...args: any[]) => any>(fn: Func): Func;
        /**
         * Captures the current execution context and returns a function that accepts a
         * function as an argument. Whenever the returned function is called, it
         * calls the function passed to it within the captured context.
         *
         * ```js
         * const asyncLocalStorage = new AsyncLocalStorage();
         * const runInAsyncScope = asyncLocalStorage.run(123, () => AsyncLocalStorage.snapshot());
         * const result = asyncLocalStorage.run(321, () => runInAsyncScope(() => asyncLocalStorage.getStore()));
         * console.log(result);  // returns 123
         * ```
         *
         * AsyncLocalStorage.snapshot() can replace the use of AsyncResource for simple
         * async context tracking purposes, for example:
         *
         * ```js
         * class Foo {
         *   #runInAsyncScope = AsyncLocalStorage.snapshot();
         *
         *   get() { return this.#runInAsyncScope(() => asyncLocalStorage.getStore()); }
         * }
         *
         * const foo = asyncLocalStorage.run(123, () => new Foo());
         * console.log(asyncLocalStorage.run(321, () => foo.get())); // returns 123
         * ```
         * @since v19.8.0
         * @experimental
         * @return A new function with the signature `(fn: (...args) : R, ...args) : R`.
         */
        static snapshot(): <R, TArgs extends any[]>(fn: (...args: TArgs) => R, ...args: TArgs) => R;
        /**
         * Disables the instance of `AsyncLocalStorage`. All subsequent calls
         * to `asyncLocalStorage.getStore()` will return `undefined` until`asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()` is called again.
         *
         * When calling `asyncLocalStorage.disable()`, all current contexts linked to the
         * instance will be exited.
         *
         * Calling `asyncLocalStorage.disable()` is required before the`asyncLocalStorage` can be garbage collected. This does not apply to stores
         * provided by the `asyncLocalStorage`, as those objects are garbage collected
         * along with the corresponding async resources.
         *
         * Use this method when the `asyncLocalStorage` is not in use anymore
         * in the current process.
         * @since v13.10.0, v12.17.0
         * @experimental
         */
        disable(): void;
        /**
         * Returns the current store.
         * If called outside of an asynchronous context initialized by
         * calling `asyncLocalStorage.run()` or `asyncLocalStorage.enterWith()`, it
         * returns `undefined`.
         * @since v13.10.0, v12.17.0
         */
        getStore(): T | undefined;
        /**
         * Runs a function synchronously within a context and returns its
         * return value. The store is not accessible outside of the callback function.
         * The store is accessible to any asynchronous operations created within the
         * callback.
         *
         * The optional `args` are passed to the callback function.
         *
         * If the callback function throws an error, the error is thrown by `run()` too.
         * The stacktrace is not impacted by this call and the context is exited.
         *
         * Example:
         *
         * ```js
         * const store = { id: 2 };
         * try {
         *   asyncLocalStorage.run(store, () => {
         *     asyncLocalStorage.getStore(); // Returns the store object
         *     setTimeout(() => {
         *       asyncLocalStorage.getStore(); // Returns the store object
         *     }, 200);
         *     throw new Error();
         *   });
         * } catch (e) {
         *   asyncLocalStorage.getStore(); // Returns undefined
         *   // The error will be caught here
         * }
         * ```
         * @since v13.10.0, v12.17.0
         */
        run<R>(store: T, callback: () => R): R;
        run<R, TArgs extends any[]>(store: T, callback: (...args: TArgs) => R, ...args: TArgs): R;
        /**
         * Runs a function synchronously outside of a context and returns its
         * return value. The store is not accessible within the callback function or
         * the asynchronous operations created within the callback. Any `getStore()`call done within the callback function will always return `undefined`.
         *
         * The optional `args` are passed to the callback function.
         *
         * If the callback function throws an error, the error is thrown by `exit()` too.
         * The stacktrace is not impacted by this call and the context is re-entered.
         *
         * Example:
         *
         * ```js
         * // Within a call to run
         * try {
         *   asyncLocalStorage.getStore(); // Returns the store object or value
         *   asyncLocalStorage.exit(() => {
         *     asyncLocalStorage.getStore(); // Returns undefined
         *     throw new Error();
         *   });
         * } catch (e) {
         *   asyncLocalStorage.getStore(); // Returns the same object or value
         *   // The error will be caught here
         * }
         * ```
         * @since v13.10.0, v12.17.0
         * @experimental
         */
        exit<R, TArgs extends any[]>(callback: (...args: TArgs) => R, ...args: TArgs): R;
        /**
         * Transitions into the context for the remainder of the current
         * synchronous execution and then persists the store through any following
         * asynchronous calls.
         *
         * Example:
         *
         * ```js
         * const store = { id: 1 };
         * // Replaces previous store with the given store object
         * asyncLocalStorage.enterWith(store);
         * asyncLocalStorage.getStore(); // Returns the store object
         * someAsyncOperation(() => {
         *   asyncLocalStorage.getStore(); // Returns the same object
         * });
         * ```
         *
         * This transition will continue for the _entire_ synchronous execution.
         * This means that if, for example, the context is entered within an event
         * handler subsequent event handlers will also run within that context unless
         * specifically bound to another context with an `AsyncResource`. That is why`run()` should be preferred over `enterWith()` unless there are strong reasons
         * to use the latter method.
         *
         * ```js
         * const store = { id: 1 };
         *
         * emitter.on('my-event', () => {
         *   asyncLocalStorage.enterWith(store);
         * });
         * emitter.on('my-event', () => {
         *   asyncLocalStorage.getStore(); // Returns the same object
         * });
         *
         * asyncLocalStorage.getStore(); // Returns undefined
         * emitter.emit('my-event');
         * asyncLocalStorage.getStore(); // Returns the same object
         * ```
         * @since v13.11.0, v12.17.0
         * @experimental
         */
        enterWith(store: T): void;
    }
}
declare module "node:async_hooks" {
    export * from "async_hooks";
}