idoc-logs-react 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Philippe Boinnard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,84 @@
1
+ # idoc-logs-react
2
+
3
+ Log client for the **IDOC.Logs** centralizing server: batched HTTPS shipping, global error capture, breadcrumbs, and React bindings.
4
+
5
+ The browser counterpart of [IDOC.Logs.Nlog](https://www.nuget.org/packages/IDOC.Logs.Nlog) (the C#/NLog client). Entries are sent to the server's `POST /api/logs/client` endpoint, authenticated by a per-application API key.
6
+
7
+ ## Installation
8
+
9
+ ```
10
+ npm install idoc-logs-react
11
+ ```
12
+
13
+ ## Quick start
14
+
15
+ ```ts
16
+ // main.tsx — once, at startup
17
+ import { initIdocLogs } from "idoc-logs-react";
18
+
19
+ initIdocLogs({
20
+ url: "https://logs.example.com:5001",
21
+ apiKey: "<clé API générée dans l'admin du serveur>",
22
+ version: "1.4.0",
23
+ });
24
+ ```
25
+
26
+ That's it — unhandled errors (`window.onerror`) and unhandled promise rejections are now reported automatically, with breadcrumbs.
27
+
28
+ ### Logging manually
29
+
30
+ ```ts
31
+ import { idocLogs } from "idoc-logs-react";
32
+
33
+ idocLogs.info("Panier", "Commande validée");
34
+ idocLogs.error("Panier", "Échec du paiement", err);
35
+ ```
36
+
37
+ ### React error boundary
38
+
39
+ ```tsx
40
+ import { IdocLogsErrorBoundary } from "idoc-logs-react/react";
41
+
42
+ <IdocLogsErrorBoundary fallback={(err, reset) => <ErreurPage onRetry={reset} />}>
43
+ <App />
44
+ </IdocLogsErrorBoundary>
45
+ ```
46
+
47
+ Render errors are reported as **Fatal** with the React component stack.
48
+
49
+ ```tsx
50
+ import { useIdocLogger } from "idoc-logs-react/react";
51
+
52
+ const logs = useIdocLogger();
53
+ logs.warn("Profil", "Avatar introuvable, fallback utilisé");
54
+ ```
55
+
56
+ ## Options
57
+
58
+ | Option | Default | Description |
59
+ |--------|---------|-------------|
60
+ | `url` | — | Base URL of the log server (e.g. `https://logs.example.com:5001`) |
61
+ | `apiKey` | — | Per-application API key (generated in the server admin) |
62
+ | `version` | `null` | Application version attached to each entry |
63
+ | `niveauEnvoi` | `"Info"` | Minimum level actually sent. Lower levels only feed breadcrumbs. |
64
+ | `captureGlobale` | `true` | Hook `window.onerror` / `unhandledrejection` |
65
+ | `breadcrumbsMax` | `30` | Breadcrumb circular buffer size |
66
+ | `flushIntervalleMs` | `5000` | Batch flush interval |
67
+ | `flushMaxEntrees` | `20` | Batch size triggering an immediate flush |
68
+
69
+ ## Behaviour
70
+
71
+ - **Batching** — entries are queued and flushed every 5 s or every 20 entries (50 max per request, the server limit).
72
+ - **Page close** — pending entries are flushed with `fetch(keepalive: true)` on `pagehide`/`visibilitychange`, which unlike `sendBeacon` supports the `X-Api-Key` header.
73
+ - **Failure** — if the server is unreachable or rejects the batch, entries are re-queued (bounded at 200) and a 30-second backoff applies. Logging never blocks nor throws — same philosophy as the NLog target.
74
+ - **Breadcrumbs & context** — every log call (any level) feeds a circular buffer. `Error`/`Fatal` entries carry a `Contexte` JSON with the breadcrumbs, current URL, screen size and language. The server adds the source IP and User-Agent.
75
+ - **Levels** — NLog names: `Trace`, `Debug`, `Info`, `Warn`, `Error`, `Fatal`.
76
+
77
+ ## Server-side setup
78
+
79
+ 1. Generate an API key for your application in the log server admin (Applications page).
80
+ 2. Add your web app's origin to `"CORS origines autorisées"` in the server's `Resources/configuration.json`.
81
+
82
+ ## License
83
+
84
+ MIT
@@ -0,0 +1,154 @@
1
+ // src/breadcrumbs.ts
2
+ var buffer = [];
3
+ var taille = 30;
4
+ function configurerBreadcrumbs(max) {
5
+ taille = max;
6
+ buffer = [];
7
+ }
8
+ function empiler(niveau, logger, message) {
9
+ if (buffer.length >= taille) buffer.shift();
10
+ buffer.push({ horodatage: /* @__PURE__ */ new Date(), niveau, logger, message });
11
+ }
12
+ function formatHeure(d) {
13
+ const p = (n, l = 2) => String(n).padStart(l, "0");
14
+ return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;
15
+ }
16
+ function instantane() {
17
+ return buffer.map((b) => `${formatHeure(b.horodatage)} [${b.niveau}] ${b.logger} \u2014 ${b.message}`);
18
+ }
19
+
20
+ // src/transport.ts
21
+ var FILE_MAX = 200;
22
+ var url = "";
23
+ var apiKey = "";
24
+ var flushMaxEntrees = 20;
25
+ var timer = null;
26
+ var file = [];
27
+ var envoiEnCours = false;
28
+ var backoffJusqua = 0;
29
+ function configurerTransport(options) {
30
+ url = options.url.replace(/\/+$/, "") + "/api/logs/client";
31
+ apiKey = options.apiKey;
32
+ flushMaxEntrees = options.flushMaxEntrees;
33
+ if (timer) clearInterval(timer);
34
+ timer = setInterval(() => void flush(), options.flushIntervalleMs);
35
+ if (typeof window !== "undefined") {
36
+ window.addEventListener("pagehide", () => void flush(true));
37
+ document.addEventListener("visibilitychange", () => {
38
+ if (document.visibilityState === "hidden") void flush(true);
39
+ });
40
+ }
41
+ }
42
+ function envoyer(entree) {
43
+ if (file.length >= FILE_MAX) file.shift();
44
+ file.push(entree);
45
+ if (file.length >= flushMaxEntrees) void flush();
46
+ }
47
+ async function flush(keepalive = false) {
48
+ if (envoiEnCours || file.length === 0 || !url) return;
49
+ if (Date.now() < backoffJusqua && !keepalive) return;
50
+ const lot = file.splice(0, 50);
51
+ envoiEnCours = true;
52
+ try {
53
+ const r\u00E9ponse = await fetch(url, {
54
+ method: "POST",
55
+ headers: { "Content-Type": "application/json", "X-Api-Key": apiKey },
56
+ body: JSON.stringify(lot),
57
+ keepalive
58
+ });
59
+ if (!r\u00E9ponse.ok && r\u00E9ponse.status !== 429) {
60
+ file = [...lot, ...file].slice(0, FILE_MAX);
61
+ backoffJusqua = Date.now() + 3e4;
62
+ }
63
+ } catch {
64
+ file = [...lot, ...file].slice(0, FILE_MAX);
65
+ backoffJusqua = Date.now() + 3e4;
66
+ } finally {
67
+ envoiEnCours = false;
68
+ }
69
+ if (file.length >= flushMaxEntrees && Date.now() >= backoffJusqua) void flush();
70
+ }
71
+
72
+ // src/types.ts
73
+ var NIVEAUX = ["Trace", "Debug", "Info", "Warn", "Error", "Fatal"];
74
+ function rangNiveau(niveau) {
75
+ return NIVEAUX.indexOf(niveau);
76
+ }
77
+
78
+ // src/core.ts
79
+ var initialis\u00E9 = false;
80
+ var version = null;
81
+ var rangEnvoi = rangNiveau("Info");
82
+ function initIdocLogs(options) {
83
+ version = options.version ?? null;
84
+ rangEnvoi = rangNiveau(options.niveauEnvoi ?? "Info");
85
+ configurerBreadcrumbs(options.breadcrumbsMax ?? 30);
86
+ configurerTransport({
87
+ url: options.url,
88
+ apiKey: options.apiKey,
89
+ flushIntervalleMs: options.flushIntervalleMs ?? 5e3,
90
+ flushMaxEntrees: options.flushMaxEntrees ?? 20
91
+ });
92
+ if (options.captureGlobale !== false) activerCaptureGlobale();
93
+ initialis\u00E9 = true;
94
+ }
95
+ function log(niveau, logger, message, exception) {
96
+ empiler(niveau, logger, message);
97
+ if (!initialis\u00E9 || rangNiveau(niveau) < rangEnvoi) return;
98
+ const estErreur = rangNiveau(niveau) >= rangNiveau("Error");
99
+ envoyer({
100
+ Horodatage: (/* @__PURE__ */ new Date()).toISOString(),
101
+ Niveau: niveau,
102
+ Logger: logger,
103
+ Message: message,
104
+ Exception: formaterException(exception),
105
+ Version: version,
106
+ Contexte: estErreur ? construireContexte() : null
107
+ });
108
+ }
109
+ function formaterException(exception) {
110
+ if (exception == null) return null;
111
+ if (exception instanceof Error)
112
+ return exception.stack ?? `${exception.name}: ${exception.message}`;
113
+ return String(exception);
114
+ }
115
+ function construireContexte() {
116
+ return JSON.stringify({
117
+ Breadcrumbs: instantane(),
118
+ Url: typeof location !== "undefined" ? location.href : null,
119
+ Ecran: typeof screen !== "undefined" ? `${screen.width}x${screen.height}` : null,
120
+ Langue: typeof navigator !== "undefined" ? navigator.language : null
121
+ });
122
+ }
123
+ var idocLogs = {
124
+ trace: (logger, message) => log("Trace", logger, message),
125
+ debug: (logger, message) => log("Debug", logger, message),
126
+ info: (logger, message) => log("Info", logger, message),
127
+ warn: (logger, message, exception) => log("Warn", logger, message, exception),
128
+ error: (logger, message, exception) => log("Error", logger, message, exception),
129
+ fatal: (logger, message, exception) => log("Fatal", logger, message, exception)
130
+ };
131
+
132
+ // src/capture.ts
133
+ var activ\u00E9e = false;
134
+ function activerCaptureGlobale() {
135
+ if (activ\u00E9e || typeof window === "undefined") return;
136
+ activ\u00E9e = true;
137
+ window.addEventListener("error", (event) => {
138
+ if (event.error == null && event.message === "") return;
139
+ log("Fatal", "window", event.message || "Erreur non g\xE9r\xE9e", event.error);
140
+ });
141
+ window.addEventListener("unhandledrejection", (event) => {
142
+ const raison = event.reason;
143
+ const message = raison instanceof Error ? raison.message : String(raison);
144
+ log("Error", "window", `Promesse rejet\xE9e non g\xE9r\xE9e : ${message}`, raison);
145
+ });
146
+ }
147
+
148
+ export {
149
+ activerCaptureGlobale,
150
+ initIdocLogs,
151
+ log,
152
+ idocLogs
153
+ };
154
+ //# sourceMappingURL=chunk-TM735D27.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/breadcrumbs.ts","../src/transport.ts","../src/types.ts","../src/core.ts","../src/capture.ts"],"sourcesContent":["import type { Niveau } from \"./types\";\n\ninterface Breadcrumb {\n horodatage: Date;\n niveau: Niveau;\n logger: string;\n message: string;\n}\n\nlet buffer: Breadcrumb[] = [];\nlet taille = 30;\n\nexport function configurerBreadcrumbs(max: number): void {\n taille = max;\n buffer = [];\n}\n\nexport function empiler(niveau: Niveau, logger: string, message: string): void {\n if (buffer.length >= taille) buffer.shift();\n buffer.push({ horodatage: new Date(), niveau, logger, message });\n}\n\nfunction formatHeure(d: Date): string {\n const p = (n: number, l = 2) => String(n).padStart(l, \"0\");\n return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;\n}\n\n/** Instantané du buffer, au format aligné sur la target NLog C#. */\nexport function instantane(): string[] {\n return buffer.map(b => `${formatHeure(b.horodatage)} [${b.niveau}] ${b.logger} — ${b.message}`);\n}\n","import type { LogClientPayload } from \"./types\";\n\n// File d'attente bornée : au-delà, les entrées les plus anciennes sont abandonnées\n// (même philosophie que la target NLog : ne jamais bloquer ni faire gonfler la mémoire).\nconst FILE_MAX = 200;\n\nlet url = \"\";\nlet apiKey = \"\";\nlet flushMaxEntrees = 20;\nlet timer: ReturnType<typeof setInterval> | null = null;\nlet file: LogClientPayload[] = [];\nlet envoiEnCours = false;\nlet backoffJusqua = 0;\n\nexport function configurerTransport(options: {\n url: string;\n apiKey: string;\n flushIntervalleMs: number;\n flushMaxEntrees: number;\n}): void {\n url = options.url.replace(/\\/+$/, \"\") + \"/api/logs/client\";\n apiKey = options.apiKey;\n flushMaxEntrees = options.flushMaxEntrees;\n\n if (timer) clearInterval(timer);\n timer = setInterval(() => void flush(), options.flushIntervalleMs);\n\n if (typeof window !== \"undefined\") {\n // fetch keepalive survit à la fermeture de la page (contrairement à un fetch\n // classique) et, contrairement à sendBeacon, permet le header X-Api-Key.\n window.addEventListener(\"pagehide\", () => void flush(true));\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") void flush(true);\n });\n }\n}\n\nexport function envoyer(entree: LogClientPayload): void {\n if (file.length >= FILE_MAX) file.shift();\n file.push(entree);\n if (file.length >= flushMaxEntrees) void flush();\n}\n\nasync function flush(keepalive = false): Promise<void> {\n if (envoiEnCours || file.length === 0 || !url) return;\n if (Date.now() < backoffJusqua && !keepalive) return;\n\n // Lots de 50 max (limite serveur) ; keepalive limite le corps à ~64 Ko,\n // on reste prudent avec un lot unique dans ce cas.\n const lot = file.splice(0, 50);\n envoiEnCours = true;\n try {\n const réponse = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key\": apiKey },\n body: JSON.stringify(lot),\n keepalive,\n });\n if (!réponse.ok && réponse.status !== 429) {\n // Clé invalide ou erreur serveur : on remet le lot, backoff 30 s.\n file = [...lot, ...file].slice(0, FILE_MAX);\n backoffJusqua = Date.now() + 30_000;\n }\n } catch {\n // Serveur injoignable : abandon silencieux du réseau, backoff 30 s.\n file = [...lot, ...file].slice(0, FILE_MAX);\n backoffJusqua = Date.now() + 30_000;\n } finally {\n envoiEnCours = false;\n }\n\n if (file.length >= flushMaxEntrees && Date.now() >= backoffJusqua) void flush();\n}\n","/** Niveaux NLog, dans l'ordre croissant de sévérité. */\nexport type Niveau = \"Trace\" | \"Debug\" | \"Info\" | \"Warn\" | \"Error\" | \"Fatal\";\n\nexport const NIVEAUX: readonly Niveau[] = [\"Trace\", \"Debug\", \"Info\", \"Warn\", \"Error\", \"Fatal\"];\n\nexport function rangNiveau(niveau: Niveau): number {\n return NIVEAUX.indexOf(niveau);\n}\n\n/** Entrée telle qu'attendue par POST /api/logs/client (PascalCase côté serveur). */\nexport interface LogClientPayload {\n Horodatage: string;\n Niveau: Niveau;\n Logger: string;\n Message: string;\n Exception: string | null;\n Version: string | null;\n Contexte: string | null;\n}\n\nexport interface IdocLogsOptions {\n /** URL de base du serveur de logs, ex. \"https://logs.example.com:5001\". */\n url: string;\n /** Clé API de l'application (générée dans l'admin du serveur de logs). */\n apiKey: string;\n /** Nom de l'application (informatif : le serveur impose celui associé à la clé). */\n application?: string;\n /** Version de l'application, jointe à chaque entrée. */\n version?: string;\n /** Niveau minimum réellement envoyé au serveur (défaut : \"Info\").\n * Les niveaux inférieurs alimentent uniquement les breadcrumbs. */\n niveauEnvoi?: Niveau;\n /** Brancher window.onerror / unhandledrejection (défaut : true). */\n captureGlobale?: boolean;\n /** Taille du buffer de breadcrumbs (défaut : 30). */\n breadcrumbsMax?: number;\n /** Intervalle de flush du lot en millisecondes (défaut : 5000). */\n flushIntervalleMs?: number;\n /** Taille de lot déclenchant un flush immédiat (défaut : 20). */\n flushMaxEntrees?: number;\n}\n","import { configurerBreadcrumbs, empiler, instantane } from \"./breadcrumbs\";\nimport { configurerTransport, envoyer } from \"./transport\";\nimport { activerCaptureGlobale } from \"./capture\";\nimport { rangNiveau, type IdocLogsOptions, type Niveau } from \"./types\";\n\nlet initialisé = false;\nlet version: string | null = null;\nlet rangEnvoi = rangNiveau(\"Info\");\n\n/** Initialise le client. À appeler une fois au démarrage de l'application. */\nexport function initIdocLogs(options: IdocLogsOptions): void {\n version = options.version ?? null;\n rangEnvoi = rangNiveau(options.niveauEnvoi ?? \"Info\");\n\n configurerBreadcrumbs(options.breadcrumbsMax ?? 30);\n configurerTransport({\n url: options.url,\n apiKey: options.apiKey,\n flushIntervalleMs: options.flushIntervalleMs ?? 5000,\n flushMaxEntrees: options.flushMaxEntrees ?? 20,\n });\n\n if (options.captureGlobale !== false) activerCaptureGlobale();\n initialisé = true;\n}\n\nexport function log(niveau: Niveau, logger: string, message: string, exception?: unknown): void {\n empiler(niveau, logger, message);\n if (!initialisé || rangNiveau(niveau) < rangEnvoi) return;\n\n const estErreur = rangNiveau(niveau) >= rangNiveau(\"Error\");\n envoyer({\n Horodatage: new Date().toISOString(),\n Niveau: niveau,\n Logger: logger,\n Message: message,\n Exception: formaterException(exception),\n Version: version,\n Contexte: estErreur ? construireContexte() : null,\n });\n}\n\nfunction formaterException(exception: unknown): string | null {\n if (exception == null) return null;\n if (exception instanceof Error)\n return exception.stack ?? `${exception.name}: ${exception.message}`;\n return String(exception);\n}\n\n/** Contexte joint aux erreurs : breadcrumbs et état de la page,\n * l'équivalent navigateur du contexte process de la target NLog. */\nfunction construireContexte(): string {\n return JSON.stringify({\n Breadcrumbs: instantane(),\n Url: typeof location !== \"undefined\" ? location.href : null,\n Ecran: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : null,\n Langue: typeof navigator !== \"undefined\" ? navigator.language : null,\n });\n}\n\nexport const idocLogs = {\n trace: (logger: string, message: string) => log(\"Trace\", logger, message),\n debug: (logger: string, message: string) => log(\"Debug\", logger, message),\n info: (logger: string, message: string) => log(\"Info\", logger, message),\n warn: (logger: string, message: string, exception?: unknown) => log(\"Warn\", logger, message, exception),\n error: (logger: string, message: string, exception?: unknown) => log(\"Error\", logger, message, exception),\n fatal: (logger: string, message: string, exception?: unknown) => log(\"Fatal\", logger, message, exception),\n};\n","import { log } from \"./core\";\n\nlet activée = false;\n\n/** Branche la capture des erreurs non gérées du navigateur.\n * Appelée automatiquement par initIdocLogs sauf captureGlobale: false. */\nexport function activerCaptureGlobale(): void {\n if (activée || typeof window === \"undefined\") return;\n activée = true;\n\n window.addEventListener(\"error\", event => {\n // Les erreurs de chargement de ressource (img, script…) n'ont pas de message d'erreur JS.\n if (event.error == null && event.message === \"\" ) return;\n log(\"Fatal\", \"window\", event.message || \"Erreur non gérée\", event.error);\n });\n\n window.addEventListener(\"unhandledrejection\", event => {\n const raison = event.reason;\n const message = raison instanceof Error ? raison.message : String(raison);\n log(\"Error\", \"window\", `Promesse rejetée non gérée : ${message}`, raison);\n });\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,47 @@
1
+ /** Niveaux NLog, dans l'ordre croissant de sévérité. */
2
+ type Niveau = "Trace" | "Debug" | "Info" | "Warn" | "Error" | "Fatal";
3
+ /** Entrée telle qu'attendue par POST /api/logs/client (PascalCase côté serveur). */
4
+ interface LogClientPayload {
5
+ Horodatage: string;
6
+ Niveau: Niveau;
7
+ Logger: string;
8
+ Message: string;
9
+ Exception: string | null;
10
+ Version: string | null;
11
+ Contexte: string | null;
12
+ }
13
+ interface IdocLogsOptions {
14
+ /** URL de base du serveur de logs, ex. "https://logs.example.com:5001". */
15
+ url: string;
16
+ /** Clé API de l'application (générée dans l'admin du serveur de logs). */
17
+ apiKey: string;
18
+ /** Nom de l'application (informatif : le serveur impose celui associé à la clé). */
19
+ application?: string;
20
+ /** Version de l'application, jointe à chaque entrée. */
21
+ version?: string;
22
+ /** Niveau minimum réellement envoyé au serveur (défaut : "Info").
23
+ * Les niveaux inférieurs alimentent uniquement les breadcrumbs. */
24
+ niveauEnvoi?: Niveau;
25
+ /** Brancher window.onerror / unhandledrejection (défaut : true). */
26
+ captureGlobale?: boolean;
27
+ /** Taille du buffer de breadcrumbs (défaut : 30). */
28
+ breadcrumbsMax?: number;
29
+ /** Intervalle de flush du lot en millisecondes (défaut : 5000). */
30
+ flushIntervalleMs?: number;
31
+ /** Taille de lot déclenchant un flush immédiat (défaut : 20). */
32
+ flushMaxEntrees?: number;
33
+ }
34
+
35
+ /** Initialise le client. À appeler une fois au démarrage de l'application. */
36
+ declare function initIdocLogs(options: IdocLogsOptions): void;
37
+ declare function log(niveau: Niveau, logger: string, message: string, exception?: unknown): void;
38
+ declare const idocLogs: {
39
+ trace: (logger: string, message: string) => void;
40
+ debug: (logger: string, message: string) => void;
41
+ info: (logger: string, message: string) => void;
42
+ warn: (logger: string, message: string, exception?: unknown) => void;
43
+ error: (logger: string, message: string, exception?: unknown) => void;
44
+ fatal: (logger: string, message: string, exception?: unknown) => void;
45
+ };
46
+
47
+ export { type IdocLogsOptions as I, type LogClientPayload as L, type Niveau as N, initIdocLogs as a, idocLogs as i, log as l };
@@ -0,0 +1,47 @@
1
+ /** Niveaux NLog, dans l'ordre croissant de sévérité. */
2
+ type Niveau = "Trace" | "Debug" | "Info" | "Warn" | "Error" | "Fatal";
3
+ /** Entrée telle qu'attendue par POST /api/logs/client (PascalCase côté serveur). */
4
+ interface LogClientPayload {
5
+ Horodatage: string;
6
+ Niveau: Niveau;
7
+ Logger: string;
8
+ Message: string;
9
+ Exception: string | null;
10
+ Version: string | null;
11
+ Contexte: string | null;
12
+ }
13
+ interface IdocLogsOptions {
14
+ /** URL de base du serveur de logs, ex. "https://logs.example.com:5001". */
15
+ url: string;
16
+ /** Clé API de l'application (générée dans l'admin du serveur de logs). */
17
+ apiKey: string;
18
+ /** Nom de l'application (informatif : le serveur impose celui associé à la clé). */
19
+ application?: string;
20
+ /** Version de l'application, jointe à chaque entrée. */
21
+ version?: string;
22
+ /** Niveau minimum réellement envoyé au serveur (défaut : "Info").
23
+ * Les niveaux inférieurs alimentent uniquement les breadcrumbs. */
24
+ niveauEnvoi?: Niveau;
25
+ /** Brancher window.onerror / unhandledrejection (défaut : true). */
26
+ captureGlobale?: boolean;
27
+ /** Taille du buffer de breadcrumbs (défaut : 30). */
28
+ breadcrumbsMax?: number;
29
+ /** Intervalle de flush du lot en millisecondes (défaut : 5000). */
30
+ flushIntervalleMs?: number;
31
+ /** Taille de lot déclenchant un flush immédiat (défaut : 20). */
32
+ flushMaxEntrees?: number;
33
+ }
34
+
35
+ /** Initialise le client. À appeler une fois au démarrage de l'application. */
36
+ declare function initIdocLogs(options: IdocLogsOptions): void;
37
+ declare function log(niveau: Niveau, logger: string, message: string, exception?: unknown): void;
38
+ declare const idocLogs: {
39
+ trace: (logger: string, message: string) => void;
40
+ debug: (logger: string, message: string) => void;
41
+ info: (logger: string, message: string) => void;
42
+ warn: (logger: string, message: string, exception?: unknown) => void;
43
+ error: (logger: string, message: string, exception?: unknown) => void;
44
+ fatal: (logger: string, message: string, exception?: unknown) => void;
45
+ };
46
+
47
+ export { type IdocLogsOptions as I, type LogClientPayload as L, type Niveau as N, initIdocLogs as a, idocLogs as i, log as l };
package/dist/index.cjs ADDED
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var src_exports = {};
22
+ __export(src_exports, {
23
+ activerCaptureGlobale: () => activerCaptureGlobale,
24
+ idocLogs: () => idocLogs,
25
+ initIdocLogs: () => initIdocLogs,
26
+ log: () => log
27
+ });
28
+ module.exports = __toCommonJS(src_exports);
29
+
30
+ // src/breadcrumbs.ts
31
+ var buffer = [];
32
+ var taille = 30;
33
+ function configurerBreadcrumbs(max) {
34
+ taille = max;
35
+ buffer = [];
36
+ }
37
+ function empiler(niveau, logger, message) {
38
+ if (buffer.length >= taille) buffer.shift();
39
+ buffer.push({ horodatage: /* @__PURE__ */ new Date(), niveau, logger, message });
40
+ }
41
+ function formatHeure(d) {
42
+ const p = (n, l = 2) => String(n).padStart(l, "0");
43
+ return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;
44
+ }
45
+ function instantane() {
46
+ return buffer.map((b) => `${formatHeure(b.horodatage)} [${b.niveau}] ${b.logger} \u2014 ${b.message}`);
47
+ }
48
+
49
+ // src/transport.ts
50
+ var FILE_MAX = 200;
51
+ var url = "";
52
+ var apiKey = "";
53
+ var flushMaxEntrees = 20;
54
+ var timer = null;
55
+ var file = [];
56
+ var envoiEnCours = false;
57
+ var backoffJusqua = 0;
58
+ function configurerTransport(options) {
59
+ url = options.url.replace(/\/+$/, "") + "/api/logs/client";
60
+ apiKey = options.apiKey;
61
+ flushMaxEntrees = options.flushMaxEntrees;
62
+ if (timer) clearInterval(timer);
63
+ timer = setInterval(() => void flush(), options.flushIntervalleMs);
64
+ if (typeof window !== "undefined") {
65
+ window.addEventListener("pagehide", () => void flush(true));
66
+ document.addEventListener("visibilitychange", () => {
67
+ if (document.visibilityState === "hidden") void flush(true);
68
+ });
69
+ }
70
+ }
71
+ function envoyer(entree) {
72
+ if (file.length >= FILE_MAX) file.shift();
73
+ file.push(entree);
74
+ if (file.length >= flushMaxEntrees) void flush();
75
+ }
76
+ async function flush(keepalive = false) {
77
+ if (envoiEnCours || file.length === 0 || !url) return;
78
+ if (Date.now() < backoffJusqua && !keepalive) return;
79
+ const lot = file.splice(0, 50);
80
+ envoiEnCours = true;
81
+ try {
82
+ const r\u00E9ponse = await fetch(url, {
83
+ method: "POST",
84
+ headers: { "Content-Type": "application/json", "X-Api-Key": apiKey },
85
+ body: JSON.stringify(lot),
86
+ keepalive
87
+ });
88
+ if (!r\u00E9ponse.ok && r\u00E9ponse.status !== 429) {
89
+ file = [...lot, ...file].slice(0, FILE_MAX);
90
+ backoffJusqua = Date.now() + 3e4;
91
+ }
92
+ } catch {
93
+ file = [...lot, ...file].slice(0, FILE_MAX);
94
+ backoffJusqua = Date.now() + 3e4;
95
+ } finally {
96
+ envoiEnCours = false;
97
+ }
98
+ if (file.length >= flushMaxEntrees && Date.now() >= backoffJusqua) void flush();
99
+ }
100
+
101
+ // src/capture.ts
102
+ var activ\u00E9e = false;
103
+ function activerCaptureGlobale() {
104
+ if (activ\u00E9e || typeof window === "undefined") return;
105
+ activ\u00E9e = true;
106
+ window.addEventListener("error", (event) => {
107
+ if (event.error == null && event.message === "") return;
108
+ log("Fatal", "window", event.message || "Erreur non g\xE9r\xE9e", event.error);
109
+ });
110
+ window.addEventListener("unhandledrejection", (event) => {
111
+ const raison = event.reason;
112
+ const message = raison instanceof Error ? raison.message : String(raison);
113
+ log("Error", "window", `Promesse rejet\xE9e non g\xE9r\xE9e : ${message}`, raison);
114
+ });
115
+ }
116
+
117
+ // src/types.ts
118
+ var NIVEAUX = ["Trace", "Debug", "Info", "Warn", "Error", "Fatal"];
119
+ function rangNiveau(niveau) {
120
+ return NIVEAUX.indexOf(niveau);
121
+ }
122
+
123
+ // src/core.ts
124
+ var initialis\u00E9 = false;
125
+ var version = null;
126
+ var rangEnvoi = rangNiveau("Info");
127
+ function initIdocLogs(options) {
128
+ version = options.version ?? null;
129
+ rangEnvoi = rangNiveau(options.niveauEnvoi ?? "Info");
130
+ configurerBreadcrumbs(options.breadcrumbsMax ?? 30);
131
+ configurerTransport({
132
+ url: options.url,
133
+ apiKey: options.apiKey,
134
+ flushIntervalleMs: options.flushIntervalleMs ?? 5e3,
135
+ flushMaxEntrees: options.flushMaxEntrees ?? 20
136
+ });
137
+ if (options.captureGlobale !== false) activerCaptureGlobale();
138
+ initialis\u00E9 = true;
139
+ }
140
+ function log(niveau, logger, message, exception) {
141
+ empiler(niveau, logger, message);
142
+ if (!initialis\u00E9 || rangNiveau(niveau) < rangEnvoi) return;
143
+ const estErreur = rangNiveau(niveau) >= rangNiveau("Error");
144
+ envoyer({
145
+ Horodatage: (/* @__PURE__ */ new Date()).toISOString(),
146
+ Niveau: niveau,
147
+ Logger: logger,
148
+ Message: message,
149
+ Exception: formaterException(exception),
150
+ Version: version,
151
+ Contexte: estErreur ? construireContexte() : null
152
+ });
153
+ }
154
+ function formaterException(exception) {
155
+ if (exception == null) return null;
156
+ if (exception instanceof Error)
157
+ return exception.stack ?? `${exception.name}: ${exception.message}`;
158
+ return String(exception);
159
+ }
160
+ function construireContexte() {
161
+ return JSON.stringify({
162
+ Breadcrumbs: instantane(),
163
+ Url: typeof location !== "undefined" ? location.href : null,
164
+ Ecran: typeof screen !== "undefined" ? `${screen.width}x${screen.height}` : null,
165
+ Langue: typeof navigator !== "undefined" ? navigator.language : null
166
+ });
167
+ }
168
+ var idocLogs = {
169
+ trace: (logger, message) => log("Trace", logger, message),
170
+ debug: (logger, message) => log("Debug", logger, message),
171
+ info: (logger, message) => log("Info", logger, message),
172
+ warn: (logger, message, exception) => log("Warn", logger, message, exception),
173
+ error: (logger, message, exception) => log("Error", logger, message, exception),
174
+ fatal: (logger, message, exception) => log("Fatal", logger, message, exception)
175
+ };
176
+ // Annotate the CommonJS export names for ESM import in node:
177
+ 0 && (module.exports = {
178
+ activerCaptureGlobale,
179
+ idocLogs,
180
+ initIdocLogs,
181
+ log
182
+ });
183
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/breadcrumbs.ts","../src/transport.ts","../src/capture.ts","../src/types.ts","../src/core.ts"],"sourcesContent":["export { initIdocLogs, idocLogs, log } from \"./core\";\nexport { activerCaptureGlobale } from \"./capture\";\nexport type { IdocLogsOptions, Niveau, LogClientPayload } from \"./types\";\n","import type { Niveau } from \"./types\";\n\ninterface Breadcrumb {\n horodatage: Date;\n niveau: Niveau;\n logger: string;\n message: string;\n}\n\nlet buffer: Breadcrumb[] = [];\nlet taille = 30;\n\nexport function configurerBreadcrumbs(max: number): void {\n taille = max;\n buffer = [];\n}\n\nexport function empiler(niveau: Niveau, logger: string, message: string): void {\n if (buffer.length >= taille) buffer.shift();\n buffer.push({ horodatage: new Date(), niveau, logger, message });\n}\n\nfunction formatHeure(d: Date): string {\n const p = (n: number, l = 2) => String(n).padStart(l, \"0\");\n return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;\n}\n\n/** Instantané du buffer, au format aligné sur la target NLog C#. */\nexport function instantane(): string[] {\n return buffer.map(b => `${formatHeure(b.horodatage)} [${b.niveau}] ${b.logger} — ${b.message}`);\n}\n","import type { LogClientPayload } from \"./types\";\n\n// File d'attente bornée : au-delà, les entrées les plus anciennes sont abandonnées\n// (même philosophie que la target NLog : ne jamais bloquer ni faire gonfler la mémoire).\nconst FILE_MAX = 200;\n\nlet url = \"\";\nlet apiKey = \"\";\nlet flushMaxEntrees = 20;\nlet timer: ReturnType<typeof setInterval> | null = null;\nlet file: LogClientPayload[] = [];\nlet envoiEnCours = false;\nlet backoffJusqua = 0;\n\nexport function configurerTransport(options: {\n url: string;\n apiKey: string;\n flushIntervalleMs: number;\n flushMaxEntrees: number;\n}): void {\n url = options.url.replace(/\\/+$/, \"\") + \"/api/logs/client\";\n apiKey = options.apiKey;\n flushMaxEntrees = options.flushMaxEntrees;\n\n if (timer) clearInterval(timer);\n timer = setInterval(() => void flush(), options.flushIntervalleMs);\n\n if (typeof window !== \"undefined\") {\n // fetch keepalive survit à la fermeture de la page (contrairement à un fetch\n // classique) et, contrairement à sendBeacon, permet le header X-Api-Key.\n window.addEventListener(\"pagehide\", () => void flush(true));\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") void flush(true);\n });\n }\n}\n\nexport function envoyer(entree: LogClientPayload): void {\n if (file.length >= FILE_MAX) file.shift();\n file.push(entree);\n if (file.length >= flushMaxEntrees) void flush();\n}\n\nasync function flush(keepalive = false): Promise<void> {\n if (envoiEnCours || file.length === 0 || !url) return;\n if (Date.now() < backoffJusqua && !keepalive) return;\n\n // Lots de 50 max (limite serveur) ; keepalive limite le corps à ~64 Ko,\n // on reste prudent avec un lot unique dans ce cas.\n const lot = file.splice(0, 50);\n envoiEnCours = true;\n try {\n const réponse = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key\": apiKey },\n body: JSON.stringify(lot),\n keepalive,\n });\n if (!réponse.ok && réponse.status !== 429) {\n // Clé invalide ou erreur serveur : on remet le lot, backoff 30 s.\n file = [...lot, ...file].slice(0, FILE_MAX);\n backoffJusqua = Date.now() + 30_000;\n }\n } catch {\n // Serveur injoignable : abandon silencieux du réseau, backoff 30 s.\n file = [...lot, ...file].slice(0, FILE_MAX);\n backoffJusqua = Date.now() + 30_000;\n } finally {\n envoiEnCours = false;\n }\n\n if (file.length >= flushMaxEntrees && Date.now() >= backoffJusqua) void flush();\n}\n","import { log } from \"./core\";\n\nlet activée = false;\n\n/** Branche la capture des erreurs non gérées du navigateur.\n * Appelée automatiquement par initIdocLogs sauf captureGlobale: false. */\nexport function activerCaptureGlobale(): void {\n if (activée || typeof window === \"undefined\") return;\n activée = true;\n\n window.addEventListener(\"error\", event => {\n // Les erreurs de chargement de ressource (img, script…) n'ont pas de message d'erreur JS.\n if (event.error == null && event.message === \"\" ) return;\n log(\"Fatal\", \"window\", event.message || \"Erreur non gérée\", event.error);\n });\n\n window.addEventListener(\"unhandledrejection\", event => {\n const raison = event.reason;\n const message = raison instanceof Error ? raison.message : String(raison);\n log(\"Error\", \"window\", `Promesse rejetée non gérée : ${message}`, raison);\n });\n}\n","/** Niveaux NLog, dans l'ordre croissant de sévérité. */\nexport type Niveau = \"Trace\" | \"Debug\" | \"Info\" | \"Warn\" | \"Error\" | \"Fatal\";\n\nexport const NIVEAUX: readonly Niveau[] = [\"Trace\", \"Debug\", \"Info\", \"Warn\", \"Error\", \"Fatal\"];\n\nexport function rangNiveau(niveau: Niveau): number {\n return NIVEAUX.indexOf(niveau);\n}\n\n/** Entrée telle qu'attendue par POST /api/logs/client (PascalCase côté serveur). */\nexport interface LogClientPayload {\n Horodatage: string;\n Niveau: Niveau;\n Logger: string;\n Message: string;\n Exception: string | null;\n Version: string | null;\n Contexte: string | null;\n}\n\nexport interface IdocLogsOptions {\n /** URL de base du serveur de logs, ex. \"https://logs.example.com:5001\". */\n url: string;\n /** Clé API de l'application (générée dans l'admin du serveur de logs). */\n apiKey: string;\n /** Nom de l'application (informatif : le serveur impose celui associé à la clé). */\n application?: string;\n /** Version de l'application, jointe à chaque entrée. */\n version?: string;\n /** Niveau minimum réellement envoyé au serveur (défaut : \"Info\").\n * Les niveaux inférieurs alimentent uniquement les breadcrumbs. */\n niveauEnvoi?: Niveau;\n /** Brancher window.onerror / unhandledrejection (défaut : true). */\n captureGlobale?: boolean;\n /** Taille du buffer de breadcrumbs (défaut : 30). */\n breadcrumbsMax?: number;\n /** Intervalle de flush du lot en millisecondes (défaut : 5000). */\n flushIntervalleMs?: number;\n /** Taille de lot déclenchant un flush immédiat (défaut : 20). */\n flushMaxEntrees?: number;\n}\n","import { configurerBreadcrumbs, empiler, instantane } from \"./breadcrumbs\";\nimport { configurerTransport, envoyer } from \"./transport\";\nimport { activerCaptureGlobale } from \"./capture\";\nimport { rangNiveau, type IdocLogsOptions, type Niveau } from \"./types\";\n\nlet initialisé = false;\nlet version: string | null = null;\nlet rangEnvoi = rangNiveau(\"Info\");\n\n/** Initialise le client. À appeler une fois au démarrage de l'application. */\nexport function initIdocLogs(options: IdocLogsOptions): void {\n version = options.version ?? null;\n rangEnvoi = rangNiveau(options.niveauEnvoi ?? \"Info\");\n\n configurerBreadcrumbs(options.breadcrumbsMax ?? 30);\n configurerTransport({\n url: options.url,\n apiKey: options.apiKey,\n flushIntervalleMs: options.flushIntervalleMs ?? 5000,\n flushMaxEntrees: options.flushMaxEntrees ?? 20,\n });\n\n if (options.captureGlobale !== false) activerCaptureGlobale();\n initialisé = true;\n}\n\nexport function log(niveau: Niveau, logger: string, message: string, exception?: unknown): void {\n empiler(niveau, logger, message);\n if (!initialisé || rangNiveau(niveau) < rangEnvoi) return;\n\n const estErreur = rangNiveau(niveau) >= rangNiveau(\"Error\");\n envoyer({\n Horodatage: new Date().toISOString(),\n Niveau: niveau,\n Logger: logger,\n Message: message,\n Exception: formaterException(exception),\n Version: version,\n Contexte: estErreur ? construireContexte() : null,\n });\n}\n\nfunction formaterException(exception: unknown): string | null {\n if (exception == null) return null;\n if (exception instanceof Error)\n return exception.stack ?? `${exception.name}: ${exception.message}`;\n return String(exception);\n}\n\n/** Contexte joint aux erreurs : breadcrumbs et état de la page,\n * l'équivalent navigateur du contexte process de la target NLog. */\nfunction construireContexte(): string {\n return JSON.stringify({\n Breadcrumbs: instantane(),\n Url: typeof location !== \"undefined\" ? location.href : null,\n Ecran: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : null,\n Langue: typeof navigator !== \"undefined\" ? navigator.language : null,\n });\n}\n\nexport const idocLogs = {\n trace: (logger: string, message: string) => log(\"Trace\", logger, message),\n debug: (logger: string, message: string) => log(\"Debug\", logger, message),\n info: (logger: string, message: string) => log(\"Info\", logger, message),\n warn: (logger: string, message: string, exception?: unknown) => log(\"Warn\", logger, message, exception),\n error: (logger: string, message: string, exception?: unknown) => log(\"Error\", logger, message, exception),\n fatal: (logger: string, message: string, exception?: unknown) => log(\"Fatal\", logger, message, exception),\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACSA,IAAI,SAAuB,CAAC;AAC5B,IAAI,SAAS;AAEN,SAAS,sBAAsB,KAAmB;AACvD,WAAS;AACT,WAAS,CAAC;AACZ;AAEO,SAAS,QAAQ,QAAgB,QAAgB,SAAuB;AAC7E,MAAI,OAAO,UAAU,OAAQ,QAAO,MAAM;AAC1C,SAAO,KAAK,EAAE,YAAY,oBAAI,KAAK,GAAG,QAAQ,QAAQ,QAAQ,CAAC;AACjE;AAEA,SAAS,YAAY,GAAiB;AACpC,QAAM,IAAI,CAAC,GAAW,IAAI,MAAM,OAAO,CAAC,EAAE,SAAS,GAAG,GAAG;AACzD,SAAO,GAAG,EAAE,EAAE,SAAS,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,WAAW,CAAC,CAAC,IAAI,EAAE,EAAE,gBAAgB,GAAG,CAAC,CAAC;AAClG;AAGO,SAAS,aAAuB;AACrC,SAAO,OAAO,IAAI,OAAK,GAAG,YAAY,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,KAAK,EAAE,MAAM,WAAM,EAAE,OAAO,EAAE;AAChG;;;AC1BA,IAAM,WAAW;AAEjB,IAAI,MAAM;AACV,IAAI,SAAS;AACb,IAAI,kBAAkB;AACtB,IAAI,QAA+C;AACnD,IAAI,OAA2B,CAAC;AAChC,IAAI,eAAe;AACnB,IAAI,gBAAgB;AAEb,SAAS,oBAAoB,SAK3B;AACP,QAAM,QAAQ,IAAI,QAAQ,QAAQ,EAAE,IAAI;AACxC,WAAS,QAAQ;AACjB,oBAAkB,QAAQ;AAE1B,MAAI,MAAO,eAAc,KAAK;AAC9B,UAAQ,YAAY,MAAM,KAAK,MAAM,GAAG,QAAQ,iBAAiB;AAEjE,MAAI,OAAO,WAAW,aAAa;AAGjC,WAAO,iBAAiB,YAAY,MAAM,KAAK,MAAM,IAAI,CAAC;AAC1D,aAAS,iBAAiB,oBAAoB,MAAM;AAClD,UAAI,SAAS,oBAAoB,SAAU,MAAK,MAAM,IAAI;AAAA,IAC5D,CAAC;AAAA,EACH;AACF;AAEO,SAAS,QAAQ,QAAgC;AACtD,MAAI,KAAK,UAAU,SAAU,MAAK,MAAM;AACxC,OAAK,KAAK,MAAM;AAChB,MAAI,KAAK,UAAU,gBAAiB,MAAK,MAAM;AACjD;AAEA,eAAe,MAAM,YAAY,OAAsB;AACrD,MAAI,gBAAgB,KAAK,WAAW,KAAK,CAAC,IAAK;AAC/C,MAAI,KAAK,IAAI,IAAI,iBAAiB,CAAC,UAAW;AAI9C,QAAM,MAAM,KAAK,OAAO,GAAG,EAAE;AAC7B,iBAAe;AACf,MAAI;AACF,UAAM,eAAU,MAAM,MAAM,KAAK;AAAA,MAC/B,QAAQ;AAAA,MACR,SAAS,EAAE,gBAAgB,oBAAoB,aAAa,OAAO;AAAA,MACnE,MAAM,KAAK,UAAU,GAAG;AAAA,MACxB;AAAA,IACF,CAAC;AACD,QAAI,CAAC,aAAQ,MAAM,aAAQ,WAAW,KAAK;AAEzC,aAAO,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,MAAM,GAAG,QAAQ;AAC1C,sBAAgB,KAAK,IAAI,IAAI;AAAA,IAC/B;AAAA,EACF,QAAQ;AAEN,WAAO,CAAC,GAAG,KAAK,GAAG,IAAI,EAAE,MAAM,GAAG,QAAQ;AAC1C,oBAAgB,KAAK,IAAI,IAAI;AAAA,EAC/B,UAAE;AACA,mBAAe;AAAA,EACjB;AAEA,MAAI,KAAK,UAAU,mBAAmB,KAAK,IAAI,KAAK,cAAe,MAAK,MAAM;AAChF;;;ACtEA,IAAI,eAAU;AAIP,SAAS,wBAA8B;AAC5C,MAAI,gBAAW,OAAO,WAAW,YAAa;AAC9C,iBAAU;AAEV,SAAO,iBAAiB,SAAS,WAAS;AAExC,QAAI,MAAM,SAAS,QAAQ,MAAM,YAAY,GAAK;AAClD,QAAI,SAAS,UAAU,MAAM,WAAW,0BAAoB,MAAM,KAAK;AAAA,EACzE,CAAC;AAED,SAAO,iBAAiB,sBAAsB,WAAS;AACrD,UAAM,SAAS,MAAM;AACrB,UAAM,UAAU,kBAAkB,QAAQ,OAAO,UAAU,OAAO,MAAM;AACxE,QAAI,SAAS,UAAU,yCAAgC,OAAO,IAAI,MAAM;AAAA,EAC1E,CAAC;AACH;;;AClBO,IAAM,UAA6B,CAAC,SAAS,SAAS,QAAQ,QAAQ,SAAS,OAAO;AAEtF,SAAS,WAAW,QAAwB;AACjD,SAAO,QAAQ,QAAQ,MAAM;AAC/B;;;ACFA,IAAI,kBAAa;AACjB,IAAI,UAAyB;AAC7B,IAAI,YAAY,WAAW,MAAM;AAG1B,SAAS,aAAa,SAAgC;AAC3D,YAAU,QAAQ,WAAW;AAC7B,cAAY,WAAW,QAAQ,eAAe,MAAM;AAEpD,wBAAsB,QAAQ,kBAAkB,EAAE;AAClD,sBAAoB;AAAA,IAClB,KAAK,QAAQ;AAAA,IACb,QAAQ,QAAQ;AAAA,IAChB,mBAAmB,QAAQ,qBAAqB;AAAA,IAChD,iBAAiB,QAAQ,mBAAmB;AAAA,EAC9C,CAAC;AAED,MAAI,QAAQ,mBAAmB,MAAO,uBAAsB;AAC5D,oBAAa;AACf;AAEO,SAAS,IAAI,QAAgB,QAAgB,SAAiB,WAA2B;AAC9F,UAAQ,QAAQ,QAAQ,OAAO;AAC/B,MAAI,CAAC,mBAAc,WAAW,MAAM,IAAI,UAAW;AAEnD,QAAM,YAAY,WAAW,MAAM,KAAK,WAAW,OAAO;AAC1D,UAAQ;AAAA,IACN,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,IACnC,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,IACT,WAAW,kBAAkB,SAAS;AAAA,IACtC,SAAS;AAAA,IACT,UAAU,YAAY,mBAAmB,IAAI;AAAA,EAC/C,CAAC;AACH;AAEA,SAAS,kBAAkB,WAAmC;AAC5D,MAAI,aAAa,KAAM,QAAO;AAC9B,MAAI,qBAAqB;AACvB,WAAO,UAAU,SAAS,GAAG,UAAU,IAAI,KAAK,UAAU,OAAO;AACnE,SAAO,OAAO,SAAS;AACzB;AAIA,SAAS,qBAA6B;AACpC,SAAO,KAAK,UAAU;AAAA,IACpB,aAAa,WAAW;AAAA,IACxB,KAAK,OAAO,aAAa,cAAc,SAAS,OAAO;AAAA,IACvD,OAAO,OAAO,WAAW,cAAc,GAAG,OAAO,KAAK,IAAI,OAAO,MAAM,KAAK;AAAA,IAC5E,QAAQ,OAAO,cAAc,cAAc,UAAU,WAAW;AAAA,EAClE,CAAC;AACH;AAEO,IAAM,WAAW;AAAA,EACtB,OAAO,CAAC,QAAgB,YAAoB,IAAI,SAAS,QAAQ,OAAO;AAAA,EACxE,OAAO,CAAC,QAAgB,YAAoB,IAAI,SAAS,QAAQ,OAAO;AAAA,EACxE,MAAM,CAAC,QAAgB,YAAoB,IAAI,QAAQ,QAAQ,OAAO;AAAA,EACtE,MAAM,CAAC,QAAgB,SAAiB,cAAwB,IAAI,QAAQ,QAAQ,SAAS,SAAS;AAAA,EACtG,OAAO,CAAC,QAAgB,SAAiB,cAAwB,IAAI,SAAS,QAAQ,SAAS,SAAS;AAAA,EACxG,OAAO,CAAC,QAAgB,SAAiB,cAAwB,IAAI,SAAS,QAAQ,SAAS,SAAS;AAC1G;","names":[]}
@@ -0,0 +1,7 @@
1
+ export { I as IdocLogsOptions, L as LogClientPayload, N as Niveau, i as idocLogs, a as initIdocLogs, l as log } from './core-xTdevcDU.cjs';
2
+
3
+ /** Branche la capture des erreurs non gérées du navigateur.
4
+ * Appelée automatiquement par initIdocLogs sauf captureGlobale: false. */
5
+ declare function activerCaptureGlobale(): void;
6
+
7
+ export { activerCaptureGlobale };
@@ -0,0 +1,7 @@
1
+ export { I as IdocLogsOptions, L as LogClientPayload, N as Niveau, i as idocLogs, a as initIdocLogs, l as log } from './core-xTdevcDU.js';
2
+
3
+ /** Branche la capture des erreurs non gérées du navigateur.
4
+ * Appelée automatiquement par initIdocLogs sauf captureGlobale: false. */
5
+ declare function activerCaptureGlobale(): void;
6
+
7
+ export { activerCaptureGlobale };
package/dist/index.js ADDED
@@ -0,0 +1,13 @@
1
+ import {
2
+ activerCaptureGlobale,
3
+ idocLogs,
4
+ initIdocLogs,
5
+ log
6
+ } from "./chunk-TM735D27.js";
7
+ export {
8
+ activerCaptureGlobale,
9
+ idocLogs,
10
+ initIdocLogs,
11
+ log
12
+ };
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/dist/react.cjs ADDED
@@ -0,0 +1,160 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/react.tsx
21
+ var react_exports = {};
22
+ __export(react_exports, {
23
+ IdocLogsErrorBoundary: () => IdocLogsErrorBoundary,
24
+ useIdocLogger: () => useIdocLogger
25
+ });
26
+ module.exports = __toCommonJS(react_exports);
27
+ var import_react = require("react");
28
+
29
+ // src/breadcrumbs.ts
30
+ var buffer = [];
31
+ var taille = 30;
32
+ function empiler(niveau, logger, message) {
33
+ if (buffer.length >= taille) buffer.shift();
34
+ buffer.push({ horodatage: /* @__PURE__ */ new Date(), niveau, logger, message });
35
+ }
36
+ function formatHeure(d) {
37
+ const p = (n, l = 2) => String(n).padStart(l, "0");
38
+ return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;
39
+ }
40
+ function instantane() {
41
+ return buffer.map((b) => `${formatHeure(b.horodatage)} [${b.niveau}] ${b.logger} \u2014 ${b.message}`);
42
+ }
43
+
44
+ // src/transport.ts
45
+ var FILE_MAX = 200;
46
+ var url = "";
47
+ var apiKey = "";
48
+ var flushMaxEntrees = 20;
49
+ var file = [];
50
+ var envoiEnCours = false;
51
+ var backoffJusqua = 0;
52
+ function envoyer(entree) {
53
+ if (file.length >= FILE_MAX) file.shift();
54
+ file.push(entree);
55
+ if (file.length >= flushMaxEntrees) void flush();
56
+ }
57
+ async function flush(keepalive = false) {
58
+ if (envoiEnCours || file.length === 0 || !url) return;
59
+ if (Date.now() < backoffJusqua && !keepalive) return;
60
+ const lot = file.splice(0, 50);
61
+ envoiEnCours = true;
62
+ try {
63
+ const r\u00E9ponse = await fetch(url, {
64
+ method: "POST",
65
+ headers: { "Content-Type": "application/json", "X-Api-Key": apiKey },
66
+ body: JSON.stringify(lot),
67
+ keepalive
68
+ });
69
+ if (!r\u00E9ponse.ok && r\u00E9ponse.status !== 429) {
70
+ file = [...lot, ...file].slice(0, FILE_MAX);
71
+ backoffJusqua = Date.now() + 3e4;
72
+ }
73
+ } catch {
74
+ file = [...lot, ...file].slice(0, FILE_MAX);
75
+ backoffJusqua = Date.now() + 3e4;
76
+ } finally {
77
+ envoiEnCours = false;
78
+ }
79
+ if (file.length >= flushMaxEntrees && Date.now() >= backoffJusqua) void flush();
80
+ }
81
+
82
+ // src/types.ts
83
+ var NIVEAUX = ["Trace", "Debug", "Info", "Warn", "Error", "Fatal"];
84
+ function rangNiveau(niveau) {
85
+ return NIVEAUX.indexOf(niveau);
86
+ }
87
+
88
+ // src/core.ts
89
+ var initialis\u00E9 = false;
90
+ var version = null;
91
+ var rangEnvoi = rangNiveau("Info");
92
+ function log(niveau, logger, message, exception) {
93
+ empiler(niveau, logger, message);
94
+ if (!initialis\u00E9 || rangNiveau(niveau) < rangEnvoi) return;
95
+ const estErreur = rangNiveau(niveau) >= rangNiveau("Error");
96
+ envoyer({
97
+ Horodatage: (/* @__PURE__ */ new Date()).toISOString(),
98
+ Niveau: niveau,
99
+ Logger: logger,
100
+ Message: message,
101
+ Exception: formaterException(exception),
102
+ Version: version,
103
+ Contexte: estErreur ? construireContexte() : null
104
+ });
105
+ }
106
+ function formaterException(exception) {
107
+ if (exception == null) return null;
108
+ if (exception instanceof Error)
109
+ return exception.stack ?? `${exception.name}: ${exception.message}`;
110
+ return String(exception);
111
+ }
112
+ function construireContexte() {
113
+ return JSON.stringify({
114
+ Breadcrumbs: instantane(),
115
+ Url: typeof location !== "undefined" ? location.href : null,
116
+ Ecran: typeof screen !== "undefined" ? `${screen.width}x${screen.height}` : null,
117
+ Langue: typeof navigator !== "undefined" ? navigator.language : null
118
+ });
119
+ }
120
+ var idocLogs = {
121
+ trace: (logger, message) => log("Trace", logger, message),
122
+ debug: (logger, message) => log("Debug", logger, message),
123
+ info: (logger, message) => log("Info", logger, message),
124
+ warn: (logger, message, exception) => log("Warn", logger, message, exception),
125
+ error: (logger, message, exception) => log("Error", logger, message, exception),
126
+ fatal: (logger, message, exception) => log("Fatal", logger, message, exception)
127
+ };
128
+
129
+ // src/react.tsx
130
+ var IdocLogsErrorBoundary = class extends import_react.Component {
131
+ constructor() {
132
+ super(...arguments);
133
+ this.state = { error: null };
134
+ this.r\u00E9initialiser = () => this.setState({ error: null });
135
+ }
136
+ static getDerivedStateFromError(error) {
137
+ return { error };
138
+ }
139
+ componentDidCatch(error, info) {
140
+ const pile = info.componentStack ? `
141
+ Composants :${info.componentStack}` : "";
142
+ log("Fatal", this.props.logger ?? "react", `${error.message}${pile}`, error);
143
+ }
144
+ render() {
145
+ const { error } = this.state;
146
+ if (error === null) return this.props.children;
147
+ const { fallback } = this.props;
148
+ if (typeof fallback === "function") return fallback(error, this.r\u00E9initialiser);
149
+ return fallback ?? null;
150
+ }
151
+ };
152
+ function useIdocLogger() {
153
+ return idocLogs;
154
+ }
155
+ // Annotate the CommonJS export names for ESM import in node:
156
+ 0 && (module.exports = {
157
+ IdocLogsErrorBoundary,
158
+ useIdocLogger
159
+ });
160
+ //# sourceMappingURL=react.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx","../src/breadcrumbs.ts","../src/transport.ts","../src/types.ts","../src/core.ts"],"sourcesContent":["import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { idocLogs, log } from \"./core\";\n\ninterface ErrorBoundaryProps {\n /** Nom du logger utilisé pour les erreurs capturées (défaut : \"react\"). */\n logger?: string;\n /** Rendu de repli affiché après une erreur. Peut être un nœud ou une fonction recevant l'erreur. */\n fallback?: ReactNode | ((error: Error, réinitialiser: () => void) => ReactNode);\n children: ReactNode;\n}\n\ninterface ErrorBoundaryState {\n error: Error | null;\n}\n\n/** Error boundary React : les erreurs de rendu sont envoyées au centralisateur\n * (niveau Fatal, avec la pile de composants), puis le fallback est affiché. */\nexport class IdocLogsErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { error: null };\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n const pile = info.componentStack ? `\\nComposants :${info.componentStack}` : \"\";\n log(\"Fatal\", this.props.logger ?? \"react\", `${error.message}${pile}`, error);\n }\n\n private réinitialiser = () => this.setState({ error: null });\n\n render(): ReactNode {\n const { error } = this.state;\n if (error === null) return this.props.children;\n\n const { fallback } = this.props;\n if (typeof fallback === \"function\") return fallback(error, this.réinitialiser);\n return fallback ?? null;\n }\n}\n\n/** Accès au logger depuis les composants. Simple ré-export stable : le client\n * est un singleton module, aucun contexte React n'est nécessaire. */\nexport function useIdocLogger(): typeof idocLogs {\n return idocLogs;\n}\n","import type { Niveau } from \"./types\";\n\ninterface Breadcrumb {\n horodatage: Date;\n niveau: Niveau;\n logger: string;\n message: string;\n}\n\nlet buffer: Breadcrumb[] = [];\nlet taille = 30;\n\nexport function configurerBreadcrumbs(max: number): void {\n taille = max;\n buffer = [];\n}\n\nexport function empiler(niveau: Niveau, logger: string, message: string): void {\n if (buffer.length >= taille) buffer.shift();\n buffer.push({ horodatage: new Date(), niveau, logger, message });\n}\n\nfunction formatHeure(d: Date): string {\n const p = (n: number, l = 2) => String(n).padStart(l, \"0\");\n return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;\n}\n\n/** Instantané du buffer, au format aligné sur la target NLog C#. */\nexport function instantane(): string[] {\n return buffer.map(b => `${formatHeure(b.horodatage)} [${b.niveau}] ${b.logger} — ${b.message}`);\n}\n","import type { LogClientPayload } from \"./types\";\n\n// File d'attente bornée : au-delà, les entrées les plus anciennes sont abandonnées\n// (même philosophie que la target NLog : ne jamais bloquer ni faire gonfler la mémoire).\nconst FILE_MAX = 200;\n\nlet url = \"\";\nlet apiKey = \"\";\nlet flushMaxEntrees = 20;\nlet timer: ReturnType<typeof setInterval> | null = null;\nlet file: LogClientPayload[] = [];\nlet envoiEnCours = false;\nlet backoffJusqua = 0;\n\nexport function configurerTransport(options: {\n url: string;\n apiKey: string;\n flushIntervalleMs: number;\n flushMaxEntrees: number;\n}): void {\n url = options.url.replace(/\\/+$/, \"\") + \"/api/logs/client\";\n apiKey = options.apiKey;\n flushMaxEntrees = options.flushMaxEntrees;\n\n if (timer) clearInterval(timer);\n timer = setInterval(() => void flush(), options.flushIntervalleMs);\n\n if (typeof window !== \"undefined\") {\n // fetch keepalive survit à la fermeture de la page (contrairement à un fetch\n // classique) et, contrairement à sendBeacon, permet le header X-Api-Key.\n window.addEventListener(\"pagehide\", () => void flush(true));\n document.addEventListener(\"visibilitychange\", () => {\n if (document.visibilityState === \"hidden\") void flush(true);\n });\n }\n}\n\nexport function envoyer(entree: LogClientPayload): void {\n if (file.length >= FILE_MAX) file.shift();\n file.push(entree);\n if (file.length >= flushMaxEntrees) void flush();\n}\n\nasync function flush(keepalive = false): Promise<void> {\n if (envoiEnCours || file.length === 0 || !url) return;\n if (Date.now() < backoffJusqua && !keepalive) return;\n\n // Lots de 50 max (limite serveur) ; keepalive limite le corps à ~64 Ko,\n // on reste prudent avec un lot unique dans ce cas.\n const lot = file.splice(0, 50);\n envoiEnCours = true;\n try {\n const réponse = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\", \"X-Api-Key\": apiKey },\n body: JSON.stringify(lot),\n keepalive,\n });\n if (!réponse.ok && réponse.status !== 429) {\n // Clé invalide ou erreur serveur : on remet le lot, backoff 30 s.\n file = [...lot, ...file].slice(0, FILE_MAX);\n backoffJusqua = Date.now() + 30_000;\n }\n } catch {\n // Serveur injoignable : abandon silencieux du réseau, backoff 30 s.\n file = [...lot, ...file].slice(0, FILE_MAX);\n backoffJusqua = Date.now() + 30_000;\n } finally {\n envoiEnCours = false;\n }\n\n if (file.length >= flushMaxEntrees && Date.now() >= backoffJusqua) void flush();\n}\n","/** Niveaux NLog, dans l'ordre croissant de sévérité. */\nexport type Niveau = \"Trace\" | \"Debug\" | \"Info\" | \"Warn\" | \"Error\" | \"Fatal\";\n\nexport const NIVEAUX: readonly Niveau[] = [\"Trace\", \"Debug\", \"Info\", \"Warn\", \"Error\", \"Fatal\"];\n\nexport function rangNiveau(niveau: Niveau): number {\n return NIVEAUX.indexOf(niveau);\n}\n\n/** Entrée telle qu'attendue par POST /api/logs/client (PascalCase côté serveur). */\nexport interface LogClientPayload {\n Horodatage: string;\n Niveau: Niveau;\n Logger: string;\n Message: string;\n Exception: string | null;\n Version: string | null;\n Contexte: string | null;\n}\n\nexport interface IdocLogsOptions {\n /** URL de base du serveur de logs, ex. \"https://logs.example.com:5001\". */\n url: string;\n /** Clé API de l'application (générée dans l'admin du serveur de logs). */\n apiKey: string;\n /** Nom de l'application (informatif : le serveur impose celui associé à la clé). */\n application?: string;\n /** Version de l'application, jointe à chaque entrée. */\n version?: string;\n /** Niveau minimum réellement envoyé au serveur (défaut : \"Info\").\n * Les niveaux inférieurs alimentent uniquement les breadcrumbs. */\n niveauEnvoi?: Niveau;\n /** Brancher window.onerror / unhandledrejection (défaut : true). */\n captureGlobale?: boolean;\n /** Taille du buffer de breadcrumbs (défaut : 30). */\n breadcrumbsMax?: number;\n /** Intervalle de flush du lot en millisecondes (défaut : 5000). */\n flushIntervalleMs?: number;\n /** Taille de lot déclenchant un flush immédiat (défaut : 20). */\n flushMaxEntrees?: number;\n}\n","import { configurerBreadcrumbs, empiler, instantane } from \"./breadcrumbs\";\nimport { configurerTransport, envoyer } from \"./transport\";\nimport { activerCaptureGlobale } from \"./capture\";\nimport { rangNiveau, type IdocLogsOptions, type Niveau } from \"./types\";\n\nlet initialisé = false;\nlet version: string | null = null;\nlet rangEnvoi = rangNiveau(\"Info\");\n\n/** Initialise le client. À appeler une fois au démarrage de l'application. */\nexport function initIdocLogs(options: IdocLogsOptions): void {\n version = options.version ?? null;\n rangEnvoi = rangNiveau(options.niveauEnvoi ?? \"Info\");\n\n configurerBreadcrumbs(options.breadcrumbsMax ?? 30);\n configurerTransport({\n url: options.url,\n apiKey: options.apiKey,\n flushIntervalleMs: options.flushIntervalleMs ?? 5000,\n flushMaxEntrees: options.flushMaxEntrees ?? 20,\n });\n\n if (options.captureGlobale !== false) activerCaptureGlobale();\n initialisé = true;\n}\n\nexport function log(niveau: Niveau, logger: string, message: string, exception?: unknown): void {\n empiler(niveau, logger, message);\n if (!initialisé || rangNiveau(niveau) < rangEnvoi) return;\n\n const estErreur = rangNiveau(niveau) >= rangNiveau(\"Error\");\n envoyer({\n Horodatage: new Date().toISOString(),\n Niveau: niveau,\n Logger: logger,\n Message: message,\n Exception: formaterException(exception),\n Version: version,\n Contexte: estErreur ? construireContexte() : null,\n });\n}\n\nfunction formaterException(exception: unknown): string | null {\n if (exception == null) return null;\n if (exception instanceof Error)\n return exception.stack ?? `${exception.name}: ${exception.message}`;\n return String(exception);\n}\n\n/** Contexte joint aux erreurs : breadcrumbs et état de la page,\n * l'équivalent navigateur du contexte process de la target NLog. */\nfunction construireContexte(): string {\n return JSON.stringify({\n Breadcrumbs: instantane(),\n Url: typeof location !== \"undefined\" ? location.href : null,\n Ecran: typeof screen !== \"undefined\" ? `${screen.width}x${screen.height}` : null,\n Langue: typeof navigator !== \"undefined\" ? navigator.language : null,\n });\n}\n\nexport const idocLogs = {\n trace: (logger: string, message: string) => log(\"Trace\", logger, message),\n debug: (logger: string, message: string) => log(\"Debug\", logger, message),\n info: (logger: string, message: string) => log(\"Info\", logger, message),\n warn: (logger: string, message: string, exception?: unknown) => log(\"Warn\", logger, message, exception),\n error: (logger: string, message: string, exception?: unknown) => log(\"Error\", logger, message, exception),\n fatal: (logger: string, message: string, exception?: unknown) => log(\"Fatal\", logger, message, exception),\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,27 @@
1
+ import { Component, ReactNode, ErrorInfo } from 'react';
2
+ import { i as idocLogs } from './core-xTdevcDU.cjs';
3
+
4
+ interface ErrorBoundaryProps {
5
+ /** Nom du logger utilisé pour les erreurs capturées (défaut : "react"). */
6
+ logger?: string;
7
+ /** Rendu de repli affiché après une erreur. Peut être un nœud ou une fonction recevant l'erreur. */
8
+ fallback?: ReactNode | ((error: Error, réinitialiser: () => void) => ReactNode);
9
+ children: ReactNode;
10
+ }
11
+ interface ErrorBoundaryState {
12
+ error: Error | null;
13
+ }
14
+ /** Error boundary React : les erreurs de rendu sont envoyées au centralisateur
15
+ * (niveau Fatal, avec la pile de composants), puis le fallback est affiché. */
16
+ declare class IdocLogsErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
17
+ state: ErrorBoundaryState;
18
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
19
+ componentDidCatch(error: Error, info: ErrorInfo): void;
20
+ private réinitialiser;
21
+ render(): ReactNode;
22
+ }
23
+ /** Accès au logger depuis les composants. Simple ré-export stable : le client
24
+ * est un singleton module, aucun contexte React n'est nécessaire. */
25
+ declare function useIdocLogger(): typeof idocLogs;
26
+
27
+ export { IdocLogsErrorBoundary, useIdocLogger };
@@ -0,0 +1,27 @@
1
+ import { Component, ReactNode, ErrorInfo } from 'react';
2
+ import { i as idocLogs } from './core-xTdevcDU.js';
3
+
4
+ interface ErrorBoundaryProps {
5
+ /** Nom du logger utilisé pour les erreurs capturées (défaut : "react"). */
6
+ logger?: string;
7
+ /** Rendu de repli affiché après une erreur. Peut être un nœud ou une fonction recevant l'erreur. */
8
+ fallback?: ReactNode | ((error: Error, réinitialiser: () => void) => ReactNode);
9
+ children: ReactNode;
10
+ }
11
+ interface ErrorBoundaryState {
12
+ error: Error | null;
13
+ }
14
+ /** Error boundary React : les erreurs de rendu sont envoyées au centralisateur
15
+ * (niveau Fatal, avec la pile de composants), puis le fallback est affiché. */
16
+ declare class IdocLogsErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {
17
+ state: ErrorBoundaryState;
18
+ static getDerivedStateFromError(error: Error): ErrorBoundaryState;
19
+ componentDidCatch(error: Error, info: ErrorInfo): void;
20
+ private réinitialiser;
21
+ render(): ReactNode;
22
+ }
23
+ /** Accès au logger depuis les composants. Simple ré-export stable : le client
24
+ * est un singleton module, aucun contexte React n'est nécessaire. */
25
+ declare function useIdocLogger(): typeof idocLogs;
26
+
27
+ export { IdocLogsErrorBoundary, useIdocLogger };
package/dist/react.js ADDED
@@ -0,0 +1,37 @@
1
+ import {
2
+ idocLogs,
3
+ log
4
+ } from "./chunk-TM735D27.js";
5
+
6
+ // src/react.tsx
7
+ import { Component } from "react";
8
+ var IdocLogsErrorBoundary = class extends Component {
9
+ constructor() {
10
+ super(...arguments);
11
+ this.state = { error: null };
12
+ this.r\u00E9initialiser = () => this.setState({ error: null });
13
+ }
14
+ static getDerivedStateFromError(error) {
15
+ return { error };
16
+ }
17
+ componentDidCatch(error, info) {
18
+ const pile = info.componentStack ? `
19
+ Composants :${info.componentStack}` : "";
20
+ log("Fatal", this.props.logger ?? "react", `${error.message}${pile}`, error);
21
+ }
22
+ render() {
23
+ const { error } = this.state;
24
+ if (error === null) return this.props.children;
25
+ const { fallback } = this.props;
26
+ if (typeof fallback === "function") return fallback(error, this.r\u00E9initialiser);
27
+ return fallback ?? null;
28
+ }
29
+ };
30
+ function useIdocLogger() {
31
+ return idocLogs;
32
+ }
33
+ export {
34
+ IdocLogsErrorBoundary,
35
+ useIdocLogger
36
+ };
37
+ //# sourceMappingURL=react.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/react.tsx"],"sourcesContent":["import { Component, type ErrorInfo, type ReactNode } from \"react\";\nimport { idocLogs, log } from \"./core\";\n\ninterface ErrorBoundaryProps {\n /** Nom du logger utilisé pour les erreurs capturées (défaut : \"react\"). */\n logger?: string;\n /** Rendu de repli affiché après une erreur. Peut être un nœud ou une fonction recevant l'erreur. */\n fallback?: ReactNode | ((error: Error, réinitialiser: () => void) => ReactNode);\n children: ReactNode;\n}\n\ninterface ErrorBoundaryState {\n error: Error | null;\n}\n\n/** Error boundary React : les erreurs de rendu sont envoyées au centralisateur\n * (niveau Fatal, avec la pile de composants), puis le fallback est affiché. */\nexport class IdocLogsErrorBoundary extends Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { error: null };\n\n static getDerivedStateFromError(error: Error): ErrorBoundaryState {\n return { error };\n }\n\n componentDidCatch(error: Error, info: ErrorInfo): void {\n const pile = info.componentStack ? `\\nComposants :${info.componentStack}` : \"\";\n log(\"Fatal\", this.props.logger ?? \"react\", `${error.message}${pile}`, error);\n }\n\n private réinitialiser = () => this.setState({ error: null });\n\n render(): ReactNode {\n const { error } = this.state;\n if (error === null) return this.props.children;\n\n const { fallback } = this.props;\n if (typeof fallback === \"function\") return fallback(error, this.réinitialiser);\n return fallback ?? null;\n }\n}\n\n/** Accès au logger depuis les composants. Simple ré-export stable : le client\n * est un singleton module, aucun contexte React n'est nécessaire. */\nexport function useIdocLogger(): typeof idocLogs {\n return idocLogs;\n}\n"],"mappings":";;;;;;AAAA,SAAS,iBAAiD;AAiBnD,IAAM,wBAAN,cAAoC,UAAkD;AAAA,EAAtF;AAAA;AACL,iBAA4B,EAAE,OAAO,KAAK;AAW1C,SAAQ,qBAAgB,MAAM,KAAK,SAAS,EAAE,OAAO,KAAK,CAAC;AAAA;AAAA,EAT3D,OAAO,yBAAyB,OAAkC;AAChE,WAAO,EAAE,MAAM;AAAA,EACjB;AAAA,EAEA,kBAAkB,OAAc,MAAuB;AACrD,UAAM,OAAO,KAAK,iBAAiB;AAAA,cAAiB,KAAK,cAAc,KAAK;AAC5E,QAAI,SAAS,KAAK,MAAM,UAAU,SAAS,GAAG,MAAM,OAAO,GAAG,IAAI,IAAI,KAAK;AAAA,EAC7E;AAAA,EAIA,SAAoB;AAClB,UAAM,EAAE,MAAM,IAAI,KAAK;AACvB,QAAI,UAAU,KAAM,QAAO,KAAK,MAAM;AAEtC,UAAM,EAAE,SAAS,IAAI,KAAK;AAC1B,QAAI,OAAO,aAAa,WAAY,QAAO,SAAS,OAAO,KAAK,kBAAa;AAC7E,WAAO,YAAY;AAAA,EACrB;AACF;AAIO,SAAS,gBAAiC;AAC/C,SAAO;AACT;","names":[]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "idoc-logs-react",
3
+ "version": "1.0.0",
4
+ "description": "Client de logs pour le centralisateur IDOC.Logs : capture d'exceptions globales, breadcrumbs, envoi par lots vers l'endpoint HTTPS d'ingestion. Bindings React inclus.",
5
+ "author": "Philippe Boinnard",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "./dist/index.cjs",
9
+ "module": "./dist/index.js",
10
+ "types": "./dist/index.d.ts",
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "require": "./dist/index.cjs"
16
+ },
17
+ "./react": {
18
+ "types": "./dist/react.d.ts",
19
+ "import": "./dist/react.js",
20
+ "require": "./dist/react.cjs"
21
+ }
22
+ },
23
+ "files": [
24
+ "dist",
25
+ "README.md",
26
+ "LICENSE"
27
+ ],
28
+ "scripts": {
29
+ "build": "tsup",
30
+ "prepublishOnly": "npm run build"
31
+ },
32
+ "keywords": [
33
+ "logging",
34
+ "error-tracking",
35
+ "breadcrumbs",
36
+ "react",
37
+ "nlog",
38
+ "idoc"
39
+ ],
40
+ "peerDependencies": {
41
+ "react": ">=17"
42
+ },
43
+ "peerDependenciesMeta": {
44
+ "react": {
45
+ "optional": true
46
+ }
47
+ },
48
+ "devDependencies": {
49
+ "@types/react": "^19.0.0",
50
+ "react": "^19.0.0",
51
+ "tsup": "^8.3.5",
52
+ "typescript": "^5.7.2"
53
+ }
54
+ }