MyUnisoft Events validator, schemas and types (useful to work with Webhooks).
- Node.js version 18 or higher
- Docker (for running tests).
This package is available in the Node Package Repository and can be easily installed with npm or yarn
$ npm i @myunisoft/events
# or
$ yarn add @myunisoft/events
Configure environment variables
variable | description | default |
---|---|---|
MYUNISOFT_EVENTS_LOGGER_MODE |
Set log level for the default logger | info |
Dispatcher | ||
MYUNISOFT_DISPATCHER_IDLE_TIME |
Interval threshold when Dispatcher become idle | 600_000 |
MYUNISOFT_DISPATCHER_CHECK_LAST_ACTIVITY_INTERVAL |
Dispatcher checking last activity interval | 120_000 |
MYUNISOFT_DISPATCHER_BACKUP_TRANSACTION_STORE_NAME |
Default name for backup transaction store | backup |
MYUNISOFT_DISPATCHER_INIT_TIMEOUT |
Dispatcher initialisation timeout | 3_500 |
MYUNISOFT_DISPATCHER_PING_INTERVAL |
Dispatcher ping interval | 3_500 |
Incomer | ||
MYUNISOFT_INCOMER_INIT_TIMEOUT |
Incomer initialisation timeout | 3_500 |
MYUNISOFT_EVENTS_INIT_EXTERNAL |
Whenever Incomer should initialize an external Dispatcher | false |
MYUNISOFT_INCOMER_MAX_PING_INTERVAL |
Maximum ping interval | 60_000 |
MYUNISOFT_INCOMER_PUBLISH_INTERVAL |
Publish interval | 60_000 |
MYUNISOFT_INCOMER_IS_DISPATCHER |
Weither Incomer is a Dispatcher | false |
Some options takes the lead over environment variables.
For instance with: new Incomer({ dispatcherInactivityOptions: { maxPingInterval: 900_000 }})
the max ping interval will be 900_000
even if MYUNISOFT_INCOMER_MAX_PING_INTERVAL
variable is set.
import * as Events, { type EventOptions } from "@myunisoft/events";
const event: EventOptions<"connector"> = {
name: "connector",
operation: "CREATE",
scope: {
schemaId: 1
},
metadata: {
agent: "Node",
origin: {
endpoint: "http://localhost:12080/api/v1/my-custom-feature",
method: "POST",
requestId: crypto.randomUUID();
},
createdAt: Date.now()
},
data: {
id: 1,
code: "JFAC"
}
};
Events.validate(event);
You can also use additional APIs to validate and narrow the data type depending on the operation:
if (Events.isCreateOperation(event.operation)) {
// Do some code
}
else if (Events.isUpdateOperation(event.operation)) {
// Do some code
}
else if (Events.isDeleteOperation(event.operation)) {
// Do some code
}
Note
π See here for the exhaustive list of Events.
A fully constituted event is composed of a name
, an operation
, and multiple objects such as data
, scope
and metadata
.
- The
name
identifies the event. - The
operation
defines if it is a creation, update, or deletion. - Based on the name, we know the data and the different
metadata.origin.method
related to it. - The
metadata
object is used to determine various pieces of information, such as the entry point. - The
scope
defines the who.
export interface Scope {
schemaId: number;
firmId?: number | null;
firmSIRET?: number | null;
accountingFolderId?: number | null;
accountingFolderSIRET?: number | null;
accountingFolderRef?: string | null;
persPhysiqueId?: number | null;
}
export interface Metadata {
agent: string;
origin?: {
endpoint: string;
method: "GET" | "POST" | "PATCH" | "PUT" | "DELETE" | "HEAD" | "OPTIONS" | (string & {});
requestId?: string;
};
createdAt: number;
}
Throw an error if a given event is not recognized internally.
isCreateOperation< T extends keyof Events >(operation: EventOptions["operation"]): operation is Operation["create"]
isUpdateOperation< T extends keyof Events >(operation: EventOptions["operation"]): operation is Operation["update"]
isDeleteOperation< T extends keyof Events >(operation: EventOptions["operation"]): operation is Operation["delete"]
EventOptions is described by the following type:
export type EventOptions<K extends keyof EventsDefinition.Events> = {
scope: Scope;
metadata: Metadata;
} & EventsDefinition.Events[K];
π See the root example/fastify for an example of utilizing webhooks with an HTTP server.
In TypeScript, webhooks can be described using the WebhookResponse
type:
import type { WebhookResponse } from "@myunisoft/events";
const response: WebhooksResponse<["connector", "accountingFolder"]> = [
{
name: "connector",
operation: "CREATE",
scope: {
schemaId: 1
},
data: {
id: 1,
code: "JFAC"
},
webhookId: "1",
createdAt: Date.now()
},
{
name: "accountingFolder",
operation: "CREATE",
scope: {
schemaId: 1
},
data: {
id: 1
},
webhookId: "2",
createdAt: Date.now()
},
];
Webhook JSON Schema
{
"description": "Webhook",
"type": "array",
"items": {
"type": "object",
"properties": {
"scope": {
"$ref": "Scope"
},
"webhookId": {
"type": "string"
},
"createdAt": {
"type": "number"
},
"name": {
"type": "string",
"description": "event related name"
},
"operation": {
"type": "string",
"description": "event related operation",
"enum": ["CREATE", "UPDATE", "DELETE", "VOID"]
},
"data": {
"type": "object",
"description": "event related data",
"properties": {
"id": {
"type": "string"
},
"required": ["id"],
"additionalProperties": true
}
}
},
"required": ["scope", "webhookId", "createdAt", "name", "operation", "data"],
"additionalProperties": false
}
}
Thanks goes to these wonderful people (emoji key):
Nicolas Hallaert π» π |
Yefis π» π |
Gentilhomme π |
PierreDemailly π» π |
MIT