diff --git a/api-documents/kit.md b/api-documents/kit.md
index 0257338..f4e1e19 100644
--- a/api-documents/kit.md
+++ b/api-documents/kit.md
@@ -44,6 +44,7 @@ A toolkit for browser extension developing.
| [DOMProxyEvents](./kit.domproxyevents.md) | Events on the DOMProxy object |
| [DOMProxyOptions](./kit.domproxyoptions.md) | Options for DOMProxy |
| [Serialization](./kit.serialization.md) | Define how to do serialization and deserialization of remote procedure call |
+| [TargetBoundEventListenerOptions](./kit.targetboundeventlisteneroptions.md) | |
| [TargetBoundEventRegistry](./kit.targetboundeventregistry.md) | |
| [UnboundedRegistry](./kit.unboundedregistry.md) | |
| [WatcherEvents](./kit.watcherevents.md) | |
diff --git a/api-documents/kit.targetboundeventlisteneroptions.md b/api-documents/kit.targetboundeventlisteneroptions.md
new file mode 100644
index 0000000..0323d7d
--- /dev/null
+++ b/api-documents/kit.targetboundeventlisteneroptions.md
@@ -0,0 +1,19 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [TargetBoundEventListenerOptions](./kit.targetboundeventlisteneroptions.md)
+
+## TargetBoundEventListenerOptions interface
+
+Signature:
+
+```typescript
+export interface TargetBoundEventListenerOptions
+```
+
+## Properties
+
+| Property | Type | Description |
+| --- | --- | --- |
+| [once?](./kit.targetboundeventlisteneroptions.once.md) | boolean | (Optional) Run the listener only once. |
+| [signal?](./kit.targetboundeventlisteneroptions.signal.md) | AbortSignal | (Optional) Cancel the listener by AbortSignal |
+
diff --git a/api-documents/kit.targetboundeventlisteneroptions.once.md b/api-documents/kit.targetboundeventlisteneroptions.once.md
new file mode 100644
index 0000000..5bcae86
--- /dev/null
+++ b/api-documents/kit.targetboundeventlisteneroptions.once.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [TargetBoundEventListenerOptions](./kit.targetboundeventlisteneroptions.md) > [once](./kit.targetboundeventlisteneroptions.once.md)
+
+## TargetBoundEventListenerOptions.once property
+
+Run the listener only once.
+
+Signature:
+
+```typescript
+once?: boolean;
+```
diff --git a/api-documents/kit.targetboundeventlisteneroptions.signal.md b/api-documents/kit.targetboundeventlisteneroptions.signal.md
new file mode 100644
index 0000000..1e6849d
--- /dev/null
+++ b/api-documents/kit.targetboundeventlisteneroptions.signal.md
@@ -0,0 +1,13 @@
+
+
+[Home](./index.md) > [@holoflows/kit](./kit.md) > [TargetBoundEventListenerOptions](./kit.targetboundeventlisteneroptions.md) > [signal](./kit.targetboundeventlisteneroptions.signal.md)
+
+## TargetBoundEventListenerOptions.signal property
+
+Cancel the listener by AbortSignal
+
+Signature:
+
+```typescript
+signal?: AbortSignal;
+```
diff --git a/api-documents/kit.targetboundeventregistry.md b/api-documents/kit.targetboundeventregistry.md
index 2ea5e0f..31a5002 100644
--- a/api-documents/kit.targetboundeventregistry.md
+++ b/api-documents/kit.targetboundeventregistry.md
@@ -15,7 +15,7 @@ export interface TargetBoundEventRegistry
| Method | Description |
| --- | --- |
| [off(callback)](./kit.targetboundeventregistry.off.md) | |
-| [on(callback)](./kit.targetboundeventregistry.on.md) | |
+| [on(callback, options)](./kit.targetboundeventregistry.on.md) | |
| [pause()](./kit.targetboundeventregistry.pause.md) | Pausing the dispatch of this event. Collect all new incoming events. |
| [send(data)](./kit.targetboundeventregistry.send.md) | |
diff --git a/api-documents/kit.targetboundeventregistry.on.md b/api-documents/kit.targetboundeventregistry.on.md
index 7eb88fd..872df8d 100644
--- a/api-documents/kit.targetboundeventregistry.on.md
+++ b/api-documents/kit.targetboundeventregistry.on.md
@@ -7,7 +7,7 @@
Signature:
```typescript
-on(callback: (data: T) => void): () => void;
+on(callback: (data: T) => void, options?: TargetBoundEventListenerOptions): () => void;
```
## Parameters
@@ -15,6 +15,7 @@ on(callback: (data: T) => void): () => void;
| Parameter | Type | Description |
| --- | --- | --- |
| callback | (data: T) => void | |
+| options | [TargetBoundEventListenerOptions](./kit.targetboundeventlisteneroptions.md) | |
Returns:
diff --git a/doc/holoflows-kit.api.report.md b/doc/holoflows-kit.api.report.md
index 1fc9d7a..f12e3df 100644
--- a/doc/holoflows-kit.api.report.md
+++ b/doc/holoflows-kit.api.report.md
@@ -4,6 +4,8 @@
```ts
+///
+
import { Emitter } from '@servie/events';
import { EventListener as EventListener_2 } from '@servie/events';
@@ -108,7 +110,7 @@ export function getEnvironment(): Environment;
export class IntervalWatcher extends Watcher {
startWatch(interval: number): this;
stopWatch(): void;
- }
+}
// @public
export function isEnvironment(env: Environment): boolean;
@@ -160,7 +162,7 @@ export class LiveSelector {
reverse(): LiveSelector;
slice(start?: number, end?: number): LiveSelector;
sort(compareFn?: (a: T, b: T) => number): LiveSelector;
- }
+}
// @public (undocumented)
export enum MessageTarget {
@@ -186,7 +188,7 @@ export class MutationObserverWatcher;
startWatch(options: MutationObserverInit): this;
stopWatch(): void;
- }
+}
// @public
export function printEnvironment(e?: Environment): string;
@@ -205,12 +207,18 @@ export type ShouldAcceptExternalConnectionResult = boolean | {
acceptAs: Environment;
};
+// @public (undocumented)
+export interface TargetBoundEventListenerOptions {
+ once?: boolean;
+ signal?: AbortSignal;
+}
+
// @public (undocumented)
export interface TargetBoundEventRegistry {
// (undocumented)
off(callback: (data: T) => void): void;
// (undocumented)
- on(callback: (data: T) => void): () => void;
+ on(callback: (data: T) => void, options?: TargetBoundEventListenerOptions): () => void;
pause(): (reducer?: (data: T[]) => T[]) => Promise;
// (undocumented)
send(data: T): void;
@@ -247,7 +255,7 @@ export class ValueRef {
removeListener(fn: (newVal: T, oldVal: T) => void): void;
get value(): T;
set value(newVal: T);
- }
+}
// Warning: (ae-forgotten-export) The symbol "ResultOf" needs to be exported by the entry point index.d.ts
//
@@ -302,40 +310,40 @@ export abstract class Watcher {
// @eventProperty (undocumented)
onAdd: [
{
- key: unknown;
- value: T;
- }
+ key: unknown;
+ value: T;
+ }
];
// @eventProperty (undocumented)
onChange: [
{
- oldKey: unknown;
- newKey: unknown;
- oldValue?: T;
- newValue: T;
- }
+ oldKey: unknown;
+ newKey: unknown;
+ oldValue?: T;
+ newValue: T;
+ }
];
// @eventProperty (undocumented)
onIteration: [
{
- new: Map;
- removed: Map;
- current: Map;
- }
+ new: Map;
+ removed: Map;
+ current: Map;
+ }
];
// @eventProperty (undocumented)
onRemove: [
{
- key: unknown;
- value: T;
- }
+ key: unknown;
+ value: T;
+ }
];
}
@@ -358,7 +366,7 @@ export class WebExtensionMessage {
// (undocumented)
logFormatter: (instance: this, key: string, data: unknown) => unknown[];
serialization: Serialization;
- }
+}
// @public (undocumented)
export interface WebExtensionMessageOptions {
@@ -366,5 +374,4 @@ export interface WebExtensionMessageOptions {
readonly externalExtensionID?: string;
}
-
```
diff --git a/src/Extension/MessageChannel.ts b/src/Extension/MessageChannel.ts
index 66a4f9d..8090259 100644
--- a/src/Extension/MessageChannel.ts
+++ b/src/Extension/MessageChannel.ts
@@ -1,3 +1,5 @@
+/* eslint-disable @typescript-eslint/strict-boolean-expressions */
+/* eslint-disable no-bitwise */
import { Emitter } from '@servie/events'
import { EventIterator } from 'event-iterator'
import { Environment, getEnvironment, isEnvironment } from './Context'
@@ -5,7 +7,7 @@ import { Environment, getEnvironment, isEnvironment } from './Context'
/**
* Define how to do serialization and deserialization of remote procedure call
*/
- export interface Serialization {
+export interface Serialization {
/**
* Do serialization
* @param from - original data
@@ -27,9 +29,15 @@ export enum MessageTarget {
/** Externals not included */ Broadcast = Environment.HasBrowserAPI,
All = Broadcast | IncludeLocal,
}
+export interface TargetBoundEventListenerOptions {
+ /** Run the listener only once. */
+ once?: boolean
+ /** Cancel the listener by AbortSignal */
+ signal?: AbortSignal
+}
export interface TargetBoundEventRegistry {
/** @returns A function to remove the listener */
- on(callback: (data: T) => void): () => void
+ on(callback: (data: T) => void, options?: TargetBoundEventListenerOptions): () => void
off(callback: (data: T) => void): void
send(data: T): void
/**
@@ -210,7 +218,7 @@ export class WebExtensionMessage {
*
* This API only works in the BackgroundPage.
*/
- public serialization: Serialization = { deserialization: x => x, serialization: x => x }
+ public serialization: Serialization = { deserialization: (x) => x, serialization: (x) => x }
public logFormatter: (instance: this, key: string, data: unknown) => unknown[] = (instance, key, data) => {
return [
`%cReceive%c %c${String(key)}`,
@@ -285,9 +293,13 @@ function UnboundedRegistry(
})
}
let binder: TargetBoundEventRegistry
- function on(cb: (data: T) => void) {
+ function on(cb: (data: T) => void, options?: TargetBoundEventListenerOptions) {
eventListener.on(eventName, cb)
- return () => eventListener.off(eventName, cb)
+
+ const off = () => eventListener.off(eventName, cb)
+ if (options?.once) eventListener.on(eventName, off)
+ if (options?.signal) options.signal.addEventListener('abort', off)
+ return off
}
function off(cb: (data: T) => void) {
eventListener.off(eventName, cb)
@@ -386,7 +398,7 @@ function backgroundPortBoarding(port: browser.runtime.Port, sender: undefined |
// Client will report it's environment flag on connection
port.onMessage.addListener(function environmentListener(x) {
const obj = backgroundOnlyLivingPorts.get(port)!
- if (typeof obj.environment === "undefined") obj.environment = Number(x)
+ if (typeof obj.environment === 'undefined') obj.environment = Number(x)
port.onMessage.removeListener(environmentListener)
})
port.onMessage.addListener(backgroundPageMessageHandler.bind(port))