Skip to content

Events and Webhooks utilities and documentation

License

Notifications You must be signed in to change notification settings

MyUnisoft/events

Folders and files

NameName
Last commit message
Last commit date

Latest commit

author
Rossb0b
Aug 1, 2023
39625ea Β· Aug 1, 2023
Jun 27, 2023
Aug 1, 2023
Jul 25, 2023
Aug 1, 2023
Jul 25, 2023
Sep 5, 2022
Apr 6, 2022
Jun 5, 2023
Apr 6, 2022
Sep 5, 2022
Jun 3, 2022
Jul 28, 2023
Jun 26, 2023
Jun 22, 2023
Jun 22, 2023
Aug 1, 2023
Aug 1, 2023
Jun 5, 2023
Mar 29, 2022

Repository files navigation

Events

MyUnisoft Events validator, schemas and types (useful to work with Webhooks).

npm version license size

🚧 Requirements

  • Node.js version 16 or higher
  • Docker (for running tests).

πŸš€ Getting Started

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

Publishing Events

Events

An Event fully constituted is composed by a name, an operation and multiple objects such as data, scope and metadata.

  • The name identify the event.
  • The operation will define if it is a creation, update or deletion.
  • According to the name, we know the data and the different metadata.origin.method related.
  • The metadata object is used to determine different information as the ecosystem, the entry point etc.
  • The scope will define 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 type Method = "POST" | "PATCH" | "PUT" | "DELETE";

export interface Metadata {
  agent: string;
  origin?: {
    endpoint: string;
    method: Method;
    requestId?: string;
  };
  createdAt: number;
}

πŸ“š Usage

Define and validate an event.

import * as MyEvents, { 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"
  }
};

MyEvents.validate<"connector">(event);

Define which operation the event has.

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"
  }
};

if (isCreateOperation(event.operation)) {
  // Do some code
}

if (isUpdateOperation(event.operation)) {
  // Do some code
}

if (isDeleteOperation(event.operation)) {
  // Do some code
}

API

Dispatcher & Incomer class

There is the documentation of Dispatcher, and Incomer classes.


validate< T extends keyof Events >(options: EventOptions): void

Throw an error if a given event is not internaly known.


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"]

Types

EventOptions

export type EventOptions<K extends keyof EventsDefinition.Events> = {
  scope: Scope;
  metadata: Metadata;
} & EventsDefinition.Events[K];

const event: EventOptions<"connector"> = {
  name: "connector",
  operation: "CREATE",
  scope: {
    schemaId: 1
  },
  metadata: {
    agent: "Node",
    createdAt: Date.now(),
    requestId: crypto.randomUUID();
  },
  data: {
    id: 1,
    code: "JFAC"
  }
}

EventsOptions

type TupleToObject<T extends readonly any[],
  M extends Record<Exclude<keyof T, keyof any[]>, PropertyKey>> =
  { [K in Exclude<keyof T, keyof any[]> as M[K]]: T[K] };

export type EventsOptions<T extends (keyof EventsDefinition.Events)[] = (keyof EventsDefinition.Events)[]> = TupleToObject<[
  ...(EventOptions<T[number]>)[]
], []>;

const events: EventsOptions<["connector", "accountingFolder"]> = [
  {
    name: "connector",
    operation: "CREATE",
    scope: {
      schemaId: 1
    },
    metadata: {
      agent: "Node",
      createdAt: Date.now(),
      requestId: crypto.randomUUID();
    },
    data: {
      id: 1,
      code: "JFAC"
    }
  },
  {
    name: "accountingFolder",
    operation: "CREATE",
    scope: {
      schemaId: 1
    },
    metadata: {
      agent: "Windev",
      createdAt: Date.now(),
      requestId: crypto.randomUUID();
    },
    data: {
      id: 1
    }
  }
];

const event: EventsOptions<["connector", "accountingFolder"]> = {
  name: "connector",
  operation: "CREATE",
  scope: {
    schemaId: 1
  },
  metadata: {
    agent: "Node",
    createdAt: Date.now(),
    requestId: 0
  },
  data: {
    id: 1,
    code: "JFAC"
  }
}

Exploiting Webhooks

πŸ“š Usage

πŸ‘€ See here for an example of exploiting webhooks with an http server.

πŸ‘€ See here for an exhaustive list of MyUnisoft Events you can subscribe to.

⚠️ A Webhook can send multiple Events on a single HTTP POST request.

Types

WebhooksResponse

JSON Schema

type WebhookResponse<K extends keyof EventTypes.Events> = {
  scope: Scope;
  webhookId: string;
  createdAt: number;
} & EventTypes.Events[K];

export type WebhooksResponse<T extends (keyof EventTypes.Events)[] = (keyof EventTypes.Events)[]> = [
  ...(WebhookResponse<T[number]>)[]
];

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()
  },
];

Contributors ✨

All Contributors

Thanks goes to these wonderful people (emoji key):


Nicolas Hallaert

πŸ’» πŸ“– ⚠️

Yefis

πŸ’» πŸ“–

Gentilhomme

πŸ“– πŸ›‘οΈ

License

MIT