autotel 4.0.0 → 4.2.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.
Files changed (232) hide show
  1. package/README.md +26 -1
  2. package/dist/auto.cjs +2 -2
  3. package/dist/auto.js +1 -1
  4. package/dist/correlation-id.cjs +1 -1
  5. package/dist/correlation-id.js +1 -1
  6. package/dist/decorators.cjs +1 -1
  7. package/dist/decorators.js +1 -1
  8. package/dist/{event-Dlqr4ZNL.cjs → event-BhHREDJk.cjs} +3 -3
  9. package/dist/{event-Dlqr4ZNL.cjs.map → event-BhHREDJk.cjs.map} +1 -1
  10. package/dist/{event-_58ryBjh.js → event-ByBTV9M2.js} +3 -3
  11. package/dist/{event-_58ryBjh.js.map → event-ByBTV9M2.js.map} +1 -1
  12. package/dist/event.cjs +1 -1
  13. package/dist/event.js +1 -1
  14. package/dist/{functional-BGkT8J-h.js → functional-DtI0u4vx.js} +19 -19
  15. package/dist/functional-DtI0u4vx.js.map +1 -0
  16. package/dist/{functional-C4CzoVrX.cjs → functional-zpzNLhky.cjs} +4 -4
  17. package/dist/{functional-C4CzoVrX.cjs.map → functional-zpzNLhky.cjs.map} +1 -1
  18. package/dist/functional.cjs +1 -1
  19. package/dist/functional.js +1 -1
  20. package/dist/http.cjs +1 -1
  21. package/dist/http.js +1 -1
  22. package/dist/index.cjs +5 -5
  23. package/dist/index.d.cts +1 -1
  24. package/dist/index.d.ts +1 -1
  25. package/dist/index.js +5 -5
  26. package/dist/{init-DJQOdVlN.d.ts → init-B7u-DjxM.d.ts} +57 -2
  27. package/dist/init-B7u-DjxM.d.ts.map +1 -0
  28. package/dist/{init-DvapOXCc.cjs → init-BX7AmFRl.cjs} +40 -21
  29. package/dist/init-BX7AmFRl.cjs.map +1 -0
  30. package/dist/{init-Ch6t7MNI.js → init-D-jnNMix.js} +39 -20
  31. package/dist/init-D-jnNMix.js.map +1 -0
  32. package/dist/{init-CNp-ee80.d.cts → init-DSrRmVnz.d.cts} +57 -2
  33. package/dist/init-DSrRmVnz.d.cts.map +1 -0
  34. package/dist/instrumentation.cjs +1 -1
  35. package/dist/instrumentation.js +1 -1
  36. package/dist/logger-D3Ej3DII.js +446 -0
  37. package/dist/logger-D3Ej3DII.js.map +1 -0
  38. package/dist/logger-thMPLpOG.cjs +487 -0
  39. package/dist/logger-thMPLpOG.cjs.map +1 -0
  40. package/dist/logger.cjs +8 -236
  41. package/dist/logger.js +2 -204
  42. package/dist/messaging.cjs +1 -1
  43. package/dist/messaging.js +1 -1
  44. package/dist/semantic-helpers.cjs +1 -1
  45. package/dist/semantic-helpers.js +1 -1
  46. package/dist/{track-3HY4NGV-.cjs → track-D59FfpL0.cjs} +2 -2
  47. package/dist/{track-3HY4NGV-.cjs.map → track-D59FfpL0.cjs.map} +1 -1
  48. package/dist/{track-nsKVy-pj.js → track-wc0HafS_.js} +6 -6
  49. package/dist/track-wc0HafS_.js.map +1 -0
  50. package/dist/webhook.cjs +1 -1
  51. package/dist/webhook.js +1 -1
  52. package/dist/workflow-distributed.cjs +1 -1
  53. package/dist/workflow-distributed.js +1 -1
  54. package/dist/workflow.cjs +1 -1
  55. package/dist/workflow.js +1 -1
  56. package/dist/{yaml-config-B3dQ82GR.cjs → yaml-config-Ck2uB0Dp.cjs} +2 -1
  57. package/dist/yaml-config-Ck2uB0Dp.cjs.map +1 -0
  58. package/dist/yaml-config.cjs +1 -1
  59. package/dist/yaml-config.d.cts +7 -1
  60. package/dist/yaml-config.d.cts.map +1 -1
  61. package/dist/yaml-config.d.ts +7 -1
  62. package/dist/yaml-config.d.ts.map +1 -1
  63. package/dist/yaml-config.js +1 -0
  64. package/dist/yaml-config.js.map +1 -1
  65. package/package.json +1 -2
  66. package/skills/autotel-core/SKILL.md +2 -0
  67. package/skills/autotel-instrumentation/SKILL.md +25 -0
  68. package/skills/debug-missing-spans/SKILL.md +3 -1
  69. package/skills/migrate-to-autotel/SKILL.md +24 -23
  70. package/skills/review-otel-patterns/SKILL.md +5 -4
  71. package/dist/functional-BGkT8J-h.js.map +0 -1
  72. package/dist/init-CNp-ee80.d.cts.map +0 -1
  73. package/dist/init-Ch6t7MNI.js.map +0 -1
  74. package/dist/init-DJQOdVlN.d.ts.map +0 -1
  75. package/dist/init-DvapOXCc.cjs.map +0 -1
  76. package/dist/logger.cjs.map +0 -1
  77. package/dist/logger.js.map +0 -1
  78. package/dist/track-nsKVy-pj.js.map +0 -1
  79. package/dist/yaml-config-B3dQ82GR.cjs.map +0 -1
  80. package/src/attribute-redacting-processor.test.ts +0 -763
  81. package/src/attribute-redacting-processor.ts +0 -621
  82. package/src/attributes/attachers.ts +0 -161
  83. package/src/attributes/builders.ts +0 -529
  84. package/src/attributes/domains.ts +0 -42
  85. package/src/attributes/index.ts +0 -81
  86. package/src/attributes/registry.ts +0 -323
  87. package/src/attributes/types.ts +0 -211
  88. package/src/attributes/utils.ts +0 -64
  89. package/src/attributes/validators.ts +0 -266
  90. package/src/attributes.test.ts +0 -292
  91. package/src/auto.ts +0 -67
  92. package/src/autotel-logger.test.ts +0 -548
  93. package/src/autotel-logger.ts +0 -364
  94. package/src/baggage-span-processor.test.ts +0 -202
  95. package/src/baggage-span-processor.ts +0 -100
  96. package/src/business-baggage.test.ts +0 -500
  97. package/src/business-baggage.ts +0 -669
  98. package/src/circuit-breaker.test.ts +0 -341
  99. package/src/circuit-breaker.ts +0 -184
  100. package/src/config.test.ts +0 -94
  101. package/src/config.ts +0 -172
  102. package/src/correlated-events.test.ts +0 -151
  103. package/src/correlated-events.ts +0 -47
  104. package/src/correlation-id.test.ts +0 -163
  105. package/src/correlation-id.ts +0 -206
  106. package/src/db.test.ts +0 -252
  107. package/src/db.ts +0 -447
  108. package/src/decorators.test.ts +0 -153
  109. package/src/decorators.ts +0 -188
  110. package/src/define-event.test.ts +0 -41
  111. package/src/define-event.ts +0 -58
  112. package/src/devtools.ts +0 -60
  113. package/src/drain-pipeline.test.ts +0 -68
  114. package/src/drain-pipeline.ts +0 -199
  115. package/src/drain-toolkit.test.ts +0 -113
  116. package/src/drain-toolkit.ts +0 -129
  117. package/src/enricher-toolkit.test.ts +0 -67
  118. package/src/enricher-toolkit.ts +0 -79
  119. package/src/enrichers.test.ts +0 -150
  120. package/src/enrichers.ts +0 -145
  121. package/src/env-config.test.ts +0 -323
  122. package/src/env-config.ts +0 -309
  123. package/src/error-catalog.test.ts +0 -133
  124. package/src/error-catalog.ts +0 -262
  125. package/src/event-queue.test.ts +0 -864
  126. package/src/event-queue.ts +0 -699
  127. package/src/event-subscriber.ts +0 -262
  128. package/src/event-testing.ts +0 -197
  129. package/src/event.test.ts +0 -1104
  130. package/src/event.ts +0 -988
  131. package/src/events-config.ts +0 -235
  132. package/src/exporters.ts +0 -165
  133. package/src/filtering-span-processor.test.ts +0 -281
  134. package/src/filtering-span-processor.ts +0 -111
  135. package/src/flatten-attributes.test.ts +0 -76
  136. package/src/flatten-attributes.ts +0 -80
  137. package/src/functional.strict-types.typecheck.ts +0 -53
  138. package/src/functional.test.ts +0 -1464
  139. package/src/functional.ts +0 -2539
  140. package/src/functional.types.test.ts +0 -135
  141. package/src/hook.mjs +0 -15
  142. package/src/http.test.ts +0 -485
  143. package/src/http.ts +0 -424
  144. package/src/index.ts +0 -433
  145. package/src/init-auto-redactor.test.ts +0 -53
  146. package/src/init-redactor.test.ts +0 -8
  147. package/src/init.customization.test.ts +0 -594
  148. package/src/init.integrations.test.ts +0 -399
  149. package/src/init.openllmetry.test.ts +0 -194
  150. package/src/init.protocol.test.ts +0 -215
  151. package/src/init.ts +0 -2312
  152. package/src/instrumentation.test.ts +0 -108
  153. package/src/instrumentation.ts +0 -319
  154. package/src/logger.test.ts +0 -125
  155. package/src/logger.ts +0 -341
  156. package/src/messaging-adapters.test.ts +0 -595
  157. package/src/messaging-adapters.ts +0 -583
  158. package/src/messaging-testing.test.ts +0 -573
  159. package/src/messaging-testing.ts +0 -935
  160. package/src/messaging.test.ts +0 -1646
  161. package/src/messaging.ts +0 -2245
  162. package/src/metric-helpers.ts +0 -47
  163. package/src/metric-testing.ts +0 -197
  164. package/src/metric.ts +0 -446
  165. package/src/metrics.test.ts +0 -241
  166. package/src/node-require.ts +0 -123
  167. package/src/operation-context.ts +0 -93
  168. package/src/parse-error.test.ts +0 -73
  169. package/src/parse-error.ts +0 -112
  170. package/src/posthog-logs.test.ts +0 -115
  171. package/src/posthog-logs.ts +0 -77
  172. package/src/pretty-console-exporter.test.ts +0 -545
  173. package/src/pretty-console-exporter.ts +0 -413
  174. package/src/pretty-log-formatter.test.ts +0 -123
  175. package/src/pretty-log-formatter.ts +0 -210
  176. package/src/processors/canonical-log-line-processor.test.ts +0 -523
  177. package/src/processors/canonical-log-line-processor.ts +0 -396
  178. package/src/processors.ts +0 -152
  179. package/src/rate-limiter.test.ts +0 -199
  180. package/src/rate-limiter.ts +0 -98
  181. package/src/redact-values.test.ts +0 -90
  182. package/src/redact-values.ts +0 -34
  183. package/src/register.ts +0 -37
  184. package/src/request-logger.test.ts +0 -545
  185. package/src/request-logger.ts +0 -342
  186. package/src/sampling.test.ts +0 -1060
  187. package/src/sampling.ts +0 -737
  188. package/src/security-schema.test.ts +0 -45
  189. package/src/security-schema.ts +0 -107
  190. package/src/semantic-conventions.ts +0 -15
  191. package/src/semantic-helpers.test.ts +0 -226
  192. package/src/semantic-helpers.ts +0 -438
  193. package/src/shutdown.test.ts +0 -364
  194. package/src/shutdown.ts +0 -246
  195. package/src/span-name-normalizer.test.ts +0 -377
  196. package/src/span-name-normalizer.ts +0 -213
  197. package/src/stable-hash.ts +0 -27
  198. package/src/structured-error.test.ts +0 -191
  199. package/src/structured-error.ts +0 -157
  200. package/src/stub.integration.test.ts +0 -361
  201. package/src/tail-sampling-processor.test.ts +0 -230
  202. package/src/tail-sampling-processor.ts +0 -55
  203. package/src/test-span-collector.test.ts +0 -234
  204. package/src/test-span-collector.ts +0 -150
  205. package/src/testing.ts +0 -705
  206. package/src/trace-context.test.ts +0 -73
  207. package/src/trace-context.ts +0 -567
  208. package/src/trace-helpers.new.test.ts +0 -278
  209. package/src/trace-helpers.test.ts +0 -290
  210. package/src/trace-helpers.ts +0 -710
  211. package/src/trace-hybrid.test.ts +0 -42
  212. package/src/trace-hybrid.ts +0 -37
  213. package/src/tracer-provider.test.ts +0 -183
  214. package/src/tracer-provider.ts +0 -266
  215. package/src/track.test.ts +0 -154
  216. package/src/track.ts +0 -216
  217. package/src/validate.test.ts +0 -287
  218. package/src/validate.ts +0 -307
  219. package/src/validation-attributes.ts +0 -43
  220. package/src/validation.test.ts +0 -330
  221. package/src/validation.ts +0 -246
  222. package/src/variable-name-inference.test.ts +0 -178
  223. package/src/variable-name-inference.ts +0 -242
  224. package/src/webhook.test.ts +0 -649
  225. package/src/webhook.ts +0 -637
  226. package/src/workflow-distributed.test.ts +0 -786
  227. package/src/workflow-distributed.ts +0 -916
  228. package/src/workflow.async-safety.integration.test.ts +0 -345
  229. package/src/workflow.test.ts +0 -647
  230. package/src/workflow.ts +0 -810
  231. package/src/yaml-config.test.ts +0 -337
  232. package/src/yaml-config.ts +0 -342
