{"id":20955127,"url":"https://github.com/myunisoft/events","last_synced_at":"2025-05-14T04:33:03.582Z","repository":{"id":37923646,"uuid":"475420957","full_name":"MyUnisoft/events","owner":"MyUnisoft","description":"Events and Webhooks utilities and documentation","archived":false,"fork":false,"pushed_at":"2025-05-07T12:55:52.000Z","size":806,"stargazers_count":6,"open_issues_count":7,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-05-07T13:49:27.347Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MyUnisoft.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-03-29T11:56:15.000Z","updated_at":"2025-03-28T11:36:53.000Z","dependencies_parsed_at":"2023-11-29T19:33:58.271Z","dependency_job_id":"c0d1651b-7a9a-4d87-8ab8-18cc1bc6d76c","html_url":"https://github.com/MyUnisoft/events","commit_stats":{"total_commits":54,"total_committers":6,"mean_commits":9.0,"dds":"0.40740740740740744","last_synced_commit":"719363b36dfcc2231f5de7e0fdce94c40318f49a"},"previous_names":[],"tags_count":106,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyUnisoft%2Fevents","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyUnisoft%2Fevents/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyUnisoft%2Fevents/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MyUnisoft%2Fevents/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MyUnisoft","download_url":"https://codeload.github.com/MyUnisoft/events/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254071367,"owners_count":22009779,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-19T01:18:08.695Z","updated_at":"2025-05-14T04:33:03.576Z","avatar_url":"https://github.com/MyUnisoft.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\u003ch1 align=\"center\"\u003e\n  Events\n\u003c/h1\u003e\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  MyUnisoft Events validator, schemas and types (useful to work with Webhooks).\n\u003c/p\u003e\n\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://github.com/MyUnisoft/events\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/package-json/v/MyUnisoft/events?style=flat-square\" alt=\"npm version\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/MyUnisoft/events\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/license/MyUnisoft/events?style=flat-square\" alt=\"license\"\u003e\n  \u003c/a\u003e\n  \u003ca href=\"https://github.com/MyUnisoft/events\"\u003e\n    \u003cimg src=\"https://img.shields.io/github/languages/code-size/MyUnisoft/events?style=flat-square\" alt=\"size\"\u003e\n  \u003c/a\u003e\n\u003c/p\u003e\n\n## 🚧 Requirements\n\n- [Node.js](https://nodejs.org/en/) version 18 or higher\n- Docker (for running tests).\n\n## 🚀 Getting Started\n\nThis package is available in the Node Package Repository and can be easily installed with [npm](https://doc.npmjs.com/getting-started/what-is-npm) or [yarn](https://yarnpkg.com)\n\n```bash\n$ npm i @myunisoft/events\n# or\n$ yarn add @myunisoft/events\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eConfigure environment variables\u003c/summary\u003e\n\u003cbr\u003e\n\n| variable | description | default |\n| --- | --- | --- |\n| `MYUNISOFT_EVENTS_LOGGER_MODE` | Set log level for the default logger | `info` |\n| \u003cb\u003eDispatcher\u003c/b\u003e |\n| `MYUNISOFT_DISPATCHER_IDLE_TIME` | Interval threshold when Dispatcher become idle | `600_000` |\n| `MYUNISOFT_DISPATCHER_CHECK_LAST_ACTIVITY_INTERVAL` | Dispatcher checking last activity interval | `120_000` |\n| `MYUNISOFT_DISPATCHER_BACKUP_TRANSACTION_STORE_NAME` | Default name for backup transaction store | `backup` |\n| `MYUNISOFT_DISPATCHER_INIT_TIMEOUT` | Dispatcher initialisation timeout | `3_500` |\n| `MYUNISOFT_DISPATCHER_PING_INTERVAL` | Dispatcher ping interval | `3_500` |\n| \u003cb\u003eIncomer\u003c/b\u003e |\n| `MYUNISOFT_INCOMER_INIT_TIMEOUT` | Incomer initialisation timeout | `3_500` |\n| `MYUNISOFT_EVENTS_INIT_EXTERNAL` | Whenever Incomer should initialize an external Dispatcher | `false` |\n| `MYUNISOFT_INCOMER_MAX_PING_INTERVAL` | Maximum ping interval | `60_000` |\n| `MYUNISOFT_INCOMER_PUBLISH_INTERVAL` | Publish interval | `60_000` |\n| `MYUNISOFT_INCOMER_IS_DISPATCHER` | Weither Incomer is a Dispatcher | `false` |\n\nSome options takes the lead over environment variables.\nFor 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.\n\n\u003c/details\u003e\n\n## 📚 Usage example\n\n```ts\nimport * as Events, { type EventOptions } from \"@myunisoft/events\";\n\nconst event: EventOptions\u003c\"connector\"\u003e = {\n  name: \"connector\",\n  operation: \"CREATE\",\n  scope: {\n    schemaId: 1\n  },\n  metadata: {\n    agent: \"Node\",\n    origin: {\n      endpoint: \"http://localhost:12080/api/v1/my-custom-feature\",\n      method: \"POST\",\n      requestId: crypto.randomUUID();\n    },\n    createdAt: Date.now()\n  },\n  data: {\n    id: \"1\",\n    code: \"JFAC\"\n  }\n};\n\nEvents.validate(event);\n```\n\nYou can also use additional APIs to validate and narrow the data type depending on the operation:\n\n```ts\nif (Events.isCreateOperation(event.operation)) {\n  // Do some code\n}\nelse if (Events.isUpdateOperation(event.operation)) {\n  // Do some code\n}\nelse if (Events.isDeleteOperation(event.operation)) {\n  // Do some code\n}\n```\n\n\u003e [!NOTE]\n\u003e 👀 See [**here**](./docs/events.md) for the exhaustive list of Events.\n\n## 💡 What is an Event?\n\nA fully constituted event is composed of a `name`, an `operation`, and multiple objects such as `data`, `scope` and `metadata`.\n- The `name` identifies the event.\n- The `operation` defines if it is a creation, update, or deletion.\n- Based on the name, we know the **data** and the different `metadata.origin.method` related to it.\n- The `metadata` object is used to determine various pieces of information, such as the entry point.\n- The `scope` defines the **who**.\n\n```ts\nexport interface Scope {\n  schemaId: number;\n  firmId?: number | null;\n  firmSIRET?: number | null;\n  accountingFolderId?: number | null;\n  accountingFolderSIRET?: number | null;\n  accountingFolderRef?: string | null;\n  persPhysiqueId?: number | null;\n}\n\nexport interface Metadata {\n  agent: string;\n  origin?: {\n    endpoint: string;\n    method: \"GET\" | \"POST\" | \"PATCH\" | \"PUT\" | \"DELETE\" | \"HEAD\" | \"OPTIONS\" | (string \u0026 {});\n    requestId?: string;\n  };\n  createdAt: number;\n}\n```\n\n## API\n\n- [Dispatcher](./docs/class/dispatcher.md)\n- [Incomer](./docs/class/incomer.md)\n\n### validate\u003c T extends keyof Events \u003e(options: EventOptions\u003cT\u003e): void\n\nThrow an error if a given event is not recognized internally.\n\n### isCreateOperation\u003c T extends keyof Events \u003e(operation: EventOptions\u003cT\u003e[\"operation\"]): operation is Operation[\"create\"]\n\n### isUpdateOperation\u003c T extends keyof Events \u003e(operation: EventOptions\u003cT\u003e[\"operation\"]): operation is Operation[\"update\"]\n\n### isDeleteOperation\u003c T extends keyof Events \u003e(operation: EventOptions\u003cT\u003e[\"operation\"]): operation is Operation[\"delete\"]\n\n---\n\nEventOptions is described by the following type:\n```ts\nexport type EventOptions\u003cK extends keyof EventsDefinition.Events\u003e = {\n  scope: Scope;\n  metadata: Metadata;\n} \u0026 EventsDefinition.Events[K];\n```\n\n## Exploiting Webhooks\n\n👀 See [**the root example/fastify**](./example/fastify/feature/webhook.ts) for an example of utilizing webhooks with an HTTP server.\n\nIn TypeScript, webhooks can be described using the `WebhookResponse` type:\n```ts\nimport type { WebhookResponse } from \"@myunisoft/events\";\n\nconst response: WebhooksResponse\u003c[\"connector\", \"accountingFolder\"]\u003e = [\n  {\n    name: \"connector\",\n    operation: \"CREATE\",\n    scope: {\n      schemaId: 1\n    },\n    data: {\n      id: 1,\n      code: \"JFAC\"\n    },\n    webhookId: \"1\",\n    createdAt: Date.now()\n  },\n  {\n    name: \"accountingFolder\",\n    operation: \"CREATE\",\n    scope: {\n      schemaId: 1\n    },\n    data: {\n      id: 1\n    },\n    webhookId: \"2\",\n    createdAt: Date.now()\n  },\n];\n```\n\n\u003cdetails\u003e\n\u003csummary\u003eWebhook JSON Schema\u003c/summary\u003e\n\n```json\n{\n  \"description\": \"Webhook\",\n  \"type\": \"array\",\n  \"items\": {\n    \"type\": \"object\",\n    \"properties\": {\n      \"scope\": {\n        \"$ref\": \"Scope\"\n      },\n      \"webhookId\": {\n        \"type\": \"string\"\n      },\n      \"createdAt\": {\n        \"type\": \"number\"\n      },\n      \"name\": {\n        \"type\": \"string\",\n        \"description\": \"event related name\"\n      },\n      \"operation\": {\n        \"type\": \"string\",\n        \"description\": \"event related operation\",\n        \"enum\": [\"CREATE\", \"UPDATE\", \"DELETE\", \"VOID\"]\n      },\n      \"data\": {\n        \"type\": \"object\",\n        \"description\": \"event related data\",\n        \"properties\": {\n          \"id\": {\n            \"type\": \"string\"\n          },\n          \"required\": [\"id\"],\n          \"additionalProperties\": true\n        }\n      }\n    },\n    \"required\": [\"scope\", \"webhookId\", \"createdAt\", \"name\", \"operation\", \"data\"],\n    \"additionalProperties\": false\n  }\n}\n```\n\u003c/details\u003e\n\n## Contributors ✨\n\n\u003c!-- ALL-CONTRIBUTORS-BADGE:START - Do not remove or modify this section --\u003e\n[![All Contributors](https://img.shields.io/badge/all_contributors-4-orange.svg?style=flat-square)](#contributors-)\n\u003c!-- ALL-CONTRIBUTORS-BADGE:END --\u003e\n\nThanks goes to these wonderful people ([emoji key](https://allcontributors.org/docs/en/emoji-key)):\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section --\u003e\n\u003c!-- prettier-ignore-start --\u003e\n\u003c!-- markdownlint-disable --\u003e\n\u003ctable\u003e\n  \u003ctbody\u003e\n    \u003ctr\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://www.linkedin.com/in/nicolas-hallaert/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/39910164?v=4?s=100\" width=\"100px;\" alt=\"Nicolas Hallaert\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eNicolas Hallaert\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/MyUnisoft/events/commits?author=Rossb0b\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/MyUnisoft/events/commits?author=Rossb0b\" title=\"Documentation\"\u003e📖\u003c/a\u003e \u003ca href=\"https://github.com/MyUnisoft/events/commits?author=Rossb0b\" title=\"Tests\"\u003e⚠️\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"http://sofiand.github.io/portfolio-client/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/39944043?v=4?s=100\" width=\"100px;\" alt=\"Yefis\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eYefis\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/MyUnisoft/events/commits?author=SofianD\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/MyUnisoft/events/commits?author=SofianD\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://www.linkedin.com/in/thomas-gentilhomme/\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/4438263?v=4?s=100\" width=\"100px;\" alt=\"Gentilhomme\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003eGentilhomme\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/MyUnisoft/events/commits?author=fraxken\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n      \u003ctd align=\"center\" valign=\"top\" width=\"14.28%\"\u003e\u003ca href=\"https://github.com/PierreDemailly\"\u003e\u003cimg src=\"https://avatars.githubusercontent.com/u/39910767?v=4?s=100\" width=\"100px;\" alt=\"PierreDemailly\"/\u003e\u003cbr /\u003e\u003csub\u003e\u003cb\u003ePierreDemailly\u003c/b\u003e\u003c/sub\u003e\u003c/a\u003e\u003cbr /\u003e\u003ca href=\"https://github.com/MyUnisoft/events/commits?author=PierreDemailly\" title=\"Code\"\u003e💻\u003c/a\u003e \u003ca href=\"https://github.com/MyUnisoft/events/commits?author=PierreDemailly\" title=\"Documentation\"\u003e📖\u003c/a\u003e\u003c/td\u003e\n    \u003c/tr\u003e\n  \u003c/tbody\u003e\n\u003c/table\u003e\n\n\u003c!-- markdownlint-restore --\u003e\n\u003c!-- prettier-ignore-end --\u003e\n\n\u003c!-- ALL-CONTRIBUTORS-LIST:END --\u003e\n\n## License\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmyunisoft%2Fevents","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmyunisoft%2Fevents","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmyunisoft%2Fevents/lists"}