@pafi-dev/issuer 0.39.2 → 0.39.3

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.
@@ -3,6 +3,7 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
6
7
  var __export = (target, all) => {
7
8
  for (var name in all)
8
9
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -16,15 +17,6 @@ var __copyProps = (to, from, except, desc) => {
16
17
  return to;
17
18
  };
18
19
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
- var __decorateClass = (decorators, target, key, kind) => {
20
- var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
- for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
- if (decorator = decorators[i])
23
- result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
- if (kind && result) __defProp(target, key, result);
25
- return result;
26
- };
27
- var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
28
20
 
29
21
  // src/nestjs/index.ts
30
22
  var nestjs_exports = {};
@@ -59,17 +51,20 @@ function buildSdkErrorBody(err) {
59
51
  if (err.details !== void 0) body.details = err.details;
60
52
  return body;
61
53
  }
54
+ __name(buildSdkErrorBody, "buildSdkErrorBody");
62
55
 
63
56
  // src/http/errorEnvelope.ts
64
57
  function isValidationPipeBody(body) {
65
58
  return Array.isArray(body["message"]) && typeof body["error"] === "string" && body["error"] === "Bad Request";
66
59
  }
60
+ __name(isValidationPipeBody, "isValidationPipeBody");
67
61
  function extractParamFromValidatorMessage(message) {
68
62
  const idx = message.indexOf(" ");
69
63
  if (idx <= 0) return void 0;
70
64
  const candidate = message.slice(0, idx);
71
65
  return /^[A-Za-z_][\w.]*$/.test(candidate) ? candidate : void 0;
72
66
  }
67
+ __name(extractParamFromValidatorMessage, "extractParamFromValidatorMessage");
73
68
  function normalizeValidationPipeBody(body) {
74
69
  const fields = {};
75
70
  for (const msg of body.message) {
@@ -84,11 +79,14 @@ function normalizeValidationPipeBody(body) {
84
79
  code: "VALIDATION_FAILED",
85
80
  message: body.message.join("; "),
86
81
  safeToRetry: false,
87
- metadata: { fieldErrors: fields }
82
+ metadata: {
83
+ fieldErrors: fields
84
+ }
88
85
  };
89
86
  if (param) payload.param = param;
90
87
  return payload;
91
88
  }
89
+ __name(normalizeValidationPipeBody, "normalizeValidationPipeBody");
92
90
  function normalizeHttpExceptionBody(desc) {
93
91
  const { statusCode, responseBody, exceptionName, fallbackMessage } = desc;
94
92
  const defaultType = (0, import_core.defaultErrorTypeForStatus)(statusCode);
@@ -129,6 +127,7 @@ function normalizeHttpExceptionBody(desc) {
129
127
  safeToRetry: false
130
128
  };
131
129
  }
130
+ __name(normalizeHttpExceptionBody, "normalizeHttpExceptionBody");
132
131
  function payloadFromPafiSdkError(err) {
133
132
  const body = buildSdkErrorBody(err);
134
133
  const payload = {
@@ -142,10 +141,12 @@ function payloadFromPafiSdkError(err) {
142
141
  if (body.details !== void 0) payload.details = body.details;
143
142
  return payload;
144
143
  }
144
+ __name(payloadFromPafiSdkError, "payloadFromPafiSdkError");
145
145
  function sanitizeDbErrorMessage(message) {
146
146
  if (/^[A-Z_]+: /.test(message) && message.length < 256) return message;
147
147
  return "Internal database error";
148
148
  }
149
+ __name(sanitizeDbErrorMessage, "sanitizeDbErrorMessage");
149
150
  function buildErrorEnvelope(input) {
150
151
  const now = (input.ctx.now ?? (() => /* @__PURE__ */ new Date()))();
151
152
  return {
@@ -159,9 +160,11 @@ function buildErrorEnvelope(input) {
159
160
  }
160
161
  };
161
162
  }
163
+ __name(buildErrorEnvelope, "buildErrorEnvelope");
162
164
  function payloadFromHttpException(desc) {
163
165
  return normalizeHttpExceptionBody(desc);
164
166
  }
167
+ __name(payloadFromHttpException, "payloadFromHttpException");
165
168
  function payloadFromGenericError(err) {
166
169
  const name = err.name || "INTERNAL_SERVER_ERROR";
167
170
  const isDbError = name === "QueryFailedError" || name === "EntityNotFoundError";
@@ -172,9 +175,24 @@ function payloadFromGenericError(err) {
172
175
  safeToRetry: false
173
176
  };
174
177
  }
178
+ __name(payloadFromGenericError, "payloadFromGenericError");
175
179
 
176
180
  // src/nestjs/httpExceptionFilter.ts
181
+ function _ts_decorate(decorators, target, key, desc) {
182
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
183
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
184
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
185
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
186
+ }
187
+ __name(_ts_decorate, "_ts_decorate");
188
+ function _ts_metadata(k, v) {
189
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
190
+ }
191
+ __name(_ts_metadata, "_ts_metadata");
177
192
  var PafiHttpExceptionFilter = class {
193
+ static {
194
+ __name(this, "PafiHttpExceptionFilter");
195
+ }
178
196
  logger = new import_common.Logger("PafiHttpExceptionFilter");
179
197
  opts;
180
198
  constructor(options = {}) {
@@ -192,31 +210,33 @@ var PafiHttpExceptionFilter = class {
192
210
  const normCtx = {
193
211
  path: request?.url ?? "",
194
212
  requestId,
195
- ...this.opts.now ? { now: this.opts.now } : {}
213
+ ...this.opts.now ? {
214
+ now: this.opts.now
215
+ } : {}
196
216
  };
197
217
  const { status, payload } = this.normalize(exception);
198
- const envelope = buildErrorEnvelope({ status, payload, ctx: normCtx });
218
+ const envelope = buildErrorEnvelope({
219
+ status,
220
+ payload,
221
+ ctx: normCtx
222
+ });
199
223
  if (this.opts.onError) {
200
224
  try {
201
225
  this.opts.onError(envelope, exception);
202
226
  } catch (hookErr) {
203
- this.logger.warn(
204
- { err: hookErr instanceof Error ? hookErr.message : String(hookErr) },
205
- "onError hook threw; continuing"
206
- );
227
+ this.logger.warn({
228
+ err: hookErr instanceof Error ? hookErr.message : String(hookErr)
229
+ }, "onError hook threw; continuing");
207
230
  }
208
231
  }
209
232
  if (status >= 500) {
210
- this.logger.error(
211
- {
212
- err: exception instanceof Error ? exception.message : String(exception),
213
- stack: exception instanceof Error ? exception.stack : void 0,
214
- name: exception instanceof Error ? exception.name : void 0,
215
- path: normCtx.path,
216
- requestId
217
- },
218
- "Unhandled error in PafiHttpExceptionFilter"
219
- );
233
+ this.logger.error({
234
+ err: exception instanceof Error ? exception.message : String(exception),
235
+ stack: exception instanceof Error ? exception.stack : void 0,
236
+ name: exception instanceof Error ? exception.name : void 0,
237
+ path: normCtx.path,
238
+ requestId
239
+ }, "Unhandled error in PafiHttpExceptionFilter");
220
240
  }
221
241
  response.status(status).json(envelope);
222
242
  }
@@ -269,8 +289,12 @@ var PafiHttpExceptionFilter = class {
269
289
  };
270
290
  }
271
291
  };
272
- PafiHttpExceptionFilter = __decorateClass([
273
- (0, import_common.Catch)()
292
+ PafiHttpExceptionFilter = _ts_decorate([
293
+ (0, import_common.Catch)(),
294
+ _ts_metadata("design:type", Function),
295
+ _ts_metadata("design:paramtypes", [
296
+ typeof PafiHttpExceptionFilterOptions === "undefined" ? Object : PafiHttpExceptionFilterOptions
297
+ ])
274
298
  ], PafiHttpExceptionFilter);
275
299
 
276
300
  // src/nestjs/walletAuthJwks.module.ts
@@ -283,35 +307,74 @@ var import_common2 = require("@nestjs/common");
283
307
  var WALLET_AUTH_JWKS_KEYS = /* @__PURE__ */ Symbol("WALLET_AUTH_JWKS_KEYS");
284
308
 
285
309
  // src/nestjs/walletAuthJwks.controller.ts
286
- var WalletAuthJwksController = class {
287
- logger = new import_common2.Logger(WalletAuthJwksController.name);
310
+ function _ts_decorate2(decorators, target, key, desc) {
311
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
312
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
313
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
314
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
315
+ }
316
+ __name(_ts_decorate2, "_ts_decorate");
317
+ function _ts_metadata2(k, v) {
318
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
319
+ }
320
+ __name(_ts_metadata2, "_ts_metadata");
321
+ function _ts_param(paramIndex, decorator) {
322
+ return function(target, key) {
323
+ decorator(target, key, paramIndex);
324
+ };
325
+ }
326
+ __name(_ts_param, "_ts_param");
327
+ var WalletAuthJwksController = class _WalletAuthJwksController {
328
+ static {
329
+ __name(this, "WalletAuthJwksController");
330
+ }
331
+ logger = new import_common2.Logger(_WalletAuthJwksController.name);
288
332
  jwks;
289
333
  constructor(keys) {
290
- this.jwks = { keys };
334
+ this.jwks = {
335
+ keys
336
+ };
291
337
  const kids = keys.map((k) => k.kid).join(", ");
292
- this.logger.log(
293
- `JWKS endpoint ready \u2014 ${keys.length} key(s) published: ${kids || "(empty)"}`
294
- );
338
+ this.logger.log(`JWKS endpoint ready \u2014 ${keys.length} key(s) published: ${kids || "(empty)"}`);
295
339
  }
296
340
  getJwks() {
297
341
  return this.jwks;
298
342
  }
299
343
  };
300
- __decorateClass([
344
+ _ts_decorate2([
301
345
  (0, import_common2.Get)("jwks.json"),
302
- (0, import_common2.HttpCode)(import_common2.HttpStatus.OK)
303
- ], WalletAuthJwksController.prototype, "getJwks", 1);
304
- WalletAuthJwksController = __decorateClass([
346
+ (0, import_common2.HttpCode)(import_common2.HttpStatus.OK),
347
+ _ts_metadata2("design:type", Function),
348
+ _ts_metadata2("design:paramtypes", []),
349
+ _ts_metadata2("design:returntype", Object)
350
+ ], WalletAuthJwksController.prototype, "getJwks", null);
351
+ WalletAuthJwksController = _ts_decorate2([
305
352
  (0, import_common2.Controller)(".well-known"),
306
- __decorateParam(0, (0, import_common2.Inject)(WALLET_AUTH_JWKS_KEYS))
353
+ _ts_param(0, (0, import_common2.Inject)(WALLET_AUTH_JWKS_KEYS)),
354
+ _ts_metadata2("design:type", Function),
355
+ _ts_metadata2("design:paramtypes", [
356
+ Array
357
+ ])
307
358
  ], WalletAuthJwksController);
308
359
 
309
360
  // src/nestjs/walletAuthJwks.module.ts
310
- var WalletAuthJwksModule = class {
361
+ function _ts_decorate3(decorators, target, key, desc) {
362
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
363
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
364
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
365
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
366
+ }
367
+ __name(_ts_decorate3, "_ts_decorate");
368
+ var WalletAuthJwksModule = class _WalletAuthJwksModule {
369
+ static {
370
+ __name(this, "WalletAuthJwksModule");
371
+ }
311
372
  static forRoot(options) {
312
373
  return {
313
- module: WalletAuthJwksModule,
314
- controllers: [WalletAuthJwksController],
374
+ module: _WalletAuthJwksModule,
375
+ controllers: [
376
+ WalletAuthJwksController
377
+ ],
315
378
  providers: [
316
379
  {
317
380
  provide: WALLET_AUTH_JWKS_KEYS,
@@ -322,23 +385,25 @@ var WalletAuthJwksModule = class {
322
385
  }
323
386
  static forRootAsync(options) {
324
387
  return {
325
- module: WalletAuthJwksModule,
388
+ module: _WalletAuthJwksModule,
326
389
  imports: options.imports ?? [],
327
- controllers: [WalletAuthJwksController],
390
+ controllers: [
391
+ WalletAuthJwksController
392
+ ],
328
393
  providers: [
329
394
  {
330
395
  provide: WALLET_AUTH_JWKS_KEYS,
331
396
  inject: options.inject ?? [],
332
- useFactory: async (...args) => {
397
+ useFactory: /* @__PURE__ */ __name(async (...args) => {
333
398
  const opts = await options.useFactory(...args);
334
399
  return validateKeys(opts.keys);
335
- }
400
+ }, "useFactory")
336
401
  }
337
402
  ]
338
403
  };
339
404
  }
340
405
  };
341
- WalletAuthJwksModule = __decorateClass([
406
+ WalletAuthJwksModule = _ts_decorate3([
342
407
  (0, import_common3.Module)({})
343
408
  ], WalletAuthJwksModule);
344
409
  function validateKeys(keys) {
@@ -353,13 +418,12 @@ function validateKeys(keys) {
353
418
  throw new Error("WalletAuthJwksModule: each key must have a `kty` field");
354
419
  }
355
420
  if (!k.kid) {
356
- throw new Error(
357
- "WalletAuthJwksModule: each key must have a `kid` field \u2014 PAFI gateway uses kid to look up the verification key"
358
- );
421
+ throw new Error("WalletAuthJwksModule: each key must have a `kid` field \u2014 PAFI gateway uses kid to look up the verification key");
359
422
  }
360
423
  }
361
424
  return keys;
362
425
  }
426
+ __name(validateKeys, "validateKeys");
363
427
  // Annotate the CommonJS export names for ESM import in node:
364
428
  0 && (module.exports = {
365
429
  PafiHttpExceptionFilter,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/nestjs/index.ts","../../src/nestjs/httpExceptionFilter.ts","../../src/errors.ts","../../src/api/errorMapper.ts","../../src/http/errorEnvelope.ts","../../src/nestjs/walletAuthJwks.module.ts","../../src/nestjs/walletAuthJwks.controller.ts","../../src/nestjs/walletAuthJwks.tokens.ts"],"sourcesContent":["export {\n PafiHttpExceptionFilter,\n type PafiHttpExceptionFilterOptions,\n} from \"./httpExceptionFilter\";\n\nexport {\n WalletAuthJwksModule,\n type WalletAuthJwksOptions,\n type WalletAuthJwksAsyncOptions,\n} from \"./walletAuthJwks.module\";\nexport { WalletAuthJwksController } from \"./walletAuthJwks.controller\";\nexport { WALLET_AUTH_JWKS_KEYS } from \"./walletAuthJwks.tokens\";\n","/**\n * NestJS global exception filter that emits the PAFI Stripe-style\n * envelope (see `@pafi-dev/issuer/http`).\n *\n * Wire it once in your bootstrap:\n *\n * ```ts\n * import { PafiHttpExceptionFilter } from \"@pafi-dev/issuer/nestjs\";\n *\n * app.useGlobalFilters(new PafiHttpExceptionFilter());\n * ```\n *\n * Catches every thrown value:\n * - `PafiSdkError` (and subclasses) → typed envelope from `httpStatus`/\n * `code`/`type`/`safeToRetry`/`param`/`metadata`.\n * - `HttpException` (NestJS) → respected status; SDK-shaped body is\n * passed through, plain bodies + ValidationPipe arrays normalized.\n * - any other `Error` → `server_error` 500 with sanitized message.\n *\n * `@nestjs/common` is an optional peer dependency — only required when\n * importing this sub-export.\n */\nimport {\n ArgumentsHost,\n Catch,\n ExceptionFilter,\n HttpException,\n HttpStatus,\n Logger,\n} from \"@nestjs/common\";\nimport { randomUUID } from \"node:crypto\";\n\nimport { PafiSdkError, SDK_ERROR_HTTP_STATUS_CODE } from \"../errors\";\nimport {\n buildErrorEnvelope,\n payloadFromGenericError,\n payloadFromHttpException,\n payloadFromPafiSdkError,\n type NormalizeContext,\n type PafiErrorEnvelope,\n type PafiErrorPayload,\n} from \"../http/errorEnvelope\";\n\ninterface MinimalHttpRequest {\n url?: string;\n headers?: Record<string, string | string[] | undefined>;\n}\ninterface MinimalHttpResponse {\n status(code: number): MinimalHttpResponse;\n json(body: unknown): unknown;\n}\n\n/** Customization knobs. None required — sensible defaults baked in. */\nexport interface PafiHttpExceptionFilterOptions {\n /**\n * Header to read for the request id, lowercase. Default `\"x-request-id\"`.\n * If absent, a UUIDv4 is generated per request.\n */\n requestIdHeader?: string;\n /**\n * Override `Date` for deterministic tests.\n */\n now?: () => Date;\n /**\n * Hook to record normalized errors before sending. Useful for\n * Sentry / Datadog / Pino. Throws are swallowed so a logging bug\n * never masks the real error response.\n */\n onError?: (envelope: PafiErrorEnvelope, raw: unknown) => void;\n}\n\n@Catch()\nexport class PafiHttpExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(\"PafiHttpExceptionFilter\");\n private readonly opts: Required<\n Pick<PafiHttpExceptionFilterOptions, \"requestIdHeader\">\n > &\n PafiHttpExceptionFilterOptions;\n\n constructor(options: PafiHttpExceptionFilterOptions = {}) {\n this.opts = {\n requestIdHeader: options.requestIdHeader ?? \"x-request-id\",\n ...options,\n };\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<MinimalHttpResponse>();\n const request = ctx.getRequest<MinimalHttpRequest>();\n\n const headerValue = request?.headers?.[this.opts.requestIdHeader];\n const requestId =\n (Array.isArray(headerValue) ? headerValue[0] : headerValue) ??\n randomUUID();\n\n const normCtx: NormalizeContext = {\n path: request?.url ?? \"\",\n requestId,\n ...(this.opts.now ? { now: this.opts.now } : {}),\n };\n\n const { status, payload } = this.normalize(exception);\n const envelope = buildErrorEnvelope({ status, payload, ctx: normCtx });\n\n if (this.opts.onError) {\n try {\n this.opts.onError(envelope, exception);\n } catch (hookErr) {\n this.logger.warn(\n { err: hookErr instanceof Error ? hookErr.message : String(hookErr) },\n \"onError hook threw; continuing\",\n );\n }\n }\n\n if (status >= 500) {\n this.logger.error(\n {\n err:\n exception instanceof Error\n ? exception.message\n : String(exception),\n stack: exception instanceof Error ? exception.stack : undefined,\n name: exception instanceof Error ? exception.name : undefined,\n path: normCtx.path,\n requestId,\n },\n \"Unhandled error in PafiHttpExceptionFilter\",\n );\n }\n\n response.status(status).json(envelope);\n }\n\n private normalize(exception: unknown): {\n status: number;\n payload: PafiErrorPayload;\n } {\n if (exception instanceof PafiSdkError) {\n return {\n status: SDK_ERROR_HTTP_STATUS_CODE[exception.httpStatus],\n payload: payloadFromPafiSdkError(exception),\n };\n }\n\n if (exception instanceof HttpException) {\n return {\n status: exception.getStatus(),\n payload: payloadFromHttpException({\n statusCode: exception.getStatus(),\n responseBody: exception.getResponse(),\n exceptionName: exception.name,\n fallbackMessage: exception.message,\n }),\n };\n }\n\n if (exception instanceof Error) {\n // Duck-typing for HttpException instances that fail `instanceof`\n // when multiple `@nestjs/common` copies exist in the dep tree.\n const maybeStatus = (exception as { status?: unknown }).status;\n const maybeGetResponse = (\n exception as { getResponse?: () => unknown }\n ).getResponse;\n if (\n typeof maybeStatus === \"number\" &&\n typeof maybeGetResponse === \"function\"\n ) {\n return {\n status: maybeStatus,\n payload: payloadFromHttpException({\n statusCode: maybeStatus,\n responseBody: maybeGetResponse.call(exception),\n exceptionName: exception.name,\n fallbackMessage: exception.message,\n }),\n };\n }\n const maybeStatusOnly =\n typeof maybeStatus === \"number\"\n ? maybeStatus\n : HttpStatus.INTERNAL_SERVER_ERROR;\n return {\n status: maybeStatusOnly,\n payload: payloadFromGenericError(exception),\n };\n }\n\n return {\n status: HttpStatus.INTERNAL_SERVER_ERROR,\n payload: {\n type: \"server_error\",\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"An unexpected error occurred\",\n safeToRetry: false,\n },\n };\n }\n}\n","/**\n * `PafiSdkError` + `SdkErrorHttpStatus` are exported from\n * `@pafi-dev/core/errors` so core-level errors (e.g. `OracleStaleError`)\n * can extend the same base. Issuer re-exports the canonical types here\n * for back-compat — `instanceof PafiSdkError` from EITHER package\n * catches errors thrown from EITHER package.\n */\nexport {\n PafiSdkError,\n SDK_ERROR_HTTP_STATUS_CODE,\n defaultErrorTypeForStatus,\n type SdkErrorHttpStatus,\n type PafiErrorType,\n} from \"@pafi-dev/core\";\nimport { PafiSdkError } from \"@pafi-dev/core\";\n\n/**\n * `ValidationError` lives in `@pafi-dev/core` so core/trading helpers\n * throw the same typed class. Re-exported here for back-compat.\n */\nexport { ValidationError } from \"@pafi-dev/core\";\n\n/**\n * Issuer wired the SDK without a dependency the requested endpoint\n * needs (e.g. `/gas-fee` called but `feeManager` not configured;\n * `/pools` called but `poolsProvider` not configured). 503 because\n * the endpoint genuinely can't serve the request — caller's payload\n * is fine, the issuer's deployment is incomplete.\n */\nexport class ConfigurationError extends PafiSdkError {\n readonly httpStatus = \"service_unavailable\" as const;\n readonly code: string;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: string,\n message: string,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.code = code;\n this.details = details;\n }\n}\n","import {\n PafiSdkError,\n SDK_ERROR_HTTP_STATUS_CODE,\n defaultErrorTypeForStatus,\n type PafiErrorType,\n type SdkErrorHttpStatus,\n} from \"../errors\";\n\n/**\n * Normalized HTTP status the issuer controller should surface for a\n * given SDK error. Mirrors `SdkErrorHttpStatus` on `PafiSdkError`.\n */\nexport type SdkErrorStatus = SdkErrorHttpStatus;\n\n/**\n * Structured body the issuer controller passes to its\n * framework-specific exception class. Stripe-style envelope:\n *\n * ```json\n * {\n * \"type\": \"business_logic_error\",\n * \"code\": \"REDEMPTION_POLICY_DENIED\",\n * \"message\": \"...\",\n * \"param\": null,\n * \"metadata\": { \"policyDenialCode\": \"PER_TX_MIN\" },\n * \"safeToRetry\": false\n * }\n * ```\n *\n * Carries enough fields for the global HTTP filter to emit the final\n * envelope without losing any SDK-side context.\n */\nexport interface SdkErrorBody {\n /** Stripe-style taxonomy slot — drives UI branching. */\n type: PafiErrorType;\n /** Machine-readable code, e.g. `\"REDEMPTION_POLICY_DENIED\"`. */\n code: string;\n /** Human-readable message. */\n message: string;\n /** Field name that triggered the error, when applicable. */\n param?: string;\n /** UI-facing structured context. */\n metadata?: Record<string, unknown>;\n /** Raw debug context. */\n details?: unknown;\n /** True when retry is safe (no side effects yet). */\n safeToRetry: boolean;\n}\n\n/**\n * Per-status exception factories. The issuer's controller wires one\n * factory per status to its preferred framework's exception class\n * (NestJS `UnprocessableEntityException`, Fastify `httpErrors.badData`,\n * etc). The factory must return an Error — `createSdkErrorMapper`\n * uses `throw factory(body)`.\n */\nexport interface SdkErrorMapperFactories {\n notFound: (body: SdkErrorBody) => Error;\n forbidden: (body: SdkErrorBody) => Error;\n unprocessable: (body: SdkErrorBody) => Error;\n serviceUnavailable: (body: SdkErrorBody) => Error;\n}\n\n/**\n * Build the Stripe-style body from any `PafiSdkError`. Exposed for\n * frameworks that don't fit the four-factory shape (e.g. a Hono error\n * handler that builds its own response object).\n */\nexport function buildSdkErrorBody(err: PafiSdkError): SdkErrorBody {\n const type =\n err.type ??\n defaultErrorTypeForStatus(SDK_ERROR_HTTP_STATUS_CODE[err.httpStatus]);\n const body: SdkErrorBody = {\n type,\n code: err.code,\n message: err.message,\n safeToRetry: err.safeToRetry,\n };\n if (err.param) body.param = err.param;\n if (err.metadata) body.metadata = err.metadata;\n if (err.details !== undefined) body.details = err.details;\n return body;\n}\n\n/**\n * Build a single error-mapping function that converts any `PafiSdkError`\n * into the issuer's framework-specific HTTP exception. Status, code,\n * `safeToRetry`, and `details` come straight off the error class —\n * the mapper is a dumb funnel, no per-error business logic.\n *\n * Any non-`PafiSdkError` is re-thrown unchanged so unexpected runtime\n * errors propagate to the framework's default 500 handler.\n *\n * Usage (NestJS):\n *\n * ```ts\n * const mapSdkError = createSdkErrorMapper({\n * notFound: (body) => new NotFoundException(body),\n * forbidden: (body) => new ForbiddenException(body),\n * unprocessable: (body) => new UnprocessableEntityException(body),\n * serviceUnavailable: (body) => new ServiceUnavailableException(body),\n * });\n *\n * try { ... } catch (err) { mapSdkError(err); }\n * ```\n *\n * Returns `never` so call sites in `try/catch` propagate the throw\n * without a redundant `throw` keyword.\n */\nexport function createSdkErrorMapper(\n factories: SdkErrorMapperFactories,\n): (err: unknown) => never {\n return (err: unknown): never => {\n if (!(err instanceof PafiSdkError)) {\n throw err;\n }\n const body = buildSdkErrorBody(err);\n switch (err.httpStatus) {\n case \"not_found\":\n throw factories.notFound(body);\n case \"forbidden\":\n throw factories.forbidden(body);\n case \"unprocessable\":\n throw factories.unprocessable(body);\n case \"service_unavailable\":\n throw factories.serviceUnavailable(body);\n }\n };\n}\n","/**\n * Stripe-style HTTP error envelope shared by every PAFI service and\n * issuer backend. The framework-agnostic `normalizeErrorToEnvelope`\n * helper produces this from any thrown value; framework-specific\n * filters (`@pafi-dev/issuer/nestjs`) call into it and write the\n * result to their response object.\n *\n * Wire format:\n *\n * ```json\n * {\n * \"success\": false,\n * \"statusCode\": 422,\n * \"error\": {\n * \"type\": \"business_logic_error\",\n * \"code\": \"REDEMPTION_POLICY_DENIED\",\n * \"message\": \"redemption denied: amount 1 below per-tx minimum\",\n * \"param\": null,\n * \"metadata\": { \"policyDenialCode\": \"PER_TX_MIN\" },\n * \"safeToRetry\": false,\n * \"details\": null\n * },\n * \"meta\": {\n * \"timestamp\": \"2026-05-07T...\",\n * \"requestId\": \"...\",\n * \"path\": \"/pt/redeem\"\n * }\n * }\n * ```\n */\n\nimport {\n PafiSdkError,\n SDK_ERROR_HTTP_STATUS_CODE,\n defaultErrorTypeForStatus,\n type PafiErrorType,\n} from \"../errors\";\nimport { buildSdkErrorBody, type SdkErrorBody } from \"../api/errorMapper\";\n\n/** Inner `error` block of the envelope. */\nexport interface PafiErrorPayload {\n type: PafiErrorType;\n code: string;\n message: string;\n param?: string;\n metadata?: Record<string, unknown>;\n details?: unknown;\n safeToRetry: boolean;\n}\n\n/** Outer envelope returned for any non-2xx response. */\nexport interface PafiErrorEnvelope {\n success: false;\n statusCode: number;\n error: PafiErrorPayload;\n meta: {\n timestamp: string;\n requestId: string;\n path: string;\n };\n}\n\n/** Per-call request context the filter must collect from the host framework. */\nexport interface NormalizeContext {\n /** `req.url` or equivalent. */\n path: string;\n /** Resolved request id (header or generated). */\n requestId: string;\n /** Optional `now()` injection for deterministic tests. */\n now?: () => Date;\n}\n\n/**\n * Generic error duck-type. The filter passes a small descriptor for\n * any framework exception so the normalizer doesn't depend on\n * `@nestjs/common` or any specific HTTP library.\n */\nexport interface GenericHttpExceptionDescriptor {\n /** HTTP status code carried by the exception. */\n statusCode: number;\n /**\n * The body the framework would have serialized. For NestJS this is\n * `exception.getResponse()`. May be a string or a record with\n * `code`/`error`/`message`/`details`/`safeToRetry`/`type`/etc.\n */\n responseBody: unknown;\n /** Exception class name, used as a last-resort `code` fallback. */\n exceptionName: string;\n /** Original `error.message`, used as a last-resort `message` fallback. */\n fallbackMessage: string;\n}\n\n/** True when `value` looks like a NestJS `BadRequestException` from `ValidationPipe`. */\nfunction isValidationPipeBody(\n body: Record<string, unknown>,\n): body is { message: string[]; error?: string; statusCode?: number } {\n return (\n Array.isArray(body[\"message\"]) &&\n typeof body[\"error\"] === \"string\" &&\n body[\"error\"] === \"Bad Request\"\n );\n}\n\n/** Pull `param` out of a `class-validator` message like `\"amount must be a number string\"`. */\nfunction extractParamFromValidatorMessage(message: string): string | undefined {\n const idx = message.indexOf(\" \");\n if (idx <= 0) return undefined;\n const candidate = message.slice(0, idx);\n return /^[A-Za-z_][\\w.]*$/.test(candidate) ? candidate : undefined;\n}\n\nfunction normalizeValidationPipeBody(\n body: { message: string[]; statusCode?: number },\n): PafiErrorPayload {\n const fields: Record<string, string[]> = {};\n for (const msg of body.message) {\n const param = extractParamFromValidatorMessage(msg);\n const key = param ?? \"_\";\n (fields[key] ??= []).push(msg);\n }\n const fieldKeys = Object.keys(fields).filter((k) => k !== \"_\");\n const param = fieldKeys.length === 1 ? fieldKeys[0] : undefined;\n\n const payload: PafiErrorPayload = {\n type: \"validation_error\",\n code: \"VALIDATION_FAILED\",\n message: body.message.join(\"; \"),\n safeToRetry: false,\n metadata: { fieldErrors: fields },\n };\n if (param) payload.param = param;\n return payload;\n}\n\n/**\n * Pull a Stripe-style payload out of a structured exception body. The\n * filter has already determined this is an `HttpException` (or\n * duck-typed equivalent). Order:\n *\n * 1. SDK-shaped body (has `type` + `code`) — pass through verbatim.\n * 2. `ValidationPipe` body (`message: string[]`, `error: \"Bad Request\"`)\n * — collapse into `validation_error` with `metadata.fieldErrors`.\n * 3. Plain object with `code` or `error` — best-effort extract.\n * 4. String body — just a message.\n */\nfunction normalizeHttpExceptionBody(\n desc: GenericHttpExceptionDescriptor,\n): PafiErrorPayload {\n const { statusCode, responseBody, exceptionName, fallbackMessage } = desc;\n const defaultType = defaultErrorTypeForStatus(statusCode);\n\n if (typeof responseBody === \"string\") {\n return {\n type: defaultType,\n code: exceptionName,\n message: responseBody,\n safeToRetry: false,\n };\n }\n\n if (responseBody && typeof responseBody === \"object\") {\n const body = responseBody as Record<string, unknown>;\n\n if (isValidationPipeBody(body)) {\n return normalizeValidationPipeBody(body);\n }\n\n const code =\n (typeof body[\"code\"] === \"string\" && body[\"code\"]) ||\n (typeof body[\"error\"] === \"string\" && body[\"error\"]) ||\n exceptionName;\n const message =\n (typeof body[\"message\"] === \"string\" && body[\"message\"]) ||\n (Array.isArray(body[\"message\"])\n ? (body[\"message\"] as string[]).join(\"; \")\n : \"\") ||\n fallbackMessage;\n const type =\n (typeof body[\"type\"] === \"string\" && (body[\"type\"] as PafiErrorType)) ||\n defaultType;\n const safeToRetry =\n typeof body[\"safeToRetry\"] === \"boolean\" ? body[\"safeToRetry\"] : false;\n\n const payload: PafiErrorPayload = {\n type,\n code,\n message,\n safeToRetry,\n };\n if (typeof body[\"param\"] === \"string\") payload.param = body[\"param\"];\n if (body[\"metadata\"] && typeof body[\"metadata\"] === \"object\") {\n payload.metadata = body[\"metadata\"] as Record<string, unknown>;\n }\n if (body[\"details\"] !== undefined) payload.details = body[\"details\"];\n return payload;\n }\n\n return {\n type: defaultType,\n code: exceptionName || \"INTERNAL_SERVER_ERROR\",\n message: fallbackMessage || \"An unexpected error occurred\",\n safeToRetry: false,\n };\n}\n\n/**\n * Convert a `PafiSdkError` directly to the inner `error` payload —\n * skipping any framework exception wrapper. Used by frameworks that\n * surface SDK errors without going through `createSdkErrorMapper`.\n */\nexport function payloadFromPafiSdkError(err: PafiSdkError): PafiErrorPayload {\n const body: SdkErrorBody = buildSdkErrorBody(err);\n const payload: PafiErrorPayload = {\n type: body.type,\n code: body.code,\n message: body.message,\n safeToRetry: body.safeToRetry,\n };\n if (body.param) payload.param = body.param;\n if (body.metadata) payload.metadata = body.metadata;\n if (body.details !== undefined) payload.details = body.details;\n return payload;\n}\n\n/** Strip SQL fragments from raw DB driver errors before exposing them. */\nfunction sanitizeDbErrorMessage(message: string): string {\n if (/^[A-Z_]+: /.test(message) && message.length < 256) return message;\n return \"Internal database error\";\n}\n\n/**\n * Build the full envelope for any thrown value. The caller resolves\n * `HttpException`-shaped exceptions and passes a descriptor; plain\n * `Error` instances and unknown throws are handled directly.\n */\nexport function buildErrorEnvelope(input: {\n status: number;\n payload: PafiErrorPayload;\n ctx: NormalizeContext;\n}): PafiErrorEnvelope {\n const now = (input.ctx.now ?? (() => new Date()))();\n return {\n success: false,\n statusCode: input.status,\n error: input.payload,\n meta: {\n timestamp: now.toISOString(),\n requestId: input.ctx.requestId,\n path: input.ctx.path,\n },\n };\n}\n\n/**\n * Normalize a known `HttpException`-shaped exception into a payload.\n * Framework filters supply the descriptor; the rest is shape-agnostic.\n */\nexport function payloadFromHttpException(\n desc: GenericHttpExceptionDescriptor,\n): PafiErrorPayload {\n return normalizeHttpExceptionBody(desc);\n}\n\n/**\n * Normalize a generic `Error` (not an HttpException) — TypeORM\n * `QueryFailedError`, viem revert errors, etc. Returns a redacted\n * 500-class payload with no message bleed-through unless the error\n * is recognizably benign.\n */\nexport function payloadFromGenericError(err: Error): PafiErrorPayload {\n const name = err.name || \"INTERNAL_SERVER_ERROR\";\n const isDbError = name === \"QueryFailedError\" || name === \"EntityNotFoundError\";\n return {\n type: \"server_error\",\n code: name,\n message: isDbError\n ? sanitizeDbErrorMessage(err.message)\n : err.message || \"An unexpected error occurred\",\n safeToRetry: false,\n };\n}\n","import {\n Module,\n type DynamicModule,\n type FactoryProvider,\n} from \"@nestjs/common\";\nimport type { IssuerPublicJwk } from \"../wallet-auth/types\";\nimport { WalletAuthJwksController } from \"./walletAuthJwks.controller\";\nimport { WALLET_AUTH_JWKS_KEYS } from \"./walletAuthJwks.tokens\";\n\nexport interface WalletAuthJwksOptions {\n /**\n * One or more public JWKs to publish. During key rotation, include\n * BOTH the active and previous keys so JWTs signed with the older\n * kid can still be verified by the PAFI gateway until the rotation\n * window closes.\n */\n keys: IssuerPublicJwk[];\n}\n\nexport interface WalletAuthJwksAsyncOptions {\n /** Modules to import for the factory's DI. */\n imports?: NonNullable<DynamicModule[\"imports\"]>;\n /** Providers to inject into useFactory — same shape as FactoryProvider.inject. */\n inject?: FactoryProvider[\"inject\"];\n /** Builds options at runtime — read env, decrypt secrets, etc. */\n useFactory: (...args: any[]) => Promise<WalletAuthJwksOptions> | WalletAuthJwksOptions;\n}\n\n/**\n * Drop-in NestJS module that publishes the issuer's public signing\n * key set at GET /.well-known/jwks.json.\n *\n * Every issuer backend integrating with the PAFI Wallet Auth Gateway\n * needs this endpoint so the gateway can fetch their public key and\n * verify issuer JWT signatures.\n *\n * @example Sync registration\n * import { WalletAuthJwksModule } from '@pafi-dev/issuer/nestjs';\n *\n * @Module({\n * imports: [\n * WalletAuthJwksModule.forRoot({\n * keys: [JSON.parse(process.env.ISSUER_PUBLIC_JWK_JSON!)],\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * @example Async registration (read from ConfigService)\n * import { ConfigModule, ConfigService } from '@nestjs/config';\n * import { WalletAuthJwksModule } from '@pafi-dev/issuer/nestjs';\n *\n * @Module({\n * imports: [\n * WalletAuthJwksModule.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (config: ConfigService) => ({\n * keys: [JSON.parse(config.getOrThrow('ISSUER_PUBLIC_JWK_JSON'))],\n * }),\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * @example Rotation window — publish 2 keys simultaneously\n * keys: [\n * JSON.parse(process.env.ISSUER_PUBLIC_JWK_JSON_ACTIVE!),\n * JSON.parse(process.env.ISSUER_PUBLIC_JWK_JSON_PREVIOUS!),\n * ]\n */\n@Module({})\nexport class WalletAuthJwksModule {\n static forRoot(options: WalletAuthJwksOptions): DynamicModule {\n return {\n module: WalletAuthJwksModule,\n controllers: [WalletAuthJwksController],\n providers: [\n {\n provide: WALLET_AUTH_JWKS_KEYS,\n useValue: validateKeys(options.keys),\n },\n ],\n };\n }\n\n static forRootAsync(options: WalletAuthJwksAsyncOptions): DynamicModule {\n return {\n module: WalletAuthJwksModule,\n imports: options.imports ?? [],\n controllers: [WalletAuthJwksController],\n providers: [\n {\n provide: WALLET_AUTH_JWKS_KEYS,\n inject: options.inject ?? [],\n useFactory: async (...args: unknown[]) => {\n const opts = await options.useFactory(...args);\n return validateKeys(opts.keys);\n },\n },\n ],\n };\n }\n}\n\n/**\n * Reject misconfiguration loudly at boot rather than serving an\n * invalid JWKS. Missing `kid` would mean the gateway can't match\n * the key against inbound JWT headers.\n */\nfunction validateKeys(keys: IssuerPublicJwk[]): IssuerPublicJwk[] {\n if (!Array.isArray(keys)) {\n throw new Error(\"WalletAuthJwksModule: `keys` must be an array\");\n }\n for (const k of keys) {\n if (!k || typeof k !== \"object\") {\n throw new Error(\"WalletAuthJwksModule: each key must be an object\");\n }\n if (!k.kty) {\n throw new Error(\"WalletAuthJwksModule: each key must have a `kty` field\");\n }\n if (!k.kid) {\n throw new Error(\n \"WalletAuthJwksModule: each key must have a `kid` field — PAFI gateway uses kid to look up the verification key\",\n );\n }\n }\n return keys;\n}\n","import {\n Controller,\n Get,\n HttpCode,\n HttpStatus,\n Inject,\n Logger,\n} from \"@nestjs/common\";\nimport type { IssuerPublicJwk } from \"../wallet-auth/types\";\nimport { WALLET_AUTH_JWKS_KEYS } from \"./walletAuthJwks.tokens\";\n\n/**\n * Publishes the issuer's public signing key set as RFC 7517 JWKS.\n *\n * The PAFI Wallet Auth Gateway fetches this URL to verify signatures\n * on issuer JWTs that this backend mints (the JWT travelling in\n * /v1/token-exchange's `issuer_jwt` body field).\n *\n * Mounted at GET /.well-known/jwks.json — no auth, public by design.\n */\n@Controller(\".well-known\")\nexport class WalletAuthJwksController {\n private readonly logger = new Logger(WalletAuthJwksController.name);\n private readonly jwks: { keys: IssuerPublicJwk[] };\n\n constructor(\n @Inject(WALLET_AUTH_JWKS_KEYS)\n keys: IssuerPublicJwk[],\n ) {\n this.jwks = { keys };\n const kids = keys.map((k) => k.kid).join(\", \");\n this.logger.log(\n `JWKS endpoint ready — ${keys.length} key(s) published: ${kids || \"(empty)\"}`,\n );\n }\n\n @Get(\"jwks.json\")\n @HttpCode(HttpStatus.OK)\n getJwks(): { keys: IssuerPublicJwk[] } {\n return this.jwks;\n }\n}\n","/** DI token: array of public JWKs to publish at /.well-known/jwks.json. */\nexport const WALLET_AUTH_JWKS_KEYS = Symbol(\"WALLET_AUTH_JWKS_KEYS\");\n"],"mappings":"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","names":["import_core","param","import_common","import_common"]}
1
+ {"version":3,"sources":["../../src/nestjs/index.ts","../../src/nestjs/httpExceptionFilter.ts","../../src/errors.ts","../../src/api/errorMapper.ts","../../src/http/errorEnvelope.ts","../../src/nestjs/walletAuthJwks.module.ts","../../src/nestjs/walletAuthJwks.controller.ts","../../src/nestjs/walletAuthJwks.tokens.ts"],"sourcesContent":["export {\n PafiHttpExceptionFilter,\n type PafiHttpExceptionFilterOptions,\n} from \"./httpExceptionFilter\";\n\nexport {\n WalletAuthJwksModule,\n type WalletAuthJwksOptions,\n type WalletAuthJwksAsyncOptions,\n} from \"./walletAuthJwks.module\";\nexport { WalletAuthJwksController } from \"./walletAuthJwks.controller\";\nexport { WALLET_AUTH_JWKS_KEYS } from \"./walletAuthJwks.tokens\";\n","/**\n * NestJS global exception filter that emits the PAFI Stripe-style\n * envelope (see `@pafi-dev/issuer/http`).\n *\n * Wire it once in your bootstrap:\n *\n * ```ts\n * import { PafiHttpExceptionFilter } from \"@pafi-dev/issuer/nestjs\";\n *\n * app.useGlobalFilters(new PafiHttpExceptionFilter());\n * ```\n *\n * Catches every thrown value:\n * - `PafiSdkError` (and subclasses) → typed envelope from `httpStatus`/\n * `code`/`type`/`safeToRetry`/`param`/`metadata`.\n * - `HttpException` (NestJS) → respected status; SDK-shaped body is\n * passed through, plain bodies + ValidationPipe arrays normalized.\n * - any other `Error` → `server_error` 500 with sanitized message.\n *\n * `@nestjs/common` is an optional peer dependency — only required when\n * importing this sub-export.\n */\nimport {\n ArgumentsHost,\n Catch,\n ExceptionFilter,\n HttpException,\n HttpStatus,\n Logger,\n} from \"@nestjs/common\";\nimport { randomUUID } from \"node:crypto\";\n\nimport { PafiSdkError, SDK_ERROR_HTTP_STATUS_CODE } from \"../errors\";\nimport {\n buildErrorEnvelope,\n payloadFromGenericError,\n payloadFromHttpException,\n payloadFromPafiSdkError,\n type NormalizeContext,\n type PafiErrorEnvelope,\n type PafiErrorPayload,\n} from \"../http/errorEnvelope\";\n\ninterface MinimalHttpRequest {\n url?: string;\n headers?: Record<string, string | string[] | undefined>;\n}\ninterface MinimalHttpResponse {\n status(code: number): MinimalHttpResponse;\n json(body: unknown): unknown;\n}\n\n/** Customization knobs. None required — sensible defaults baked in. */\nexport interface PafiHttpExceptionFilterOptions {\n /**\n * Header to read for the request id, lowercase. Default `\"x-request-id\"`.\n * If absent, a UUIDv4 is generated per request.\n */\n requestIdHeader?: string;\n /**\n * Override `Date` for deterministic tests.\n */\n now?: () => Date;\n /**\n * Hook to record normalized errors before sending. Useful for\n * Sentry / Datadog / Pino. Throws are swallowed so a logging bug\n * never masks the real error response.\n */\n onError?: (envelope: PafiErrorEnvelope, raw: unknown) => void;\n}\n\n@Catch()\nexport class PafiHttpExceptionFilter implements ExceptionFilter {\n private readonly logger = new Logger(\"PafiHttpExceptionFilter\");\n private readonly opts: Required<\n Pick<PafiHttpExceptionFilterOptions, \"requestIdHeader\">\n > &\n PafiHttpExceptionFilterOptions;\n\n constructor(options: PafiHttpExceptionFilterOptions = {}) {\n this.opts = {\n requestIdHeader: options.requestIdHeader ?? \"x-request-id\",\n ...options,\n };\n }\n\n catch(exception: unknown, host: ArgumentsHost): void {\n const ctx = host.switchToHttp();\n const response = ctx.getResponse<MinimalHttpResponse>();\n const request = ctx.getRequest<MinimalHttpRequest>();\n\n const headerValue = request?.headers?.[this.opts.requestIdHeader];\n const requestId =\n (Array.isArray(headerValue) ? headerValue[0] : headerValue) ??\n randomUUID();\n\n const normCtx: NormalizeContext = {\n path: request?.url ?? \"\",\n requestId,\n ...(this.opts.now ? { now: this.opts.now } : {}),\n };\n\n const { status, payload } = this.normalize(exception);\n const envelope = buildErrorEnvelope({ status, payload, ctx: normCtx });\n\n if (this.opts.onError) {\n try {\n this.opts.onError(envelope, exception);\n } catch (hookErr) {\n this.logger.warn(\n { err: hookErr instanceof Error ? hookErr.message : String(hookErr) },\n \"onError hook threw; continuing\",\n );\n }\n }\n\n if (status >= 500) {\n this.logger.error(\n {\n err:\n exception instanceof Error\n ? exception.message\n : String(exception),\n stack: exception instanceof Error ? exception.stack : undefined,\n name: exception instanceof Error ? exception.name : undefined,\n path: normCtx.path,\n requestId,\n },\n \"Unhandled error in PafiHttpExceptionFilter\",\n );\n }\n\n response.status(status).json(envelope);\n }\n\n private normalize(exception: unknown): {\n status: number;\n payload: PafiErrorPayload;\n } {\n if (exception instanceof PafiSdkError) {\n return {\n status: SDK_ERROR_HTTP_STATUS_CODE[exception.httpStatus],\n payload: payloadFromPafiSdkError(exception),\n };\n }\n\n if (exception instanceof HttpException) {\n return {\n status: exception.getStatus(),\n payload: payloadFromHttpException({\n statusCode: exception.getStatus(),\n responseBody: exception.getResponse(),\n exceptionName: exception.name,\n fallbackMessage: exception.message,\n }),\n };\n }\n\n if (exception instanceof Error) {\n // Duck-typing for HttpException instances that fail `instanceof`\n // when multiple `@nestjs/common` copies exist in the dep tree.\n const maybeStatus = (exception as { status?: unknown }).status;\n const maybeGetResponse = (\n exception as { getResponse?: () => unknown }\n ).getResponse;\n if (\n typeof maybeStatus === \"number\" &&\n typeof maybeGetResponse === \"function\"\n ) {\n return {\n status: maybeStatus,\n payload: payloadFromHttpException({\n statusCode: maybeStatus,\n responseBody: maybeGetResponse.call(exception),\n exceptionName: exception.name,\n fallbackMessage: exception.message,\n }),\n };\n }\n const maybeStatusOnly =\n typeof maybeStatus === \"number\"\n ? maybeStatus\n : HttpStatus.INTERNAL_SERVER_ERROR;\n return {\n status: maybeStatusOnly,\n payload: payloadFromGenericError(exception),\n };\n }\n\n return {\n status: HttpStatus.INTERNAL_SERVER_ERROR,\n payload: {\n type: \"server_error\",\n code: \"INTERNAL_SERVER_ERROR\",\n message: \"An unexpected error occurred\",\n safeToRetry: false,\n },\n };\n }\n}\n","/**\n * `PafiSdkError` + `SdkErrorHttpStatus` are exported from\n * `@pafi-dev/core/errors` so core-level errors (e.g. `OracleStaleError`)\n * can extend the same base. Issuer re-exports the canonical types here\n * for back-compat — `instanceof PafiSdkError` from EITHER package\n * catches errors thrown from EITHER package.\n */\nexport {\n PafiSdkError,\n SDK_ERROR_HTTP_STATUS_CODE,\n defaultErrorTypeForStatus,\n type SdkErrorHttpStatus,\n type PafiErrorType,\n} from \"@pafi-dev/core\";\nimport { PafiSdkError } from \"@pafi-dev/core\";\n\n/**\n * `ValidationError` lives in `@pafi-dev/core` so core/trading helpers\n * throw the same typed class. Re-exported here for back-compat.\n */\nexport { ValidationError } from \"@pafi-dev/core\";\n\n/**\n * Issuer wired the SDK without a dependency the requested endpoint\n * needs (e.g. `/gas-fee` called but `feeManager` not configured;\n * `/pools` called but `poolsProvider` not configured). 503 because\n * the endpoint genuinely can't serve the request — caller's payload\n * is fine, the issuer's deployment is incomplete.\n */\nexport class ConfigurationError extends PafiSdkError {\n readonly httpStatus = \"service_unavailable\" as const;\n readonly code: string;\n readonly details?: Record<string, unknown>;\n\n constructor(\n code: string,\n message: string,\n details?: Record<string, unknown>,\n ) {\n super(message);\n this.code = code;\n this.details = details;\n }\n}\n","import {\n PafiSdkError,\n SDK_ERROR_HTTP_STATUS_CODE,\n defaultErrorTypeForStatus,\n type PafiErrorType,\n type SdkErrorHttpStatus,\n} from \"../errors\";\n\n/**\n * Normalized HTTP status the issuer controller should surface for a\n * given SDK error. Mirrors `SdkErrorHttpStatus` on `PafiSdkError`.\n */\nexport type SdkErrorStatus = SdkErrorHttpStatus;\n\n/**\n * Structured body the issuer controller passes to its\n * framework-specific exception class. Stripe-style envelope:\n *\n * ```json\n * {\n * \"type\": \"business_logic_error\",\n * \"code\": \"REDEMPTION_POLICY_DENIED\",\n * \"message\": \"...\",\n * \"param\": null,\n * \"metadata\": { \"policyDenialCode\": \"PER_TX_MIN\" },\n * \"safeToRetry\": false\n * }\n * ```\n *\n * Carries enough fields for the global HTTP filter to emit the final\n * envelope without losing any SDK-side context.\n */\nexport interface SdkErrorBody {\n /** Stripe-style taxonomy slot — drives UI branching. */\n type: PafiErrorType;\n /** Machine-readable code, e.g. `\"REDEMPTION_POLICY_DENIED\"`. */\n code: string;\n /** Human-readable message. */\n message: string;\n /** Field name that triggered the error, when applicable. */\n param?: string;\n /** UI-facing structured context. */\n metadata?: Record<string, unknown>;\n /** Raw debug context. */\n details?: unknown;\n /** True when retry is safe (no side effects yet). */\n safeToRetry: boolean;\n}\n\n/**\n * Per-status exception factories. The issuer's controller wires one\n * factory per status to its preferred framework's exception class\n * (NestJS `UnprocessableEntityException`, Fastify `httpErrors.badData`,\n * etc). The factory must return an Error — `createSdkErrorMapper`\n * uses `throw factory(body)`.\n */\nexport interface SdkErrorMapperFactories {\n notFound: (body: SdkErrorBody) => Error;\n forbidden: (body: SdkErrorBody) => Error;\n unprocessable: (body: SdkErrorBody) => Error;\n serviceUnavailable: (body: SdkErrorBody) => Error;\n}\n\n/**\n * Build the Stripe-style body from any `PafiSdkError`. Exposed for\n * frameworks that don't fit the four-factory shape (e.g. a Hono error\n * handler that builds its own response object).\n */\nexport function buildSdkErrorBody(err: PafiSdkError): SdkErrorBody {\n const type =\n err.type ??\n defaultErrorTypeForStatus(SDK_ERROR_HTTP_STATUS_CODE[err.httpStatus]);\n const body: SdkErrorBody = {\n type,\n code: err.code,\n message: err.message,\n safeToRetry: err.safeToRetry,\n };\n if (err.param) body.param = err.param;\n if (err.metadata) body.metadata = err.metadata;\n if (err.details !== undefined) body.details = err.details;\n return body;\n}\n\n/**\n * Build a single error-mapping function that converts any `PafiSdkError`\n * into the issuer's framework-specific HTTP exception. Status, code,\n * `safeToRetry`, and `details` come straight off the error class —\n * the mapper is a dumb funnel, no per-error business logic.\n *\n * Any non-`PafiSdkError` is re-thrown unchanged so unexpected runtime\n * errors propagate to the framework's default 500 handler.\n *\n * Usage (NestJS):\n *\n * ```ts\n * const mapSdkError = createSdkErrorMapper({\n * notFound: (body) => new NotFoundException(body),\n * forbidden: (body) => new ForbiddenException(body),\n * unprocessable: (body) => new UnprocessableEntityException(body),\n * serviceUnavailable: (body) => new ServiceUnavailableException(body),\n * });\n *\n * try { ... } catch (err) { mapSdkError(err); }\n * ```\n *\n * Returns `never` so call sites in `try/catch` propagate the throw\n * without a redundant `throw` keyword.\n */\nexport function createSdkErrorMapper(\n factories: SdkErrorMapperFactories,\n): (err: unknown) => never {\n return (err: unknown): never => {\n if (!(err instanceof PafiSdkError)) {\n throw err;\n }\n const body = buildSdkErrorBody(err);\n switch (err.httpStatus) {\n case \"not_found\":\n throw factories.notFound(body);\n case \"forbidden\":\n throw factories.forbidden(body);\n case \"unprocessable\":\n throw factories.unprocessable(body);\n case \"service_unavailable\":\n throw factories.serviceUnavailable(body);\n }\n };\n}\n","/**\n * Stripe-style HTTP error envelope shared by every PAFI service and\n * issuer backend. The framework-agnostic `normalizeErrorToEnvelope`\n * helper produces this from any thrown value; framework-specific\n * filters (`@pafi-dev/issuer/nestjs`) call into it and write the\n * result to their response object.\n *\n * Wire format:\n *\n * ```json\n * {\n * \"success\": false,\n * \"statusCode\": 422,\n * \"error\": {\n * \"type\": \"business_logic_error\",\n * \"code\": \"REDEMPTION_POLICY_DENIED\",\n * \"message\": \"redemption denied: amount 1 below per-tx minimum\",\n * \"param\": null,\n * \"metadata\": { \"policyDenialCode\": \"PER_TX_MIN\" },\n * \"safeToRetry\": false,\n * \"details\": null\n * },\n * \"meta\": {\n * \"timestamp\": \"2026-05-07T...\",\n * \"requestId\": \"...\",\n * \"path\": \"/pt/redeem\"\n * }\n * }\n * ```\n */\n\nimport {\n PafiSdkError,\n SDK_ERROR_HTTP_STATUS_CODE,\n defaultErrorTypeForStatus,\n type PafiErrorType,\n} from \"../errors\";\nimport { buildSdkErrorBody, type SdkErrorBody } from \"../api/errorMapper\";\n\n/** Inner `error` block of the envelope. */\nexport interface PafiErrorPayload {\n type: PafiErrorType;\n code: string;\n message: string;\n param?: string;\n metadata?: Record<string, unknown>;\n details?: unknown;\n safeToRetry: boolean;\n}\n\n/** Outer envelope returned for any non-2xx response. */\nexport interface PafiErrorEnvelope {\n success: false;\n statusCode: number;\n error: PafiErrorPayload;\n meta: {\n timestamp: string;\n requestId: string;\n path: string;\n };\n}\n\n/** Per-call request context the filter must collect from the host framework. */\nexport interface NormalizeContext {\n /** `req.url` or equivalent. */\n path: string;\n /** Resolved request id (header or generated). */\n requestId: string;\n /** Optional `now()` injection for deterministic tests. */\n now?: () => Date;\n}\n\n/**\n * Generic error duck-type. The filter passes a small descriptor for\n * any framework exception so the normalizer doesn't depend on\n * `@nestjs/common` or any specific HTTP library.\n */\nexport interface GenericHttpExceptionDescriptor {\n /** HTTP status code carried by the exception. */\n statusCode: number;\n /**\n * The body the framework would have serialized. For NestJS this is\n * `exception.getResponse()`. May be a string or a record with\n * `code`/`error`/`message`/`details`/`safeToRetry`/`type`/etc.\n */\n responseBody: unknown;\n /** Exception class name, used as a last-resort `code` fallback. */\n exceptionName: string;\n /** Original `error.message`, used as a last-resort `message` fallback. */\n fallbackMessage: string;\n}\n\n/** True when `value` looks like a NestJS `BadRequestException` from `ValidationPipe`. */\nfunction isValidationPipeBody(\n body: Record<string, unknown>,\n): body is { message: string[]; error?: string; statusCode?: number } {\n return (\n Array.isArray(body[\"message\"]) &&\n typeof body[\"error\"] === \"string\" &&\n body[\"error\"] === \"Bad Request\"\n );\n}\n\n/** Pull `param` out of a `class-validator` message like `\"amount must be a number string\"`. */\nfunction extractParamFromValidatorMessage(message: string): string | undefined {\n const idx = message.indexOf(\" \");\n if (idx <= 0) return undefined;\n const candidate = message.slice(0, idx);\n return /^[A-Za-z_][\\w.]*$/.test(candidate) ? candidate : undefined;\n}\n\nfunction normalizeValidationPipeBody(\n body: { message: string[]; statusCode?: number },\n): PafiErrorPayload {\n const fields: Record<string, string[]> = {};\n for (const msg of body.message) {\n const param = extractParamFromValidatorMessage(msg);\n const key = param ?? \"_\";\n (fields[key] ??= []).push(msg);\n }\n const fieldKeys = Object.keys(fields).filter((k) => k !== \"_\");\n const param = fieldKeys.length === 1 ? fieldKeys[0] : undefined;\n\n const payload: PafiErrorPayload = {\n type: \"validation_error\",\n code: \"VALIDATION_FAILED\",\n message: body.message.join(\"; \"),\n safeToRetry: false,\n metadata: { fieldErrors: fields },\n };\n if (param) payload.param = param;\n return payload;\n}\n\n/**\n * Pull a Stripe-style payload out of a structured exception body. The\n * filter has already determined this is an `HttpException` (or\n * duck-typed equivalent). Order:\n *\n * 1. SDK-shaped body (has `type` + `code`) — pass through verbatim.\n * 2. `ValidationPipe` body (`message: string[]`, `error: \"Bad Request\"`)\n * — collapse into `validation_error` with `metadata.fieldErrors`.\n * 3. Plain object with `code` or `error` — best-effort extract.\n * 4. String body — just a message.\n */\nfunction normalizeHttpExceptionBody(\n desc: GenericHttpExceptionDescriptor,\n): PafiErrorPayload {\n const { statusCode, responseBody, exceptionName, fallbackMessage } = desc;\n const defaultType = defaultErrorTypeForStatus(statusCode);\n\n if (typeof responseBody === \"string\") {\n return {\n type: defaultType,\n code: exceptionName,\n message: responseBody,\n safeToRetry: false,\n };\n }\n\n if (responseBody && typeof responseBody === \"object\") {\n const body = responseBody as Record<string, unknown>;\n\n if (isValidationPipeBody(body)) {\n return normalizeValidationPipeBody(body);\n }\n\n const code =\n (typeof body[\"code\"] === \"string\" && body[\"code\"]) ||\n (typeof body[\"error\"] === \"string\" && body[\"error\"]) ||\n exceptionName;\n const message =\n (typeof body[\"message\"] === \"string\" && body[\"message\"]) ||\n (Array.isArray(body[\"message\"])\n ? (body[\"message\"] as string[]).join(\"; \")\n : \"\") ||\n fallbackMessage;\n const type =\n (typeof body[\"type\"] === \"string\" && (body[\"type\"] as PafiErrorType)) ||\n defaultType;\n const safeToRetry =\n typeof body[\"safeToRetry\"] === \"boolean\" ? body[\"safeToRetry\"] : false;\n\n const payload: PafiErrorPayload = {\n type,\n code,\n message,\n safeToRetry,\n };\n if (typeof body[\"param\"] === \"string\") payload.param = body[\"param\"];\n if (body[\"metadata\"] && typeof body[\"metadata\"] === \"object\") {\n payload.metadata = body[\"metadata\"] as Record<string, unknown>;\n }\n if (body[\"details\"] !== undefined) payload.details = body[\"details\"];\n return payload;\n }\n\n return {\n type: defaultType,\n code: exceptionName || \"INTERNAL_SERVER_ERROR\",\n message: fallbackMessage || \"An unexpected error occurred\",\n safeToRetry: false,\n };\n}\n\n/**\n * Convert a `PafiSdkError` directly to the inner `error` payload —\n * skipping any framework exception wrapper. Used by frameworks that\n * surface SDK errors without going through `createSdkErrorMapper`.\n */\nexport function payloadFromPafiSdkError(err: PafiSdkError): PafiErrorPayload {\n const body: SdkErrorBody = buildSdkErrorBody(err);\n const payload: PafiErrorPayload = {\n type: body.type,\n code: body.code,\n message: body.message,\n safeToRetry: body.safeToRetry,\n };\n if (body.param) payload.param = body.param;\n if (body.metadata) payload.metadata = body.metadata;\n if (body.details !== undefined) payload.details = body.details;\n return payload;\n}\n\n/** Strip SQL fragments from raw DB driver errors before exposing them. */\nfunction sanitizeDbErrorMessage(message: string): string {\n if (/^[A-Z_]+: /.test(message) && message.length < 256) return message;\n return \"Internal database error\";\n}\n\n/**\n * Build the full envelope for any thrown value. The caller resolves\n * `HttpException`-shaped exceptions and passes a descriptor; plain\n * `Error` instances and unknown throws are handled directly.\n */\nexport function buildErrorEnvelope(input: {\n status: number;\n payload: PafiErrorPayload;\n ctx: NormalizeContext;\n}): PafiErrorEnvelope {\n const now = (input.ctx.now ?? (() => new Date()))();\n return {\n success: false,\n statusCode: input.status,\n error: input.payload,\n meta: {\n timestamp: now.toISOString(),\n requestId: input.ctx.requestId,\n path: input.ctx.path,\n },\n };\n}\n\n/**\n * Normalize a known `HttpException`-shaped exception into a payload.\n * Framework filters supply the descriptor; the rest is shape-agnostic.\n */\nexport function payloadFromHttpException(\n desc: GenericHttpExceptionDescriptor,\n): PafiErrorPayload {\n return normalizeHttpExceptionBody(desc);\n}\n\n/**\n * Normalize a generic `Error` (not an HttpException) — TypeORM\n * `QueryFailedError`, viem revert errors, etc. Returns a redacted\n * 500-class payload with no message bleed-through unless the error\n * is recognizably benign.\n */\nexport function payloadFromGenericError(err: Error): PafiErrorPayload {\n const name = err.name || \"INTERNAL_SERVER_ERROR\";\n const isDbError = name === \"QueryFailedError\" || name === \"EntityNotFoundError\";\n return {\n type: \"server_error\",\n code: name,\n message: isDbError\n ? sanitizeDbErrorMessage(err.message)\n : err.message || \"An unexpected error occurred\",\n safeToRetry: false,\n };\n}\n","import {\n Module,\n type DynamicModule,\n type FactoryProvider,\n} from \"@nestjs/common\";\nimport type { IssuerPublicJwk } from \"../wallet-auth/types\";\nimport { WalletAuthJwksController } from \"./walletAuthJwks.controller\";\nimport { WALLET_AUTH_JWKS_KEYS } from \"./walletAuthJwks.tokens\";\n\nexport interface WalletAuthJwksOptions {\n /**\n * One or more public JWKs to publish. During key rotation, include\n * BOTH the active and previous keys so JWTs signed with the older\n * kid can still be verified by the PAFI gateway until the rotation\n * window closes.\n */\n keys: IssuerPublicJwk[];\n}\n\nexport interface WalletAuthJwksAsyncOptions {\n /** Modules to import for the factory's DI. */\n imports?: NonNullable<DynamicModule[\"imports\"]>;\n /** Providers to inject into useFactory — same shape as FactoryProvider.inject. */\n inject?: FactoryProvider[\"inject\"];\n /** Builds options at runtime — read env, decrypt secrets, etc. */\n useFactory: (...args: any[]) => Promise<WalletAuthJwksOptions> | WalletAuthJwksOptions;\n}\n\n/**\n * Drop-in NestJS module that publishes the issuer's public signing\n * key set at GET /.well-known/jwks.json.\n *\n * Every issuer backend integrating with the PAFI Wallet Auth Gateway\n * needs this endpoint so the gateway can fetch their public key and\n * verify issuer JWT signatures.\n *\n * @example Sync registration\n * import { WalletAuthJwksModule } from '@pafi-dev/issuer/nestjs';\n *\n * @Module({\n * imports: [\n * WalletAuthJwksModule.forRoot({\n * keys: [JSON.parse(process.env.ISSUER_PUBLIC_JWK_JSON!)],\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * @example Async registration (read from ConfigService)\n * import { ConfigModule, ConfigService } from '@nestjs/config';\n * import { WalletAuthJwksModule } from '@pafi-dev/issuer/nestjs';\n *\n * @Module({\n * imports: [\n * WalletAuthJwksModule.forRootAsync({\n * imports: [ConfigModule],\n * inject: [ConfigService],\n * useFactory: (config: ConfigService) => ({\n * keys: [JSON.parse(config.getOrThrow('ISSUER_PUBLIC_JWK_JSON'))],\n * }),\n * }),\n * ],\n * })\n * export class AppModule {}\n *\n * @example Rotation window — publish 2 keys simultaneously\n * keys: [\n * JSON.parse(process.env.ISSUER_PUBLIC_JWK_JSON_ACTIVE!),\n * JSON.parse(process.env.ISSUER_PUBLIC_JWK_JSON_PREVIOUS!),\n * ]\n */\n@Module({})\nexport class WalletAuthJwksModule {\n static forRoot(options: WalletAuthJwksOptions): DynamicModule {\n return {\n module: WalletAuthJwksModule,\n controllers: [WalletAuthJwksController],\n providers: [\n {\n provide: WALLET_AUTH_JWKS_KEYS,\n useValue: validateKeys(options.keys),\n },\n ],\n };\n }\n\n static forRootAsync(options: WalletAuthJwksAsyncOptions): DynamicModule {\n return {\n module: WalletAuthJwksModule,\n imports: options.imports ?? [],\n controllers: [WalletAuthJwksController],\n providers: [\n {\n provide: WALLET_AUTH_JWKS_KEYS,\n inject: options.inject ?? [],\n useFactory: async (...args: unknown[]) => {\n const opts = await options.useFactory(...args);\n return validateKeys(opts.keys);\n },\n },\n ],\n };\n }\n}\n\n/**\n * Reject misconfiguration loudly at boot rather than serving an\n * invalid JWKS. Missing `kid` would mean the gateway can't match\n * the key against inbound JWT headers.\n */\nfunction validateKeys(keys: IssuerPublicJwk[]): IssuerPublicJwk[] {\n if (!Array.isArray(keys)) {\n throw new Error(\"WalletAuthJwksModule: `keys` must be an array\");\n }\n for (const k of keys) {\n if (!k || typeof k !== \"object\") {\n throw new Error(\"WalletAuthJwksModule: each key must be an object\");\n }\n if (!k.kty) {\n throw new Error(\"WalletAuthJwksModule: each key must have a `kty` field\");\n }\n if (!k.kid) {\n throw new Error(\n \"WalletAuthJwksModule: each key must have a `kid` field — PAFI gateway uses kid to look up the verification key\",\n );\n }\n }\n return keys;\n}\n","import {\n Controller,\n Get,\n HttpCode,\n HttpStatus,\n Inject,\n Logger,\n} from \"@nestjs/common\";\nimport type { IssuerPublicJwk } from \"../wallet-auth/types\";\nimport { WALLET_AUTH_JWKS_KEYS } from \"./walletAuthJwks.tokens\";\n\n/**\n * Publishes the issuer's public signing key set as RFC 7517 JWKS.\n *\n * The PAFI Wallet Auth Gateway fetches this URL to verify signatures\n * on issuer JWTs that this backend mints (the JWT travelling in\n * /v1/token-exchange's `issuer_jwt` body field).\n *\n * Mounted at GET /.well-known/jwks.json — no auth, public by design.\n */\n@Controller(\".well-known\")\nexport class WalletAuthJwksController {\n private readonly logger = new Logger(WalletAuthJwksController.name);\n private readonly jwks: { keys: IssuerPublicJwk[] };\n\n constructor(\n @Inject(WALLET_AUTH_JWKS_KEYS)\n keys: IssuerPublicJwk[],\n ) {\n this.jwks = { keys };\n const kids = keys.map((k) => k.kid).join(\", \");\n this.logger.log(\n `JWKS endpoint ready — ${keys.length} key(s) published: ${kids || \"(empty)\"}`,\n );\n }\n\n @Get(\"jwks.json\")\n @HttpCode(HttpStatus.OK)\n getJwks(): { keys: IssuerPublicJwk[] } {\n return this.jwks;\n }\n}\n","/** DI token: array of public JWKs to publish at /.well-known/jwks.json. */\nexport const WALLET_AUTH_JWKS_KEYS = Symbol(\"WALLET_AUTH_JWKS_KEYS\");\n"],"mappings":"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","names":["import_core","buildSdkErrorBody","err","type","defaultErrorTypeForStatus","SDK_ERROR_HTTP_STATUS_CODE","httpStatus","body","code","message","safeToRetry","param","metadata","details","undefined","isValidationPipeBody","body","Array","isArray","extractParamFromValidatorMessage","message","idx","indexOf","undefined","candidate","slice","test","normalizeValidationPipeBody","fields","msg","param","key","push","fieldKeys","Object","keys","filter","k","length","payload","type","code","join","safeToRetry","metadata","fieldErrors","normalizeHttpExceptionBody","desc","statusCode","responseBody","exceptionName","fallbackMessage","defaultType","defaultErrorTypeForStatus","details","payloadFromPafiSdkError","err","buildSdkErrorBody","sanitizeDbErrorMessage","buildErrorEnvelope","input","now","ctx","Date","success","status","error","meta","timestamp","toISOString","requestId","path","payloadFromHttpException","payloadFromGenericError","name","isDbError","PafiHttpExceptionFilter","logger","Logger","opts","options","requestIdHeader","catch","exception","host","ctx","switchToHttp","response","getResponse","request","getRequest","headerValue","headers","requestId","Array","isArray","randomUUID","normCtx","path","url","now","status","payload","normalize","envelope","buildErrorEnvelope","onError","hookErr","warn","err","Error","message","String","error","stack","undefined","name","json","PafiSdkError","SDK_ERROR_HTTP_STATUS_CODE","httpStatus","payloadFromPafiSdkError","HttpException","getStatus","payloadFromHttpException","statusCode","responseBody","exceptionName","fallbackMessage","maybeStatus","maybeGetResponse","call","maybeStatusOnly","HttpStatus","INTERNAL_SERVER_ERROR","payloadFromGenericError","type","code","safeToRetry","import_common","import_common","WALLET_AUTH_JWKS_KEYS","Symbol","WalletAuthJwksController","logger","Logger","name","jwks","keys","kids","map","k","kid","join","log","length","getJwks","OK","WalletAuthJwksModule","forRoot","options","module","controllers","WalletAuthJwksController","providers","provide","WALLET_AUTH_JWKS_KEYS","useValue","validateKeys","keys","forRootAsync","imports","inject","useFactory","args","opts","Array","isArray","Error","k","kty","kid"]}