@@ -1,133 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import {
3
- defineErrorCatalog,
4
- defineAuditCatalog,
5
- isCatalogError,
6
- getCatalogCode,
7
- } from './error-catalog';
8
-
9
- describe('defineErrorCatalog', () => {
10
- const billing = defineErrorCatalog('billing', {
11
- PAYMENT_DECLINED: {
12
- status: 402,
13
- message: 'Card declined',
14
- why: 'The issuer rejected the charge',
15
- fix: 'Try a different payment method',
16
- link: 'https://docs.example.com/billing',
17
- },
18
- INSUFFICIENT_FUNDS: {
19
- status: 402,
20
- message: ({
21
- available,
22
- required,
23
- }: {
24
- available: number;
25
- required: number;
26
- }) => `Insufficient funds: $${available} of $${required}`,
27
- why: ({ required }: { available: number; required: number }) =>
28
- `Needs $${required}`,
29
- },
30
- LEGACY: {
31
- code: 'BILLING_LEGACY_42',
32
- message: 'Legacy failure',
33
- },
34
- });
35
-
36
- it('builds a structured error from a static entry', () => {
37
- const err = billing.PAYMENT_DECLINED();
38
- expect(err).toBeInstanceOf(Error);
39
- expect(err.message).toBe('Card declined');
40
- expect(err.status).toBe(402);
41
- expect(err.why).toBe('The issuer rejected the charge');
42
- expect(err.fix).toBe('Try a different payment method');
43
- expect(err.link).toBe('https://docs.example.com/billing');
44
- expect(err.code).toBe('billing.PAYMENT_DECLINED');
45
- expect(err.name).toBe('PAYMENT_DECLINED');
46
- });
47
-
48
- it('interpolates typed params in message and why', () => {
49
- const err = billing.INSUFFICIENT_FUNDS({ available: 5, required: 100 });
50
- expect(err.message).toBe('Insufficient funds: $5 of $100');
51
- expect(err.why).toBe('Needs $100');
52
- });
53
-
54
- it('honors a custom code', () => {
55
- const err = billing.LEGACY();
56
- expect(err.code).toBe('BILLING_LEGACY_42');
57
- });
58
-
59
- it('exposes the code on the builder', () => {
60
- expect(billing.PAYMENT_DECLINED.code).toBe('billing.PAYMENT_DECLINED');
61
- expect(billing.LEGACY.code).toBe('BILLING_LEGACY_42');
62
- });
63
-
64
- it('matches its own errors and rejects others', () => {
65
- const declined = billing.PAYMENT_DECLINED();
66
- const funds = billing.INSUFFICIENT_FUNDS({ available: 1, required: 2 });
67
- expect(billing.PAYMENT_DECLINED.match(declined)).toBe(true);
68
- expect(billing.PAYMENT_DECLINED.match(funds)).toBe(false);
69
- expect(billing.PAYMENT_DECLINED.match(new Error('nope'))).toBe(false);
70
- expect(billing.PAYMENT_DECLINED.match(null)).toBe(false);
71
- });
72
-
73
- it('tags errors so isCatalogError / getCatalogCode work', () => {
74
- const err = billing.PAYMENT_DECLINED();
75
- expect(isCatalogError(err)).toBe(true);
76
- expect(isCatalogError(new Error('plain'))).toBe(false);
77
- expect(getCatalogCode(err)).toBe('billing.PAYMENT_DECLINED');
78
- expect(getCatalogCode(new Error('plain'))).toBeUndefined();
79
- });
80
-
81
- it('passes cause, details, and internal through build options', () => {
82
- const cause = new Error('stripe boom');
83
- const err = billing.PAYMENT_DECLINED({
84
- cause,
85
- details: { attempt: 2 },
86
- internal: { stripeId: 'ch_1' },
87
- });
88
- expect(err.cause).toBe(cause);
89
- expect(err.details).toEqual({ attempt: 2 });
90
- expect(err.internal).toEqual({ stripeId: 'ch_1' });
91
- });
92
-
93
- it('accepts options as the second arg for param entries', () => {
94
- const cause = new Error('root');
95
- const err = billing.INSUFFICIENT_FUNDS(
96
- { available: 5, required: 100 },
97
- { cause },
98
- );
99
- expect(err.message).toBe('Insufficient funds: $5 of $100');
100
- expect(err.cause).toBe(cause);
101
- });
102
- });
103
-
104
- describe('defineAuditCatalog', () => {
105
- const audit = defineAuditCatalog('user', {
106
- LOGIN: { message: 'User logged in' },
107
- ROLE_CHANGED: {
108
- severity: 'critical',
109
- message: ({ role }: { role: string }) => `Role set to ${role}`,
110
- },
111
- DELETED: { action: 'user.account.deleted', severity: 'warn' },
112
- });
113
-
114
- it('produces typed action descriptors with defaults', () => {
115
- const action = audit.LOGIN();
116
- expect(action.action).toBe('user.LOGIN');
117
- expect(action.severity).toBe('info');
118
- expect(action.message).toBe('User logged in');
119
- });
120
-
121
- it('interpolates params and respects severity', () => {
122
- const action = audit.ROLE_CHANGED({ role: 'admin' });
123
- expect(action.action).toBe('user.ROLE_CHANGED');
124
- expect(action.severity).toBe('critical');
125
- expect(action.message).toBe('Role set to admin');
126
- });
127
-
128
- it('honors a custom action name', () => {
129
- expect(audit.DELETED.action).toBe('user.account.deleted');
130
- expect(audit.DELETED.severity).toBe('warn');
131
- expect(audit.DELETED().message).toBeUndefined();
132
- });
133
- });
@@ -1,262 +0,0 @@
1
- /**
2
- * Typed error and audit catalogs.
3
- *
4
- * Group related errors into one catalog and get a refactor-safe builder per
5
- * code, with autocomplete at every call site and typed message parameters.
6
- *
7
- * @example
8
- * ```typescript
9
- * import { defineErrorCatalog } from 'autotel';
10
- *
11
- * export const billing = defineErrorCatalog('billing', {
12
- * PAYMENT_DECLINED: {
13
- * status: 402,
14
- * message: 'Card declined',
15
- * why: 'The issuer rejected the charge',
16
- * fix: 'Try a different payment method',
17
- * },
18
- * INSUFFICIENT_FUNDS: {
19
- * status: 402,
20
- * message: ({ available, required }: { available: number; required: number }) =>
21
- * `Insufficient funds: $${available} of $${required}`,
22
- * },
23
- * });
24
- *
25
- * throw billing.PAYMENT_DECLINED({ cause: stripeError });
26
- * throw billing.INSUFFICIENT_FUNDS({ available: 5, required: 100 });
27
- *
28
- * // In a catch block — refactor-safe, no magic strings:
29
- * if (billing.PAYMENT_DECLINED.match(err)) { ... }
30
- * ```
31
- */
32
-
33
- import {
34
- createStructuredError,
35
- type StructuredError,
36
- } from './structured-error';
37
-
38
- const catalogCodeKey = Symbol.for('autotel.catalog.code');
39
-
40
- /** Definition of a single error in a catalog. */
41
- export interface ErrorCatalogEntry {
42
- /**
43
- * Human-readable message. Use a function to interpolate typed parameters;
44
- * the parameter type flows through to the call site.
45
- */
46
- message: string | ((params: never) => string);
47
- /** HTTP status to surface to clients. */
48
- status?: number;
49
- /** Stable error code. Defaults to `${namespace}.${KEY}`. */
50
- code?: string | number;
51
- /** Why it happened. A function receives the same params as `message`. */
52
- why?: string | ((params: never) => string);
53
- /** What the caller should do next. */
54
- fix?: string;
55
- /** Docs or runbook link. */
56
- link?: string;
57
- /** Error name. Defaults to the catalog key. */
58
- name?: string;
59
- }
60
-
61
- /** Per-call options passed alongside (or instead of) typed params. */
62
- export interface ErrorBuildOptions {
63
- cause?: unknown;
64
- details?: Record<string, unknown>;
65
- /** Backend-only context. Never serialized to clients. */
66
- internal?: Record<string, unknown>;
67
- }
68
-
69
- type ParamsOf<E> = E extends { message: (params: infer P) => string }
70
- ? P
71
- : E extends { why: (params: infer P) => string }
72
- ? P
73
- : void;
74
-
75
- type BuilderArgs<E extends ErrorCatalogEntry> =
76
- ParamsOf<E> extends void
77
- ? [options?: ErrorBuildOptions]
78
- : [params: ParamsOf<E>, options?: ErrorBuildOptions];
79
-
80
- /** A callable error factory produced by {@link defineErrorCatalog}. */
81
- export interface ErrorBuilder<E extends ErrorCatalogEntry> {
82
- (...args: BuilderArgs<E>): StructuredError;
83
- /** Stable code assigned to every error from this entry. */
84
- readonly code: string | number;
85
- /** True when `error` was produced by this catalog entry. */
86
- match(error: unknown): boolean;
87
- }
88
-
89
- export type ErrorCatalog<T extends Record<string, ErrorCatalogEntry>> = {
90
- readonly [K in keyof T]: ErrorBuilder<T[K]>;
91
- };
92
-
93
- function readCatalogCode(error: unknown): string | number | undefined {
94
- if (error === null || typeof error !== 'object') return undefined;
95
- return (error as Record<symbol, unknown>)[catalogCodeKey] as
96
- | string
97
- | number
98
- | undefined;
99
- }
100
-
101
- /** True when `error` was produced by any autotel error catalog. */
102
- export function isCatalogError(error: unknown): error is StructuredError {
103
- return readCatalogCode(error) !== undefined;
104
- }
105
-
106
- /** Returns the catalog code of `error`, or `undefined` if it has none. */
107
- export function getCatalogCode(error: unknown): string | number | undefined {
108
- return readCatalogCode(error);
109
- }
110
-
111
- /**
112
- * Define a typed error catalog. Returns an object whose keys are error
113
- * builders. Each builder produces a {@link StructuredError} carrying the
114
- * entry's message, status, code, why, fix, and link.
115
- */
116
- export function defineErrorCatalog<
117
- const T extends Record<string, ErrorCatalogEntry>,
118
- >(namespace: string, entries: T): ErrorCatalog<T> {
119
- const catalog: Record<string, ErrorBuilder<ErrorCatalogEntry>> = {};
120
-
121
- for (const [key, entry] of Object.entries(entries) as [
122
- string,
123
- ErrorCatalogEntry,
124
- ][]) {
125
- const code = entry.code ?? `${namespace}.${key}`;
126
- const usesParams =
127
- typeof entry.message === 'function' || typeof entry.why === 'function';
128
-
129
- const builder = ((
130
- paramsOrOptions?: unknown,
131
- maybeOptions?: ErrorBuildOptions,
132
- ): StructuredError => {
133
- const params = usesParams ? paramsOrOptions : undefined;
134
- const options = (usesParams ? maybeOptions : paramsOrOptions) as
135
- | ErrorBuildOptions
136
- | undefined;
137
-
138
- const message =
139
- typeof entry.message === 'function'
140
- ? (entry.message as (p: unknown) => string)(params)
141
- : entry.message;
142
- const why =
143
- typeof entry.why === 'function'
144
- ? (entry.why as (p: unknown) => string)(params)
145
- : entry.why;
146
-
147
- const error = createStructuredError({
148
- message,
149
- name: entry.name ?? key,
150
- code,
151
- ...(entry.status === undefined ? {} : { status: entry.status }),
152
- ...(why === undefined ? {} : { why }),
153
- ...(entry.fix === undefined ? {} : { fix: entry.fix }),
154
- ...(entry.link === undefined ? {} : { link: entry.link }),
155
- ...(options?.cause === undefined ? {} : { cause: options.cause }),
156
- ...(options?.details === undefined ? {} : { details: options.details }),
157
- ...(options?.internal === undefined
158
- ? {}
159
- : { internal: options.internal }),
160
- });
161
-
162
- Object.defineProperty(error, catalogCodeKey, {
163
- value: code,
164
- enumerable: false,
165
- writable: false,
166
- configurable: true,
167
- });
168
-
169
- return error;
170
- }) as ErrorBuilder<ErrorCatalogEntry>;
171
-
172
- Object.defineProperty(builder, 'code', {
173
- value: code,
174
- enumerable: true,
175
- });
176
- Object.defineProperty(builder, 'match', {
177
- value: (error: unknown): boolean => readCatalogCode(error) === code,
178
- enumerable: false,
179
- });
180
-
181
- catalog[key] = builder;
182
- }
183
-
184
- return Object.freeze(catalog) as ErrorCatalog<T>;
185
- }
186
-
187
- /** Severity of an audit action. */
188
- export type AuditSeverity = 'info' | 'warn' | 'critical';
189
-
190
- /** Definition of a single action in an audit catalog. */
191
- export interface AuditCatalogEntry {
192
- /** Human-readable description. Use a function for typed params. */
193
- message?: string | ((params: never) => string);
194
- /** Stable action name. Defaults to `${namespace}.${KEY}`. */
195
- action?: string;
196
- /** Severity of the action. Defaults to `'info'`. */
197
- severity?: AuditSeverity;
198
- }
199
-
200
- /** A resolved audit action descriptor produced by an audit catalog. */
201
- export interface AuditAction {
202
- readonly action: string;
203
- readonly severity: AuditSeverity;
204
- readonly message?: string;
205
- }
206
-
207
- type AuditDescriptorArgs<E extends AuditCatalogEntry> =
208
- ParamsOf<E> extends void ? [] : [params: ParamsOf<E>];
209
-
210
- /** A callable audit-action descriptor produced by {@link defineAuditCatalog}. */
211
- export interface AuditDescriptor<E extends AuditCatalogEntry> {
212
- (...args: AuditDescriptorArgs<E>): AuditAction;
213
- readonly action: string;
214
- readonly severity: AuditSeverity;
215
- }
216
-
217
- export type AuditCatalog<T extends Record<string, AuditCatalogEntry>> = {
218
- readonly [K in keyof T]: AuditDescriptor<T[K]>;
219
- };
220
-
221
- /**
222
- * Define a typed audit catalog. Returns typed action descriptors you can pass
223
- * to `track()` or audit helpers without scattering magic strings.
224
- */
225
- export function defineAuditCatalog<
226
- const T extends Record<string, AuditCatalogEntry>,
227
- >(namespace: string, entries: T): AuditCatalog<T> {
228
- const catalog: Record<string, AuditDescriptor<AuditCatalogEntry>> = {};
229
-
230
- for (const [key, entry] of Object.entries(entries) as [
231
- string,
232
- AuditCatalogEntry,
233
- ][]) {
234
- const action = entry.action ?? `${namespace}.${key}`;
235
- const severity: AuditSeverity = entry.severity ?? 'info';
236
-
237
- const descriptor = ((params?: unknown): AuditAction => {
238
- const message =
239
- typeof entry.message === 'function'
240
- ? (entry.message as (p: unknown) => string)(params)
241
- : entry.message;
242
- return Object.freeze({
243
- action,
244
- severity,
245
- ...(message === undefined ? {} : { message }),
246
- });
247
- }) as AuditDescriptor<AuditCatalogEntry>;
248
-
249
- Object.defineProperty(descriptor, 'action', {
250
- value: action,
251
- enumerable: true,
252
- });
253
- Object.defineProperty(descriptor, 'severity', {
254
- value: severity,
255
- enumerable: true,
256
- });
257
-
258
- catalog[key] = descriptor;
259
- }
260
-
261
- return Object.freeze(catalog) as AuditCatalog<T>;
262
- }