This commit is contained in:
2026-03-25 14:14:07 +01:00
parent d6b31e2ef7
commit a0073b4fb1
10368 changed files with 2214340 additions and 0 deletions

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Nathan Rajlich
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,93 @@
# @tootallnate/once
### Creates a Promise that waits for a single event
## Installation
Install with `npm`:
```bash
$ npm install @tootallnate/once
```
## API
### once(emitter: EventEmitter, name: string, opts?: OnceOptions): Promise<[...Args]>
Creates a Promise that waits for event `name` to occur on `emitter`, and resolves
the promise with an array of the values provided to the event handler. If an
`error` event occurs before the event specified by `name`, then the Promise is
rejected with the error argument.
```typescript
import once from '@tootallnate/once';
import { EventEmitter } from 'events';
const emitter = new EventEmitter();
setTimeout(() => {
emitter.emit('foo', 'bar');
}, 100);
const [result] = await once(emitter, 'foo');
console.log({ result });
// { result: 'bar' }
```
#### Promise Strong Typing
The main feature that this module provides over other "once" implementations is that
the Promise that is returned is _**strongly typed**_ based on the type of `emitter`
and the `name` of the event. Some examples are shown below.
_The process "exit" event contains a single number for exit code:_
```typescript
const [code] = await once(process, 'exit');
// ^ number
```
_A child process "exit" event contains either an exit code or a signal:_
```typescript
const child = spawn('echo', []);
const [code, signal] = await once(child, 'exit');
// ^ number | null
// ^ string | null
```
_A forked child process "message" event is type `any`, so you can cast the Promise directly:_
```typescript
const child = fork('file.js');
// With `await`
const [message, _]: [WorkerPayload, unknown] = await once(child, 'message');
// With Promise
const messagePromise: Promise<[WorkerPayload, unknown]> = once(child, 'message');
// Better yet would be to leave it as `any`, and validate the payload
// at runtime with i.e. `ajv` + `json-schema-to-typescript`
```
_If the TypeScript definition does not contain an overload for the specified event name, then the Promise will have type `unknown[]` and your code will need to narrow the result manually:_
```typescript
interface CustomEmitter extends EventEmitter {
on(name: 'foo', listener: (a: string, b: number) => void): this;
}
const emitter: CustomEmitter = new EventEmitter();
// "foo" event is a defined overload, so it's properly typed
const fooPromise = once(emitter, 'foo');
// ^ Promise<[a: string, b: number]>
// "bar" event in not a defined overload, so it gets `unknown[]`
const barPromise = once(emitter, 'bar');
// ^ Promise<unknown[]>
```
### OnceOptions
- `signal` - `AbortSignal` instance to unbind event handlers before the Promise has been fulfilled.

View File

@@ -0,0 +1,52 @@
{
"name": "@tootallnate/once",
"version": "2.0.0",
"description": "Creates a Promise that waits for a single event",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"dist"
],
"scripts": {
"prebuild": "rimraf dist",
"build": "tsc",
"test": "jest",
"prepublishOnly": "npm run build"
},
"repository": {
"type": "git",
"url": "git://github.com/TooTallNate/once.git"
},
"keywords": [],
"author": "Nathan Rajlich <nathan@tootallnate.net> (http://n8.io/)",
"license": "MIT",
"bugs": {
"url": "https://github.com/TooTallNate/once/issues"
},
"devDependencies": {
"@types/jest": "^27.0.2",
"@types/node": "^12.12.11",
"abort-controller": "^3.0.0",
"jest": "^27.2.1",
"rimraf": "^3.0.0",
"ts-jest": "^27.0.5",
"typescript": "^4.4.3"
},
"engines": {
"node": ">= 10"
},
"jest": {
"preset": "ts-jest",
"globals": {
"ts-jest": {
"diagnostics": false,
"isolatedModules": true
}
},
"verbose": false,
"testEnvironment": "node",
"testMatch": [
"<rootDir>/test/**/*.test.ts"
]
}
}