@pedrohb/errors 0.0.0-stage → 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.
@@ -0,0 +1,399 @@
1
+ import { t as InvalidParamDelimitersError } from "../invalid-param-delimiters-error-BFxlVXp3.mjs";
2
+ //#region src/functions/escape-reg-exp.ts
3
+ /**
4
+ * Escapa os caracteres especiais de expressões regulares em uma string, para
5
+ * que ela possa ser usada como texto literal dentro de um `RegExp`.
6
+ *
7
+ * Cada caractere especial (`. * + ? ^ $ { } ( ) | [ ] \`) é precedido por uma
8
+ * barra invertida. Caracteres comuns permanecem inalterados.
9
+ *
10
+ * Útil por exemplo, para montar uma expressão regular a partir de
11
+ * delimitadores informados pelo usuário (como os de placeholders), sem que
12
+ * símbolos como `[` ou `{` sejam interpretados como parte da sintaxe.
13
+ *
14
+ * @param value - String a ser escapada.
15
+ * @returns A string com os caracteres especiais escapados.
16
+ *
17
+ * @example
18
+ * ```ts
19
+ * escapeRegExp("{id}"); // "\\{id\\}"
20
+ * escapeRegExp("[nome]"); // "\\[nome\\]"
21
+ * escapeRegExp("a.b*c"); // "a\\.b\\*c"
22
+ * escapeRegExp("texto livre"); // "texto livre"
23
+ *
24
+ * const regex = new RegExp(escapeRegExp("(x)"), "g");
25
+ * "valor (x) aqui".replace(regex, "1"); // "valor 1 aqui"
26
+ * ```
27
+ */
28
+ function escapeRegExp(value) {
29
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
30
+ }
31
+ //#endregion
32
+ //#region src/functions/create-param-placeholder.ts
33
+ /**
34
+ * Delimitadores padrão dos placeholders em mensagens de erro: `{` para abrir
35
+ * e `}` para fechar (ex.: `{id}`).
36
+ *
37
+ * Declarado com `as const`, então mantém os tipos literais `"{"` e `"}"`,
38
+ * o que permite derivar {@link DefaultParamDelimiters} a partir dele.
39
+ */
40
+ const DEFAULT_PARAM_DELIMITERS = {
41
+ open: "{",
42
+ close: "}"
43
+ };
44
+ /**
45
+ * Cria uma expressão regular global que localiza os placeholders de uma
46
+ * mensagem de erro com base nos delimitadores informados.
47
+ *
48
+ * Os delimitadores são escapados com {@link escapeRegExp}, então símbolos como
49
+ * `[`, `(` ou `$` são tratados como texto literal. Delimitadores com mais de
50
+ * um caractere (ex.: `{{` e `}}`) também são aceitos.
51
+ *
52
+ * Em cada correspondência o grupo de captura `1` contém o texto entre os
53
+ * delimitadores, exatamente como aparece na mensagem (sem aparar espaços).
54
+ * O conteúdo pode ocupar várias linhas, mas não pode conter os delimitadores
55
+ * de abertura ou de fechamento. Em casos como `{{id}}` a correspondência
56
+ * recai sobre o par mais interno (`{id}`). Placeholders vazios (ex.: `{}`)
57
+ * também correspondem com o grupo `1` igual a `""`.
58
+ *
59
+ * Cada chamada devolve uma nova instância de `RegExp`. Como ela usa a flag
60
+ * `g` que mantém estado em `lastIndex`, isso evita que usos diferentes
61
+ * compartilhem o mesmo estado.
62
+ *
63
+ * @param delimiters - Delimitadores `open` e `close` do placeholder. Por
64
+ * padrão, {@link DEFAULT_PARAM_DELIMITERS} (`{` e `}`).
65
+ * @returns Expressão regular global que corresponde a cada placeholder.
66
+ * @throws {InvalidParamDelimitersError} Se `open` ou `close` for uma string
67
+ * vazia.
68
+ *
69
+ * @example
70
+ * ```ts
71
+ * const regex = createParamPlaceholder();
72
+ *
73
+ * for (const match of "Usuário {id} não encontrado em {table}".matchAll(regex)) {
74
+ * console.log(match[1]);
75
+ * }
76
+ * // "id"
77
+ * // "table"
78
+ *
79
+ * "Olá, {nome}!".replace(regex, (_, param) => `<${param}>`);
80
+ * // "Olá, <nome>!"
81
+ *
82
+ * // Delimitadores personalizados
83
+ * const brackets = createParamPlaceholder({ open: "[", close: "]" });
84
+ * "Rota [route] não encontrada".match(brackets); // ["[route]"]
85
+ *
86
+ * // Delimitadores vazios não são permitidos
87
+ * createParamPlaceholder({ open: "", close: "}" });
88
+ * // Lança InvalidParamDelimitersError
89
+ * ```
90
+ */
91
+ function createParamPlaceholder(delimiters = DEFAULT_PARAM_DELIMITERS) {
92
+ const { open, close } = delimiters;
93
+ if (open === "" || close === "") throw new InvalidParamDelimitersError();
94
+ const o = escapeRegExp(open);
95
+ const c = escapeRegExp(close);
96
+ return new RegExp(`${o}((?:(?!${o}|${c})[\\s\\S])*)${c}`, "g");
97
+ }
98
+ //#endregion
99
+ //#region src/functions/is-base-error.ts
100
+ /**
101
+ * Símbolo usado como marca ("brand") para identificar instâncias de
102
+ * `BaseError` em tempo de execução.
103
+ *
104
+ * É criado com `Symbol.for` que consulta o registro global de símbolos. Assim
105
+ * mesmo que o pacote seja carregado mais de uma vez (ex.: versões duplicadas
106
+ * em `node_modules` ou diferentes bundles), todas as cópias compartilham o
107
+ * mesmo símbolo e {@link isBaseError} continua reconhecendo os erros, algo que
108
+ * `instanceof` sozinho não garante.
109
+ */
110
+ const BASE_ERROR_BRAND = Symbol.for("@pedrohb/errors/base-error");
111
+ /**
112
+ * Verifica se um valor é uma instância de `BaseError` funcionando como um
113
+ * type guard.
114
+ *
115
+ * A checagem exige que o valor seja uma instância de `Error` e que possua a
116
+ * propriedade marcada por {@link BASE_ERROR_BRAND} com o valor `true`. Por
117
+ * usar a marca em vez de `instanceof BaseError`, o resultado é confiável
118
+ * mesmo quando há múltiplas cópias do pacote carregadas na mesma aplicação.
119
+ *
120
+ * @param value - Valor a ser verificado.
121
+ * @returns `true` se `value` for um `BaseError` (e nesse caso o TypeScript
122
+ * restringe o tipo para `BaseError`); caso contrário `false`.
123
+ *
124
+ * @example
125
+ * ```ts
126
+ * try {
127
+ * await execute();
128
+ * } catch (error) {
129
+ * if (isBaseError(error)) {
130
+ * console.log(error.code); // `error` é tipado como BaseError
131
+ * } else {
132
+ * throw error;
133
+ * }
134
+ * }
135
+ *
136
+ * isBaseError(new Error("comum")); // false
137
+ * isBaseError("texto"); // false
138
+ * isBaseError(null); // false
139
+ * ```
140
+ */
141
+ function isBaseError(value) {
142
+ return value instanceof Error && value[BASE_ERROR_BRAND] === true;
143
+ }
144
+ //#endregion
145
+ //#region src/functions/serialize-native-error.ts
146
+ /**
147
+ * Serializa um `Error` nativo para um objeto simples
148
+ * ({@link SerializedNativeError}) apropriado para `JSON.stringify`, logs ou
149
+ * transmissão.
150
+ *
151
+ * O resultado sempre contém `message` e `name`. As demais propriedades são
152
+ * incluídas apenas quando aplicável:
153
+ * - `cause`: se o erro tiver causa (`error.cause !== undefined`) serializada
154
+ * com {@link serializeCauseError};
155
+ * - `errors`: se o erro tiver uma propriedade `errors` que seja um array
156
+ * (como em `AggregateError`) com cada item serializado com
157
+ * {@link serializeCauseError};
158
+ * - `stack`: somente se `includeStack` for `true`.
159
+ *
160
+ * **Referências circulares:** o erro é registrado em `seen` durante a
161
+ * serialização e removido ao final (mesmo se ocorrer uma exceção). Assim se
162
+ * `cause` ou algum item de `errors` apontar de volta para este mesmo erro, o
163
+ * ponto de repetição é substituído por `"[Circular]"` em vez de causar
164
+ * recursão infinita. Por ser removido ao terminar, o mesmo erro pode aparecer
165
+ * em lugares distintos (sem ciclo) e ser serializado por completo em cada um.
166
+ *
167
+ * **Limitações:** apenas `message`, `name`, `cause`, `errors` e `stack` são
168
+ * copiados. Propriedades adicionais definidas em subclasses (ex.: `code` ou
169
+ * `status`) não são incluídas.
170
+ *
171
+ * @param error - `Error` a ser serializado.
172
+ * @param includeStack - Se `true` inclui o stack trace no resultado e o
173
+ * repassa à serialização da causa e dos erros agregados. Por padrão, `false`.
174
+ * @param seen - Conjunto de referências em processo de serialização usado
175
+ * internamente na recursão para detectar ciclos. Em geral não deve ser
176
+ * informado; por padrão, um novo `WeakSet` vazio.
177
+ * @returns Objeto serializável que representa o erro.
178
+ *
179
+ * @example
180
+ * ```ts
181
+ * serializeNativeError(new TypeError("valor inválido"));
182
+ * // { message: "valor inválido", name: "TypeError" }
183
+ *
184
+ * // Com stack trace
185
+ * serializeNativeError(new Error("falhou"), true);
186
+ * // { message: "falhou", name: "Error", stack: "Error: falhou\n at ..." }
187
+ *
188
+ * // Com causa
189
+ * serializeNativeError(new Error("falhou", { cause: "timeout" }));
190
+ * // { cause: "timeout", message: "falhou", name: "Error" }
191
+ *
192
+ * // Com erros agregados
193
+ * serializeNativeError(
194
+ * new AggregateError([new Error("a"), new Error("b")], "vários erros"),
195
+ * );
196
+ * // {
197
+ * // errors: [
198
+ * // { message: "a", name: "Error" },
199
+ * // { message: "b", name: "Error" },
200
+ * // ],
201
+ * // message: "vários erros",
202
+ * // name: "AggregateError",
203
+ * // }
204
+ *
205
+ * // Referência circular
206
+ * const error = new Error("ciclo");
207
+ * error.cause = error;
208
+ * serializeNativeError(error);
209
+ * // { cause: "[Circular]", message: "ciclo", name: "Error" }
210
+ * ```
211
+ */
212
+ function serializeNativeError(error, includeStack = false, seen = /* @__PURE__ */ new WeakSet()) {
213
+ seen.add(error);
214
+ try {
215
+ const errors = "errors" in error && Array.isArray(error.errors) ? error.errors : void 0;
216
+ return {
217
+ ...error.cause !== void 0 && { cause: serializeCauseError(error.cause, includeStack, seen) },
218
+ ...errors && { errors: errors.map((item) => serializeCauseError(item, includeStack, seen)) },
219
+ message: error.message,
220
+ name: error.name,
221
+ ...includeStack && { stack: error.stack }
222
+ };
223
+ } finally {
224
+ seen.delete(error);
225
+ }
226
+ }
227
+ //#endregion
228
+ //#region src/functions/serialize-cause-error.ts
229
+ /**
230
+ * Texto que substitui uma referência circular durante a serialização.
231
+ *
232
+ * É retornado no lugar de um objeto que já está sendo serializado mais acima
233
+ * na mesma cadeia evitando recursão infinita.
234
+ */
235
+ const CIRCULAR_MARKER = "[Circular]";
236
+ /**
237
+ * Serializa de forma segura, o valor de uma `cause` (causa) de erro para uma
238
+ * estrutura simples e apropriada para `JSON.stringify`, logs ou transmissão.
239
+ *
240
+ * A conversão depende do tipo do valor:
241
+ * - `string`, `number`, `boolean` e `undefined`: retornados sem alteração;
242
+ * - `null`: retorna `null`;
243
+ * - `bigint` e `symbol`: convertidos para texto com `toString()`
244
+ * (ex.: `10n` vira `"10"`);
245
+ * - função: vira o texto `"[Function: nome]"` ou `"[Function: anonymous]"`
246
+ * se não tiver nome;
247
+ * - `BaseError`: delegado a {@link serializeBaseError};
248
+ * - `Error` nativo: delegado a {@link serializeNativeError};
249
+ * - `Date`: convertida para string ISO 8601 ou `"Invalid Date"` se a data
250
+ * for inválida;
251
+ * - array: cada item é serializado recursivamente;
252
+ * - objeto comum: cada propriedade própria enumerável de chave `string` é
253
+ * serializada recursivamente, resultando em um novo objeto simples.
254
+ *
255
+ * **Referências circulares:** apenas as referências da cadeia atual (os
256
+ * "ancestrais" do valor sendo serializado) são rastreadas. Quando um objeto
257
+ * aparece dentro de si mesmo o ponto de repetição é substituído por
258
+ * {@link CIRCULAR_MARKER}. Como cada objeto é removido do conjunto ao terminar
259
+ * de ser serializado, um mesmo objeto referenciado em dois lugares distintos
260
+ * (sem ciclo) é serializado por completo nas duas ocorrências e não marcado
261
+ * como circular.
262
+ *
263
+ * **Limitações:** protótipos e métodos de objetos comuns são descartados e
264
+ * propriedades com chave `symbol` são ignoradas. Instâncias como `Map` e
265
+ * `Set`, que não possuem propriedades próprias enumeráveis resultam em `{}`.
266
+ *
267
+ * @param cause - Valor a ser serializado normalmente a propriedade `cause`
268
+ * de um erro, mas pode ser qualquer valor.
269
+ * @param includeStack - Se `true`, inclui o stack trace ao serializar erros
270
+ * (`BaseError` e `Error` nativo), repassando a opção aos respectivos
271
+ * serializadores. Por padrão, `false`.
272
+ * @param seen - Conjunto de referências em processo de serialização usado
273
+ * internamente na recursão para detectar ciclos. Em geral não deve ser
274
+ * informado; por padrão, um novo `WeakSet` vazio.
275
+ * @returns Representação serializável do valor cujo formato depende do tipo
276
+ * recebido (ver lista acima).
277
+ *
278
+ * @example
279
+ * ```ts
280
+ * serializeCauseError("falha"); // "falha"
281
+ * serializeCauseError(10n); // "10"
282
+ * serializeCauseError(Symbol("x")); // "Symbol(x)"
283
+ * serializeCauseError(function foo() {}); // "[Function: foo]"
284
+ * serializeCauseError(new Date("2026-01-01T00:00:00Z"));
285
+ * // "2026-01-01T00:00:00.000Z"
286
+ * serializeCauseError(new Date("inválida")); // "Invalid Date"
287
+ *
288
+ * // Estruturas aninhadas
289
+ * serializeCauseError({ ids: [1, 2n], origin: null });
290
+ * // { ids: [1, "2"], origin: null }
291
+ *
292
+ * // Referência circular
293
+ * const a: Record<string, unknown> = { name: "a" };
294
+ * a.self = a;
295
+ * serializeCauseError(a);
296
+ * // { name: "a", self: "[Circular]" }
297
+ *
298
+ * // Mesmo objeto em dois lugares (sem ciclo): serializado nas duas vezes
299
+ * const shared = { x: 1 };
300
+ * serializeCauseError({ a: shared, b: shared });
301
+ * // { a: { x: 1 }, b: { x: 1 } }
302
+ *
303
+ * // Erros, com stack trace opcional
304
+ * serializeCauseError(new Error("falhou"), true);
305
+ * ```
306
+ */
307
+ function serializeCauseError(cause, includeStack = false, seen = /* @__PURE__ */ new WeakSet()) {
308
+ switch (typeof cause) {
309
+ case "bigint":
310
+ case "symbol": return cause.toString();
311
+ case "function": return `[Function: ${cause.name || "anonymous"}]`;
312
+ case "object": break;
313
+ default: return cause;
314
+ }
315
+ if (cause === null) return null;
316
+ if (seen.has(cause)) return CIRCULAR_MARKER;
317
+ if (isBaseError(cause)) return serializeBaseError(cause, includeStack, seen);
318
+ if (cause instanceof Error) return serializeNativeError(cause, includeStack, seen);
319
+ if (cause instanceof Date) return Number.isNaN(cause.getTime()) ? "Invalid Date" : cause.toISOString();
320
+ seen.add(cause);
321
+ try {
322
+ if (Array.isArray(cause)) return cause.map((item) => serializeCauseError(item, includeStack, seen));
323
+ return Object.fromEntries(Object.entries(cause).map(([key, value]) => [key, serializeCauseError(value, includeStack, seen)]));
324
+ } finally {
325
+ seen.delete(cause);
326
+ }
327
+ }
328
+ //#endregion
329
+ //#region src/functions/serialize-base-error.ts
330
+ /**
331
+ * Serializa um `BaseError` para um objeto simples ({@link SerializedBaseError})
332
+ * apropriado para `JSON.stringify`, logs ou transmissão.
333
+ *
334
+ * O resultado sempre contém `code`, `message` e `name`. As demais
335
+ * propriedades são incluídas apenas quando aplicável:
336
+ * - `cause`: se o erro tiver causa (`error.cause !== undefined`) serializada
337
+ * com {@link serializeCauseError};
338
+ * - `params`: se o erro tiver parâmetros (`error.params !== undefined`)
339
+ * também serializados com {@link serializeCauseError};
340
+ * - `stack`: somente se `includeStack` for `true`.
341
+ *
342
+ * **Referências circulares:** o erro é registrado em `seen` durante a
343
+ * serialização e removido ao final (mesmo se ocorrer uma exceção). Assim se
344
+ * alguma `cause` ou `params` apontar de volta para este mesmo erro, o ponto
345
+ * de repetição é substituído por `"[Circular]"` em vez de causar recursão
346
+ * infinita. Por ser removido ao terminar, o mesmo erro pode aparecer em
347
+ * lugares distintos (sem ciclo) e ser serializado por completo em cada um.
348
+ *
349
+ * @param error - `BaseError` a ser serializado.
350
+ * @param includeStack - Se `true` inclui o stack trace no resultado e o
351
+ * repassa à serialização da causa e dos parâmetros. Por padrão, `false`.
352
+ * @param seen - Conjunto de referências em processo de serialização usado
353
+ * internamente na recursão para detectar ciclos. Em geral não deve ser
354
+ * informado; por padrão, um novo `WeakSet` vazio.
355
+ * @returns Objeto serializável que representa o erro.
356
+ *
357
+ * @example
358
+ * ```ts
359
+ * const error = new BaseError(ERROR_CODES.USER_NOT_FOUND, { id: 42 });
360
+ *
361
+ * serializeBaseError(error);
362
+ * // {
363
+ * // code: "USER_NOT_FOUND",
364
+ * // message: "Usuário 42 não encontrado",
365
+ * // name: "BaseError",
366
+ * // params: { id: 42 },
367
+ * // }
368
+ *
369
+ * // Com stack trace
370
+ * serializeBaseError(erro, true);
371
+ * // { ..., stack: "BaseError: Usuário 42 não encontrado\n at ..." }
372
+ *
373
+ * // Com causa
374
+ * const withCause = new BaseError(ERROR_CODES.INVALID_TOKEN, undefined, {
375
+ * cause: new Error("expirado"),
376
+ * });
377
+ * serializeBaseError(withCause);
378
+ * // { cause: { ... }, code: "INVALID_TOKEN", message: "Token inválido", name: "BaseError" }
379
+ * ```
380
+ */
381
+ function serializeBaseError(error, includeStack = false, seen = /* @__PURE__ */ new WeakSet()) {
382
+ seen.add(error);
383
+ try {
384
+ return {
385
+ ...error.cause !== void 0 && { cause: serializeCauseError(error.cause, includeStack, seen) },
386
+ code: error.code,
387
+ message: error.message,
388
+ name: error.name,
389
+ ...error.params !== void 0 && { params: serializeCauseError(error.params, includeStack, seen) },
390
+ ...includeStack && { stack: error.stack }
391
+ };
392
+ } finally {
393
+ seen.delete(error);
394
+ }
395
+ }
396
+ //#endregion
397
+ export { BASE_ERROR_BRAND, CIRCULAR_MARKER, DEFAULT_PARAM_DELIMITERS, createParamPlaceholder, escapeRegExp, isBaseError, serializeBaseError, serializeCauseError, serializeNativeError };
398
+
399
+ //# sourceMappingURL=index.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.mjs","names":[],"sources":["../../src/functions/escape-reg-exp.ts","../../src/functions/create-param-placeholder.ts","../../src/functions/is-base-error.ts","../../src/functions/serialize-native-error.ts","../../src/functions/serialize-cause-error.ts","../../src/functions/serialize-base-error.ts"],"sourcesContent":["/**\r\n * Escapa os caracteres especiais de expressões regulares em uma string, para\r\n * que ela possa ser usada como texto literal dentro de um `RegExp`.\r\n *\r\n * Cada caractere especial (`. * + ? ^ $ { } ( ) | [ ] \\`) é precedido por uma\r\n * barra invertida. Caracteres comuns permanecem inalterados.\r\n *\r\n * Útil por exemplo, para montar uma expressão regular a partir de\r\n * delimitadores informados pelo usuário (como os de placeholders), sem que\r\n * símbolos como `[` ou `{` sejam interpretados como parte da sintaxe.\r\n *\r\n * @param value - String a ser escapada.\r\n * @returns A string com os caracteres especiais escapados.\r\n *\r\n * @example\r\n * ```ts\r\n * escapeRegExp(\"{id}\"); // \"\\\\{id\\\\}\"\r\n * escapeRegExp(\"[nome]\"); // \"\\\\[nome\\\\]\"\r\n * escapeRegExp(\"a.b*c\"); // \"a\\\\.b\\\\*c\"\r\n * escapeRegExp(\"texto livre\"); // \"texto livre\"\r\n *\r\n * const regex = new RegExp(escapeRegExp(\"(x)\"), \"g\");\r\n * \"valor (x) aqui\".replace(regex, \"1\"); // \"valor 1 aqui\"\r\n * ```\r\n */\r\nexport function escapeRegExp(value: string) {\r\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\r\n}\r\n","import { InvalidParamDelimitersError } from \"#/errors/invalid-param-delimiters-error.js\";\r\nimport type { ErrorParamDelimiters } from \"#/types/error-param-delimiters.js\";\r\nimport { escapeRegExp } from \"./escape-reg-exp.js\";\r\n\r\n/**\r\n * Delimitadores padrão dos placeholders em mensagens de erro: `{` para abrir\r\n * e `}` para fechar (ex.: `{id}`).\r\n *\r\n * Declarado com `as const`, então mantém os tipos literais `\"{\"` e `\"}\"`,\r\n * o que permite derivar {@link DefaultParamDelimiters} a partir dele.\r\n */\r\nexport const DEFAULT_PARAM_DELIMITERS = {\r\n open: \"{\",\r\n close: \"}\",\r\n} as const satisfies ErrorParamDelimiters;\r\n\r\n/**\r\n * Tipo dos delimitadores padrão equivalente a\r\n * `{ readonly open: \"{\"; readonly close: \"}\" }`.\r\n *\r\n * É usado como valor padrão de `Delimiters` em tipos como `ErrorParams`.\r\n */\r\nexport type DefaultParamDelimiters = typeof DEFAULT_PARAM_DELIMITERS;\r\n\r\n/**\r\n * Cria uma expressão regular global que localiza os placeholders de uma\r\n * mensagem de erro com base nos delimitadores informados.\r\n *\r\n * Os delimitadores são escapados com {@link escapeRegExp}, então símbolos como\r\n * `[`, `(` ou `$` são tratados como texto literal. Delimitadores com mais de\r\n * um caractere (ex.: `{{` e `}}`) também são aceitos.\r\n *\r\n * Em cada correspondência o grupo de captura `1` contém o texto entre os\r\n * delimitadores, exatamente como aparece na mensagem (sem aparar espaços).\r\n * O conteúdo pode ocupar várias linhas, mas não pode conter os delimitadores\r\n * de abertura ou de fechamento. Em casos como `{{id}}` a correspondência\r\n * recai sobre o par mais interno (`{id}`). Placeholders vazios (ex.: `{}`)\r\n * também correspondem com o grupo `1` igual a `\"\"`.\r\n *\r\n * Cada chamada devolve uma nova instância de `RegExp`. Como ela usa a flag\r\n * `g` que mantém estado em `lastIndex`, isso evita que usos diferentes\r\n * compartilhem o mesmo estado.\r\n *\r\n * @param delimiters - Delimitadores `open` e `close` do placeholder. Por\r\n * padrão, {@link DEFAULT_PARAM_DELIMITERS} (`{` e `}`).\r\n * @returns Expressão regular global que corresponde a cada placeholder.\r\n * @throws {InvalidParamDelimitersError} Se `open` ou `close` for uma string\r\n * vazia.\r\n *\r\n * @example\r\n * ```ts\r\n * const regex = createParamPlaceholder();\r\n *\r\n * for (const match of \"Usuário {id} não encontrado em {table}\".matchAll(regex)) {\r\n * console.log(match[1]);\r\n * }\r\n * // \"id\"\r\n * // \"table\"\r\n *\r\n * \"Olá, {nome}!\".replace(regex, (_, param) => `<${param}>`);\r\n * // \"Olá, <nome>!\"\r\n *\r\n * // Delimitadores personalizados\r\n * const brackets = createParamPlaceholder({ open: \"[\", close: \"]\" });\r\n * \"Rota [route] não encontrada\".match(brackets); // [\"[route]\"]\r\n *\r\n * // Delimitadores vazios não são permitidos\r\n * createParamPlaceholder({ open: \"\", close: \"}\" });\r\n * // Lança InvalidParamDelimitersError\r\n * ```\r\n */\r\nexport function createParamPlaceholder(\r\n delimiters: ErrorParamDelimiters = DEFAULT_PARAM_DELIMITERS,\r\n) {\r\n const { open, close } = delimiters;\r\n\r\n if (open === \"\" || close === \"\") {\r\n throw new InvalidParamDelimitersError();\r\n }\r\n\r\n const o = escapeRegExp(open);\r\n const c = escapeRegExp(close);\r\n\r\n return new RegExp(`${o}((?:(?!${o}|${c})[\\\\s\\\\S])*)${c}`, \"g\");\r\n}\r\n","import type { BaseError } from \"#/base-error.js\";\r\n\r\n/**\r\n * Símbolo usado como marca (\"brand\") para identificar instâncias de\r\n * `BaseError` em tempo de execução.\r\n *\r\n * É criado com `Symbol.for` que consulta o registro global de símbolos. Assim\r\n * mesmo que o pacote seja carregado mais de uma vez (ex.: versões duplicadas\r\n * em `node_modules` ou diferentes bundles), todas as cópias compartilham o\r\n * mesmo símbolo e {@link isBaseError} continua reconhecendo os erros, algo que\r\n * `instanceof` sozinho não garante.\r\n */\r\nexport const BASE_ERROR_BRAND = Symbol.for(\"@pedrohb/errors/base-error\");\r\n\r\n/**\r\n * Verifica se um valor é uma instância de `BaseError` funcionando como um\r\n * type guard.\r\n *\r\n * A checagem exige que o valor seja uma instância de `Error` e que possua a\r\n * propriedade marcada por {@link BASE_ERROR_BRAND} com o valor `true`. Por\r\n * usar a marca em vez de `instanceof BaseError`, o resultado é confiável\r\n * mesmo quando há múltiplas cópias do pacote carregadas na mesma aplicação.\r\n *\r\n * @param value - Valor a ser verificado.\r\n * @returns `true` se `value` for um `BaseError` (e nesse caso o TypeScript\r\n * restringe o tipo para `BaseError`); caso contrário `false`.\r\n *\r\n * @example\r\n * ```ts\r\n * try {\r\n * await execute();\r\n * } catch (error) {\r\n * if (isBaseError(error)) {\r\n * console.log(error.code); // `error` é tipado como BaseError\r\n * } else {\r\n * throw error;\r\n * }\r\n * }\r\n *\r\n * isBaseError(new Error(\"comum\")); // false\r\n * isBaseError(\"texto\"); // false\r\n * isBaseError(null); // false\r\n * ```\r\n */\r\nexport function isBaseError(value: unknown): value is BaseError {\r\n return (\r\n value instanceof Error &&\r\n (value as { [BASE_ERROR_BRAND]?: unknown })[BASE_ERROR_BRAND] === true\r\n );\r\n}\r\n","import {\r\n type SeenReferences,\r\n serializeCauseError,\r\n} from \"./serialize-cause-error.js\";\r\n\r\n/**\r\n * Representação serializável de um `Error` nativo (ou de uma subclasse que\r\n * não seja `BaseError`), composta apenas por valores simples e apropriada para\r\n * `JSON.stringify`, logs ou transmissão.\r\n *\r\n * As propriedades `cause`, `errors` e `stack` são opcionais e só aparecem\r\n * quando o erro as possui (ou no caso de `stack` quando solicitado).\r\n */\r\nexport type SerializedNativeError = Readonly<{\r\n /** Causa do erro já serializada com {@link serializeCauseError}. */\r\n cause?: unknown;\r\n /**\r\n * Lista de erros agregados já serializados. Presente em erros como\r\n * `AggregateError` que expõem uma propriedade `errors` do tipo array.\r\n */\r\n errors?: readonly unknown[];\r\n /** Mensagem do erro. */\r\n message: string;\r\n /** Nome do erro (ex.: `\"Error\"`, `\"TypeError\"`, `\"AggregateError\"`). */\r\n name: string;\r\n /** Stack trace do erro presente apenas se `includeStack` for `true`. */\r\n stack?: string;\r\n}>;\r\n\r\n/**\r\n * Serializa um `Error` nativo para um objeto simples\r\n * ({@link SerializedNativeError}) apropriado para `JSON.stringify`, logs ou\r\n * transmissão.\r\n *\r\n * O resultado sempre contém `message` e `name`. As demais propriedades são\r\n * incluídas apenas quando aplicável:\r\n * - `cause`: se o erro tiver causa (`error.cause !== undefined`) serializada\r\n * com {@link serializeCauseError};\r\n * - `errors`: se o erro tiver uma propriedade `errors` que seja um array\r\n * (como em `AggregateError`) com cada item serializado com\r\n * {@link serializeCauseError};\r\n * - `stack`: somente se `includeStack` for `true`.\r\n *\r\n * **Referências circulares:** o erro é registrado em `seen` durante a\r\n * serialização e removido ao final (mesmo se ocorrer uma exceção). Assim se\r\n * `cause` ou algum item de `errors` apontar de volta para este mesmo erro, o\r\n * ponto de repetição é substituído por `\"[Circular]\"` em vez de causar\r\n * recursão infinita. Por ser removido ao terminar, o mesmo erro pode aparecer\r\n * em lugares distintos (sem ciclo) e ser serializado por completo em cada um.\r\n *\r\n * **Limitações:** apenas `message`, `name`, `cause`, `errors` e `stack` são\r\n * copiados. Propriedades adicionais definidas em subclasses (ex.: `code` ou\r\n * `status`) não são incluídas.\r\n *\r\n * @param error - `Error` a ser serializado.\r\n * @param includeStack - Se `true` inclui o stack trace no resultado e o\r\n * repassa à serialização da causa e dos erros agregados. Por padrão, `false`.\r\n * @param seen - Conjunto de referências em processo de serialização usado\r\n * internamente na recursão para detectar ciclos. Em geral não deve ser\r\n * informado; por padrão, um novo `WeakSet` vazio.\r\n * @returns Objeto serializável que representa o erro.\r\n *\r\n * @example\r\n * ```ts\r\n * serializeNativeError(new TypeError(\"valor inválido\"));\r\n * // { message: \"valor inválido\", name: \"TypeError\" }\r\n *\r\n * // Com stack trace\r\n * serializeNativeError(new Error(\"falhou\"), true);\r\n * // { message: \"falhou\", name: \"Error\", stack: \"Error: falhou\\n at ...\" }\r\n *\r\n * // Com causa\r\n * serializeNativeError(new Error(\"falhou\", { cause: \"timeout\" }));\r\n * // { cause: \"timeout\", message: \"falhou\", name: \"Error\" }\r\n *\r\n * // Com erros agregados\r\n * serializeNativeError(\r\n * new AggregateError([new Error(\"a\"), new Error(\"b\")], \"vários erros\"),\r\n * );\r\n * // {\r\n * // errors: [\r\n * // { message: \"a\", name: \"Error\" },\r\n * // { message: \"b\", name: \"Error\" },\r\n * // ],\r\n * // message: \"vários erros\",\r\n * // name: \"AggregateError\",\r\n * // }\r\n *\r\n * // Referência circular\r\n * const error = new Error(\"ciclo\");\r\n * error.cause = error;\r\n * serializeNativeError(error);\r\n * // { cause: \"[Circular]\", message: \"ciclo\", name: \"Error\" }\r\n * ```\r\n */\r\nexport function serializeNativeError(\r\n error: Error,\r\n includeStack = false,\r\n seen: SeenReferences = new WeakSet(),\r\n): SerializedNativeError {\r\n seen.add(error);\r\n\r\n try {\r\n const errors =\r\n \"errors\" in error && Array.isArray(error.errors)\r\n ? (error.errors as unknown[])\r\n : undefined;\r\n\r\n return {\r\n ...(error.cause !== undefined && {\r\n cause: serializeCauseError(error.cause, includeStack, seen),\r\n }),\r\n ...(errors && {\r\n errors: errors.map((item) =>\r\n serializeCauseError(item, includeStack, seen),\r\n ),\r\n }),\r\n message: error.message,\r\n name: error.name,\r\n ...(includeStack && { stack: error.stack }),\r\n };\r\n } finally {\r\n seen.delete(error);\r\n }\r\n}\r\n","import { isBaseError } from \"./is-base-error.js\";\r\nimport { serializeBaseError } from \"./serialize-base-error.js\";\r\nimport { serializeNativeError } from \"./serialize-native-error.js\";\r\n\r\n/**\r\n * Texto que substitui uma referência circular durante a serialização.\r\n *\r\n * É retornado no lugar de um objeto que já está sendo serializado mais acima\r\n * na mesma cadeia evitando recursão infinita.\r\n */\r\nexport const CIRCULAR_MARKER = \"[Circular]\";\r\n\r\n/**\r\n * Conjunto de referências em processo de serialização usado para detectar\r\n * ciclos.\r\n *\r\n * Por ser um `WeakSet` não impede que os objetos sejam coletados pelo\r\n * garbage collector.\r\n */\r\nexport type SeenReferences = WeakSet<object>;\r\n\r\n/**\r\n * Serializa de forma segura, o valor de uma `cause` (causa) de erro para uma\r\n * estrutura simples e apropriada para `JSON.stringify`, logs ou transmissão.\r\n *\r\n * A conversão depende do tipo do valor:\r\n * - `string`, `number`, `boolean` e `undefined`: retornados sem alteração;\r\n * - `null`: retorna `null`;\r\n * - `bigint` e `symbol`: convertidos para texto com `toString()`\r\n * (ex.: `10n` vira `\"10\"`);\r\n * - função: vira o texto `\"[Function: nome]\"` ou `\"[Function: anonymous]\"`\r\n * se não tiver nome;\r\n * - `BaseError`: delegado a {@link serializeBaseError};\r\n * - `Error` nativo: delegado a {@link serializeNativeError};\r\n * - `Date`: convertida para string ISO 8601 ou `\"Invalid Date\"` se a data\r\n * for inválida;\r\n * - array: cada item é serializado recursivamente;\r\n * - objeto comum: cada propriedade própria enumerável de chave `string` é\r\n * serializada recursivamente, resultando em um novo objeto simples.\r\n *\r\n * **Referências circulares:** apenas as referências da cadeia atual (os\r\n * \"ancestrais\" do valor sendo serializado) são rastreadas. Quando um objeto\r\n * aparece dentro de si mesmo o ponto de repetição é substituído por\r\n * {@link CIRCULAR_MARKER}. Como cada objeto é removido do conjunto ao terminar\r\n * de ser serializado, um mesmo objeto referenciado em dois lugares distintos\r\n * (sem ciclo) é serializado por completo nas duas ocorrências e não marcado\r\n * como circular.\r\n *\r\n * **Limitações:** protótipos e métodos de objetos comuns são descartados e\r\n * propriedades com chave `symbol` são ignoradas. Instâncias como `Map` e\r\n * `Set`, que não possuem propriedades próprias enumeráveis resultam em `{}`.\r\n *\r\n * @param cause - Valor a ser serializado normalmente a propriedade `cause`\r\n * de um erro, mas pode ser qualquer valor.\r\n * @param includeStack - Se `true`, inclui o stack trace ao serializar erros\r\n * (`BaseError` e `Error` nativo), repassando a opção aos respectivos\r\n * serializadores. Por padrão, `false`.\r\n * @param seen - Conjunto de referências em processo de serialização usado\r\n * internamente na recursão para detectar ciclos. Em geral não deve ser\r\n * informado; por padrão, um novo `WeakSet` vazio.\r\n * @returns Representação serializável do valor cujo formato depende do tipo\r\n * recebido (ver lista acima).\r\n *\r\n * @example\r\n * ```ts\r\n * serializeCauseError(\"falha\"); // \"falha\"\r\n * serializeCauseError(10n); // \"10\"\r\n * serializeCauseError(Symbol(\"x\")); // \"Symbol(x)\"\r\n * serializeCauseError(function foo() {}); // \"[Function: foo]\"\r\n * serializeCauseError(new Date(\"2026-01-01T00:00:00Z\"));\r\n * // \"2026-01-01T00:00:00.000Z\"\r\n * serializeCauseError(new Date(\"inválida\")); // \"Invalid Date\"\r\n *\r\n * // Estruturas aninhadas\r\n * serializeCauseError({ ids: [1, 2n], origin: null });\r\n * // { ids: [1, \"2\"], origin: null }\r\n *\r\n * // Referência circular\r\n * const a: Record<string, unknown> = { name: \"a\" };\r\n * a.self = a;\r\n * serializeCauseError(a);\r\n * // { name: \"a\", self: \"[Circular]\" }\r\n *\r\n * // Mesmo objeto em dois lugares (sem ciclo): serializado nas duas vezes\r\n * const shared = { x: 1 };\r\n * serializeCauseError({ a: shared, b: shared });\r\n * // { a: { x: 1 }, b: { x: 1 } }\r\n *\r\n * // Erros, com stack trace opcional\r\n * serializeCauseError(new Error(\"falhou\"), true);\r\n * ```\r\n */\r\nexport function serializeCauseError(\r\n cause: unknown,\r\n includeStack = false,\r\n seen: SeenReferences = new WeakSet(),\r\n): unknown {\r\n switch (typeof cause) {\r\n case \"bigint\":\r\n case \"symbol\":\r\n return cause.toString();\r\n case \"function\":\r\n return `[Function: ${cause.name || \"anonymous\"}]`;\r\n case \"object\":\r\n break;\r\n default:\r\n return cause;\r\n }\r\n\r\n if (cause === null) {\r\n return null;\r\n }\r\n\r\n if (seen.has(cause)) {\r\n return CIRCULAR_MARKER;\r\n }\r\n\r\n if (isBaseError(cause)) {\r\n return serializeBaseError(cause, includeStack, seen);\r\n }\r\n\r\n if (cause instanceof Error) {\r\n return serializeNativeError(cause, includeStack, seen);\r\n }\r\n\r\n if (cause instanceof Date) {\r\n return Number.isNaN(cause.getTime()) ? \"Invalid Date\" : cause.toISOString();\r\n }\r\n\r\n seen.add(cause);\r\n\r\n try {\r\n if (Array.isArray(cause)) {\r\n return cause.map((item) => serializeCauseError(item, includeStack, seen));\r\n }\r\n\r\n return Object.fromEntries(\r\n Object.entries(cause).map(([key, value]) => [\r\n key,\r\n serializeCauseError(value, includeStack, seen),\r\n ]),\r\n );\r\n } finally {\r\n seen.delete(cause);\r\n }\r\n}\r\n","import type { BaseError } from \"#/base-error.js\";\r\nimport {\r\n type SeenReferences,\r\n serializeCauseError,\r\n} from \"./serialize-cause-error.js\";\r\n\r\n/**\r\n * Representação serializável de um `BaseError` composta apenas por valores\r\n * simples e apropriada para `JSON.stringify`, logs ou transmissão.\r\n *\r\n * As propriedades `cause`, `params` e `stack` são opcionais e só aparecem\r\n * quando o erro as possui (ou no caso de `stack` quando solicitado).\r\n */\r\nexport type SerializedBaseError = Readonly<{\r\n /** Causa do erro já serializada com {@link serializeCauseError}. */\r\n cause?: unknown;\r\n /** Código do erro conforme o catálogo (ex.: `\"USER_NOT_FOUND\"`). */\r\n code: string;\r\n /** Mensagem do erro já com os placeholders interpolados. */\r\n message: string;\r\n /** Nome da classe do erro (ex.: `\"BaseError\"`). */\r\n name: string;\r\n /** Parâmetros usados para interpolar a mensagem já serializados. */\r\n params?: Readonly<Record<string, unknown>>;\r\n /** Stack trace do erro presente apenas se `includeStack` for `true`. */\r\n stack?: string;\r\n}>;\r\n\r\n/**\r\n * Serializa um `BaseError` para um objeto simples ({@link SerializedBaseError})\r\n * apropriado para `JSON.stringify`, logs ou transmissão.\r\n *\r\n * O resultado sempre contém `code`, `message` e `name`. As demais\r\n * propriedades são incluídas apenas quando aplicável:\r\n * - `cause`: se o erro tiver causa (`error.cause !== undefined`) serializada\r\n * com {@link serializeCauseError};\r\n * - `params`: se o erro tiver parâmetros (`error.params !== undefined`)\r\n * também serializados com {@link serializeCauseError};\r\n * - `stack`: somente se `includeStack` for `true`.\r\n *\r\n * **Referências circulares:** o erro é registrado em `seen` durante a\r\n * serialização e removido ao final (mesmo se ocorrer uma exceção). Assim se\r\n * alguma `cause` ou `params` apontar de volta para este mesmo erro, o ponto\r\n * de repetição é substituído por `\"[Circular]\"` em vez de causar recursão\r\n * infinita. Por ser removido ao terminar, o mesmo erro pode aparecer em\r\n * lugares distintos (sem ciclo) e ser serializado por completo em cada um.\r\n *\r\n * @param error - `BaseError` a ser serializado.\r\n * @param includeStack - Se `true` inclui o stack trace no resultado e o\r\n * repassa à serialização da causa e dos parâmetros. Por padrão, `false`.\r\n * @param seen - Conjunto de referências em processo de serialização usado\r\n * internamente na recursão para detectar ciclos. Em geral não deve ser\r\n * informado; por padrão, um novo `WeakSet` vazio.\r\n * @returns Objeto serializável que representa o erro.\r\n *\r\n * @example\r\n * ```ts\r\n * const error = new BaseError(ERROR_CODES.USER_NOT_FOUND, { id: 42 });\r\n *\r\n * serializeBaseError(error);\r\n * // {\r\n * // code: \"USER_NOT_FOUND\",\r\n * // message: \"Usuário 42 não encontrado\",\r\n * // name: \"BaseError\",\r\n * // params: { id: 42 },\r\n * // }\r\n *\r\n * // Com stack trace\r\n * serializeBaseError(erro, true);\r\n * // { ..., stack: \"BaseError: Usuário 42 não encontrado\\n at ...\" }\r\n *\r\n * // Com causa\r\n * const withCause = new BaseError(ERROR_CODES.INVALID_TOKEN, undefined, {\r\n * cause: new Error(\"expirado\"),\r\n * });\r\n * serializeBaseError(withCause);\r\n * // { cause: { ... }, code: \"INVALID_TOKEN\", message: \"Token inválido\", name: \"BaseError\" }\r\n * ```\r\n */\r\nexport function serializeBaseError(\r\n error: BaseError,\r\n includeStack = false,\r\n seen: SeenReferences = new WeakSet(),\r\n): SerializedBaseError {\r\n seen.add(error);\r\n\r\n try {\r\n return {\r\n ...(error.cause !== undefined && {\r\n cause: serializeCauseError(error.cause, includeStack, seen),\r\n }),\r\n code: error.code,\r\n message: error.message,\r\n name: error.name,\r\n ...(error.params !== undefined && {\r\n params: serializeCauseError(\r\n error.params,\r\n includeStack,\r\n seen,\r\n ) as Readonly<Record<string, unknown>>,\r\n }),\r\n ...(includeStack && { stack: error.stack }),\r\n };\r\n } finally {\r\n seen.delete(error);\r\n }\r\n}\r\n"],"mappings":"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"}