port_agent
Advanced tools
Comparing version 1.4.1 to 1.4.2
@@ -1,2 +0,1 @@ | ||
/// <reference types="node" /> | ||
import * as threads from 'node:worker_threads'; | ||
@@ -3,0 +2,0 @@ import { CallMessage } from './messages'; |
@@ -18,9 +18,19 @@ "use strict"; | ||
}); | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
var __importStar = (this && this.__importStar) || (function () { | ||
var ownKeys = function(o) { | ||
ownKeys = Object.getOwnPropertyNames || function (o) { | ||
var ar = []; | ||
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; | ||
return ar; | ||
}; | ||
return ownKeys(o); | ||
}; | ||
return function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); | ||
__setModuleDefault(result, mod); | ||
return result; | ||
}; | ||
})(); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -146,3 +156,3 @@ exports.Agent = exports.Call = void 0; | ||
await this.portOnline; | ||
// Each call must await here in order to ensure previous calls are executed prior to this one. | ||
// Each call must await here, until the port comes online, in order to ensure previous calls are processed prior to this one. | ||
return new Promise((r, j) => { | ||
@@ -149,0 +159,0 @@ const id = this.callID++; |
@@ -1,2 +0,2 @@ | ||
import { Agent } from "./agent"; | ||
import { Agent } from './agent'; | ||
export { Agent }; |
{ | ||
"name": "port_agent", | ||
"version": "1.4.1", | ||
"version": "1.4.2", | ||
"description": "A RPC-like facility for making inter-thread function calls.", | ||
@@ -10,3 +10,3 @@ "main": "./dist/index.js", | ||
"clean:build": "npm run clean && npm run build", | ||
"test": "npm run clean:build && npm install --prefix ./tests/test && npm run clean:build:start --prefix ./tests/test", | ||
"test": "npm upgrade && npm run clean:build && npm upgrade --prefix ./tests/test && npm run clean:build:start --prefix ./tests/test", | ||
"watch": "tsc --watch" | ||
@@ -25,6 +25,7 @@ }, | ||
"devDependencies": { | ||
"@types/node": "^20.3.1", | ||
"@typescript-eslint/eslint-plugin": "^6.0.0", | ||
"@typescript-eslint/parser": "^6.0.0", | ||
"eslint": "^8.44.0", | ||
"@eslint/js": "^9.6.0", | ||
"@types/eslint__js": "^8.42.3", | ||
"@types/node": "^20.11.28", | ||
"eslint": "^8.57.0", | ||
"typescript-eslint": "^7.15.0", | ||
"nodemon": "^2.0.22", | ||
@@ -31,0 +32,0 @@ "typescript": "^5.1.6" |
141
README.md
@@ -18,8 +18,9 @@ # Port Agent | ||
- [Agent](#agent) | ||
- [API](#api) | ||
- [Usage](#usage) | ||
- [How to create an Agent instance.](#how-to-create-an-agent-instance) | ||
- [Examples](#examples) | ||
- [A simple example.](#a-simple-example-example) | ||
- [A comprehensive example.](#a-comprehensive-example-example) | ||
- [A simple example.](#a-simple-example-nodejs) | ||
- [A comprehensive example.](#a-comprehensive-example-typescript) | ||
- [API](#api) | ||
- [Versioning](#versioning) | ||
- [Notes](#notes) | ||
@@ -33,3 +34,3 @@ - [Support for BroadcastChannels.](#support-for-broadcastchannels) | ||
An instance of an `Agent` facilitates communication across threads. The `Agent` can be used in order to register a function in one thread and call it from another thread. Calls may be made from the main thread to a worker thread, and conversely from a worker thread to the main thread. | ||
An instance of an `Agent` facilitates bi-directional communication between threads. The `Agent` can be used in order to register a function in one thread and call it from another thread. Calls may be made from the main thread to a worker thread, and conversely from a worker thread to the main thread. | ||
@@ -40,32 +41,2 @@ Late binding registrants will be called with previously awaited invocations; thus preventing a race condition. This means that you may await a call to a function that has not yet been registered. Once the function is registered in the *other* thread it will be called and its return value or `Error` will be marshalled back to the caller. | ||
## API | ||
### The `Agent` class. | ||
#### port_agent.Agent(port) | ||
- port `<threads.MessagePort>` or `<threads.Worker>` The message port. | ||
#### agent.call\<T\>(name, ...args) | ||
- name `<string>` The name of the registered function. | ||
- ...args `<Array<unknown>>` Arguments to be passed to the registered function. | ||
- Returns: `<Promise<T>>` | ||
- Errors: | ||
- If the registered function in the *other* thread throws an `Error`, the `Error` will be marshalled back from the *other* thread to *this* thread and the `Promise` will reject with the `Error` as its failure reason. | ||
- If a worker thread throws an unhandled exception while a call is awaited, the `Error` will be marshalled back from the *other* thread to *this* thread and the `Promise` will reject with the unhandled exception as its failure reason. | ||
- If a worker exits while a call is awaited, the `Error` will be marshalled back from the *other* thread to *this* thread and the `Promise` will reject with the exit code as its failure reason. | ||
#### agent.register(name, fn) | ||
- name `<string>` The name of the registered function. | ||
- fn `<(...args: Array<any>) => any>` The registered function. | ||
- Returns: `<void>` | ||
#### agent.deregister(name) | ||
- name `<string>` The name of the registered function. | ||
- Returns: `<void>` | ||
## Usage | ||
@@ -108,74 +79,52 @@ | ||
### *A simple example.* <sup><sup>(example)</sup></sup> | ||
### *A Simple Example* <sup><sup>\</Node.js\></sup></sup> | ||
Please see the [Simple Example](https://github.com/faranalytics/port_agent/tree/main/examples/simple) for a working implementation. | ||
In this example you will: | ||
### *A Comprehensive Example* <sup><sup>\</TypeScript\></sup></sup> | ||
Please see the [Comprehensive Example](https://github.com/faranalytics/port_agent/tree/main/examples/comprehensive) for a working implementation. | ||
1. Instantiate a worker thread. | ||
2. Instantiate an `Agent` in the main thread. | ||
3. Use the `Agent` to await a call to the `hello_world` function. | ||
4. Instantiate an `Agent` in the worker thread. | ||
5. Use the `Agent` in order to register a function named `abend` that will throw an `Error` when it is called. | ||
6. Use the `Agent` in order to register a function named `hello_word` to handle calls to the `hello_world` function. | ||
7. Use the `Agent` in order to register a function named `add` that will return the sum of two operands. | ||
8. Resolve (3) and log the `greeting` to the console. | ||
9. Use the `Agent` to await a call to the function named `add`. | ||
10. Resolve (9) and log the `result` to the console. | ||
11. Use the `Agent` to await a call to the function named `abend`. | ||
12. Catch the `Error` from (11) and log the stack trace to the console. | ||
13. Terminate the thread. | ||
## API | ||
`examples/simple/index.js` | ||
```js | ||
import { Worker, isMainThread, parentPort } from 'node:worker_threads'; | ||
import { fileURLToPath } from 'node:url'; | ||
import { Agent } from 'port_agent'; | ||
### The Agent Class | ||
if (isMainThread) { // This is the main thread. | ||
void (async () => { | ||
const worker = new Worker(fileURLToPath(import.meta.url)); // (1) | ||
const agent = new Agent(worker); // (2) | ||
try { | ||
const greeting = await agent.call('hello_world', 'another'); // (3) | ||
console.log(greeting); // (8) | ||
#### port_agent.Agent(port) | ||
- port `<threads.MessagePort>` or `<threads.Worker>` The message port. | ||
const result = await agent.call('add', 1, 1); // (9) | ||
console.log(result); // (10) | ||
#### agent.call\<T\>(name, ...args) | ||
- name `<string>` The name of the registered function. | ||
- ...args `<Array<unknown>>` Arguments to be passed to the registered function. | ||
await agent.call('abend', "This Error is expected, indeed.") // (11) | ||
} | ||
catch (err) { | ||
console.error(err); // (12) | ||
} | ||
finally { | ||
worker.terminate(); // (13) | ||
} | ||
})(); | ||
} | ||
else { // This is a worker thread. | ||
if (parentPort) { | ||
const agent = new Agent(parentPort); // (4) | ||
agent.register('abend', (message) => { throw new Error(message); }); // (5) | ||
agent.register('hello_world', (value) => `Hello, ${value} world!`); // (6) | ||
agent.register('add', (a, b) => a + b); // (7) | ||
} | ||
} | ||
``` | ||
The example will log to the console something similar to this: | ||
- Returns: `<Promise<T>>` | ||
```bash | ||
Hello, another world! | ||
2 | ||
Error: This Error is expected, indeed. | ||
at file:///port_agent/examples/simple/index.js:29:54 | ||
at Agent.tryPost (/port_agent/examples/simple/node_modules/port_agent/dist/index.js:145:33) | ||
at MessagePort.<anonymous> (/port_agent/examples/simple/node_modules/port_agent/dist/index.js:114:36) | ||
at [nodejs.internal.kHybridDispatch] (node:internal/event_target:762:20) | ||
at exports.emitMessage (node:internal/per_context/messageport:23:28) | ||
``` | ||
- Errors: | ||
Please see the [Simple example](https://github.com/faranalytics/port_agent/tree/main/examples/simple) for a working implementation. | ||
- If the registered function in the *other* thread throws an `Error`, the `Error` will be marshalled back from the *other* thread to *this* thread and the `Promise` will reject with the `Error` as its failure reason. | ||
- If a worker thread throws an unhandled exception while a call is awaited, the `Error` will be marshalled back from the *other* thread to *this* thread and the `Promise` will reject with the unhandled exception as its failure reason. | ||
- If a worker exits while a call is awaited, the `Error` will be marshalled back from the *other* thread to *this* thread and the `Promise` will reject with the exit code as its failure reason. | ||
### *A comprehensive example.* <sup><sup>(example)</sup></sup> | ||
Please see the [Comprehensive example](https://github.com/faranalytics/port_agent/tree/main/examples/comprehensive) for a working implementation. | ||
#### agent.register(name, fn) | ||
- name `<string>` The name of the registered function. | ||
- fn `<(...args: Array<any>) => any>` The registered function. | ||
- Returns: `<void>` | ||
#### agent.deregister(name) | ||
- name `<string>` The name of the registered function. | ||
- Returns: `<void>` | ||
## Versioning | ||
The Port Agent package adheres to semantic versioning. Breaking changes to the public API will result in a turn of the major. Minor and patch changes will always be backward compatible. | ||
Excerpted from [Semantic Versioning 2.0.0](https://semver.org/): | ||
> Given a version number MAJOR.MINOR.PATCH, increment the: | ||
> | ||
> 1. MAJOR version when you make incompatible API changes | ||
> 2. MINOR version when you add functionality in a backward compatible manner | ||
> 3. PATCH version when you make backward compatible bug fixes | ||
> | ||
> Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format. | ||
## Notes | ||
@@ -182,0 +131,0 @@ |
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
270
0
17348
7
132