@pafi-dev/issuer 0.8.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-R4FYJZ2N.js +1 -0
- package/dist/chunk-R4FYJZ2N.js.map +1 -0
- package/dist/chunk-U3WMORJG.js +230 -0
- package/dist/chunk-U3WMORJG.js.map +1 -0
- package/dist/http/index.cjs +169 -0
- package/dist/http/index.cjs.map +1 -0
- package/dist/http/index.d.cts +112 -0
- package/dist/http/index.d.ts +112 -0
- package/dist/http/index.js +14 -0
- package/dist/http/index.js.map +1 -0
- package/dist/index.cjs +161 -26
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +35 -5
- package/dist/index.d.ts +35 -5
- package/dist/index.js +21 -41
- package/dist/index.js.map +1 -1
- package/dist/nestjs/index.cjs +314 -0
- package/dist/nestjs/index.cjs.map +1 -0
- package/dist/nestjs/index.d.cts +54 -0
- package/dist/nestjs/index.d.ts +54 -0
- package/dist/nestjs/index.js +124 -0
- package/dist/nestjs/index.js.map +1 -0
- package/package.json +29 -2
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { PafiErrorType, PafiSdkError } from '@pafi-dev/core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Stripe-style HTTP error envelope shared by every PAFI service and
|
|
5
|
+
* issuer backend. The framework-agnostic `normalizeErrorToEnvelope`
|
|
6
|
+
* helper produces this from any thrown value; framework-specific
|
|
7
|
+
* filters (`@pafi-dev/issuer/nestjs`) call into it and write the
|
|
8
|
+
* result to their response object.
|
|
9
|
+
*
|
|
10
|
+
* Wire format:
|
|
11
|
+
*
|
|
12
|
+
* ```json
|
|
13
|
+
* {
|
|
14
|
+
* "success": false,
|
|
15
|
+
* "statusCode": 422,
|
|
16
|
+
* "error": {
|
|
17
|
+
* "type": "business_logic_error",
|
|
18
|
+
* "code": "REDEMPTION_POLICY_DENIED",
|
|
19
|
+
* "message": "redemption denied: amount 1 below per-tx minimum",
|
|
20
|
+
* "param": null,
|
|
21
|
+
* "metadata": { "policyDenialCode": "PER_TX_MIN" },
|
|
22
|
+
* "safeToRetry": false,
|
|
23
|
+
* "details": null
|
|
24
|
+
* },
|
|
25
|
+
* "meta": {
|
|
26
|
+
* "timestamp": "2026-05-07T...",
|
|
27
|
+
* "requestId": "...",
|
|
28
|
+
* "path": "/pt/redeem"
|
|
29
|
+
* }
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
/** Inner `error` block of the envelope. */
|
|
35
|
+
interface PafiErrorPayload {
|
|
36
|
+
type: PafiErrorType;
|
|
37
|
+
code: string;
|
|
38
|
+
message: string;
|
|
39
|
+
param?: string;
|
|
40
|
+
metadata?: Record<string, unknown>;
|
|
41
|
+
details?: unknown;
|
|
42
|
+
safeToRetry: boolean;
|
|
43
|
+
}
|
|
44
|
+
/** Outer envelope returned for any non-2xx response. */
|
|
45
|
+
interface PafiErrorEnvelope {
|
|
46
|
+
success: false;
|
|
47
|
+
statusCode: number;
|
|
48
|
+
error: PafiErrorPayload;
|
|
49
|
+
meta: {
|
|
50
|
+
timestamp: string;
|
|
51
|
+
requestId: string;
|
|
52
|
+
path: string;
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
/** Per-call request context the filter must collect from the host framework. */
|
|
56
|
+
interface NormalizeContext {
|
|
57
|
+
/** `req.url` or equivalent. */
|
|
58
|
+
path: string;
|
|
59
|
+
/** Resolved request id (header or generated). */
|
|
60
|
+
requestId: string;
|
|
61
|
+
/** Optional `now()` injection for deterministic tests. */
|
|
62
|
+
now?: () => Date;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Generic error duck-type. The filter passes a small descriptor for
|
|
66
|
+
* any framework exception so the normalizer doesn't depend on
|
|
67
|
+
* `@nestjs/common` or any specific HTTP library.
|
|
68
|
+
*/
|
|
69
|
+
interface GenericHttpExceptionDescriptor {
|
|
70
|
+
/** HTTP status code carried by the exception. */
|
|
71
|
+
statusCode: number;
|
|
72
|
+
/**
|
|
73
|
+
* The body the framework would have serialized. For NestJS this is
|
|
74
|
+
* `exception.getResponse()`. May be a string or a record with
|
|
75
|
+
* `code`/`error`/`message`/`details`/`safeToRetry`/`type`/etc.
|
|
76
|
+
*/
|
|
77
|
+
responseBody: unknown;
|
|
78
|
+
/** Exception class name, used as a last-resort `code` fallback. */
|
|
79
|
+
exceptionName: string;
|
|
80
|
+
/** Original `error.message`, used as a last-resort `message` fallback. */
|
|
81
|
+
fallbackMessage: string;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Convert a `PafiSdkError` directly to the inner `error` payload —
|
|
85
|
+
* skipping any framework exception wrapper. Used by frameworks that
|
|
86
|
+
* surface SDK errors without going through `createSdkErrorMapper`.
|
|
87
|
+
*/
|
|
88
|
+
declare function payloadFromPafiSdkError(err: PafiSdkError): PafiErrorPayload;
|
|
89
|
+
/**
|
|
90
|
+
* Build the full envelope for any thrown value. The caller resolves
|
|
91
|
+
* `HttpException`-shaped exceptions and passes a descriptor; plain
|
|
92
|
+
* `Error` instances and unknown throws are handled directly.
|
|
93
|
+
*/
|
|
94
|
+
declare function buildErrorEnvelope(input: {
|
|
95
|
+
status: number;
|
|
96
|
+
payload: PafiErrorPayload;
|
|
97
|
+
ctx: NormalizeContext;
|
|
98
|
+
}): PafiErrorEnvelope;
|
|
99
|
+
/**
|
|
100
|
+
* Normalize a known `HttpException`-shaped exception into a payload.
|
|
101
|
+
* Framework filters supply the descriptor; the rest is shape-agnostic.
|
|
102
|
+
*/
|
|
103
|
+
declare function payloadFromHttpException(desc: GenericHttpExceptionDescriptor): PafiErrorPayload;
|
|
104
|
+
/**
|
|
105
|
+
* Normalize a generic `Error` (not an HttpException) — TypeORM
|
|
106
|
+
* `QueryFailedError`, viem revert errors, etc. Returns a redacted
|
|
107
|
+
* 500-class payload with no message bleed-through unless the error
|
|
108
|
+
* is recognizably benign.
|
|
109
|
+
*/
|
|
110
|
+
declare function payloadFromGenericError(err: Error): PafiErrorPayload;
|
|
111
|
+
|
|
112
|
+
export { type GenericHttpExceptionDescriptor, type NormalizeContext, type PafiErrorEnvelope, type PafiErrorPayload, buildErrorEnvelope, payloadFromGenericError, payloadFromHttpException, payloadFromPafiSdkError };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import "../chunk-R4FYJZ2N.js";
|
|
2
|
+
import {
|
|
3
|
+
buildErrorEnvelope,
|
|
4
|
+
payloadFromGenericError,
|
|
5
|
+
payloadFromHttpException,
|
|
6
|
+
payloadFromPafiSdkError
|
|
7
|
+
} from "../chunk-U3WMORJG.js";
|
|
8
|
+
export {
|
|
9
|
+
buildErrorEnvelope,
|
|
10
|
+
payloadFromGenericError,
|
|
11
|
+
payloadFromHttpException,
|
|
12
|
+
payloadFromPafiSdkError
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.cjs
CHANGED
|
@@ -62,14 +62,18 @@ __export(index_exports, {
|
|
|
62
62
|
RedemptionService: () => RedemptionService,
|
|
63
63
|
RelayError: () => RelayError,
|
|
64
64
|
RelayService: () => RelayService,
|
|
65
|
+
SDK_ERROR_HTTP_STATUS_CODE: () => import_core.SDK_ERROR_HTTP_STATUS_CODE,
|
|
65
66
|
SettlementClient: () => SettlementClient,
|
|
66
67
|
ValidationError: () => import_core3.ValidationError,
|
|
67
68
|
authenticateRequest: () => authenticateRequest,
|
|
69
|
+
buildErrorEnvelope: () => buildErrorEnvelope,
|
|
70
|
+
buildSdkErrorBody: () => buildSdkErrorBody,
|
|
68
71
|
createIssuerService: () => createIssuerService,
|
|
69
72
|
createNativePtQuoter: () => createNativePtQuoter,
|
|
70
73
|
createSdkErrorMapper: () => createSdkErrorMapper,
|
|
71
74
|
createSubgraphNativeUsdtQuoter: () => createSubgraphNativeUsdtQuoter,
|
|
72
75
|
createSubgraphPoolsProvider: () => createSubgraphPoolsProvider,
|
|
76
|
+
defaultErrorTypeForStatus: () => import_core.defaultErrorTypeForStatus,
|
|
73
77
|
defaultPolicyFor: () => defaultPolicyFor,
|
|
74
78
|
evaluateRedemption: () => evaluateRedemption,
|
|
75
79
|
handleClaimStatus: () => handleClaimStatus,
|
|
@@ -78,6 +82,9 @@ __export(index_exports, {
|
|
|
78
82
|
handleMobileSubmit: () => handleMobileSubmit,
|
|
79
83
|
handleRedeemStatus: () => handleRedeemStatus,
|
|
80
84
|
mergePaymasterFields: () => mergePaymasterFields,
|
|
85
|
+
payloadFromGenericError: () => payloadFromGenericError,
|
|
86
|
+
payloadFromHttpException: () => payloadFromHttpException,
|
|
87
|
+
payloadFromPafiSdkError: () => payloadFromPafiSdkError,
|
|
81
88
|
prepareMobileUserOp: () => prepareMobileUserOp,
|
|
82
89
|
relayUserOp: () => relayUserOp,
|
|
83
90
|
requestPaymaster: () => requestPaymaster,
|
|
@@ -101,6 +108,152 @@ var ConfigurationError = class extends import_core2.PafiSdkError {
|
|
|
101
108
|
}
|
|
102
109
|
};
|
|
103
110
|
|
|
111
|
+
// src/api/errorMapper.ts
|
|
112
|
+
function buildSdkErrorBody(err) {
|
|
113
|
+
const type = err.type ?? (0, import_core.defaultErrorTypeForStatus)(import_core.SDK_ERROR_HTTP_STATUS_CODE[err.httpStatus]);
|
|
114
|
+
const body = {
|
|
115
|
+
type,
|
|
116
|
+
code: err.code,
|
|
117
|
+
message: err.message,
|
|
118
|
+
safeToRetry: err.safeToRetry
|
|
119
|
+
};
|
|
120
|
+
if (err.param) body.param = err.param;
|
|
121
|
+
if (err.metadata) body.metadata = err.metadata;
|
|
122
|
+
if (err.details !== void 0) body.details = err.details;
|
|
123
|
+
return body;
|
|
124
|
+
}
|
|
125
|
+
function createSdkErrorMapper(factories) {
|
|
126
|
+
return (err) => {
|
|
127
|
+
if (!(err instanceof import_core.PafiSdkError)) {
|
|
128
|
+
throw err;
|
|
129
|
+
}
|
|
130
|
+
const body = buildSdkErrorBody(err);
|
|
131
|
+
switch (err.httpStatus) {
|
|
132
|
+
case "not_found":
|
|
133
|
+
throw factories.notFound(body);
|
|
134
|
+
case "forbidden":
|
|
135
|
+
throw factories.forbidden(body);
|
|
136
|
+
case "unprocessable":
|
|
137
|
+
throw factories.unprocessable(body);
|
|
138
|
+
case "service_unavailable":
|
|
139
|
+
throw factories.serviceUnavailable(body);
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/http/errorEnvelope.ts
|
|
145
|
+
function isValidationPipeBody(body) {
|
|
146
|
+
return Array.isArray(body["message"]) && typeof body["error"] === "string" && body["error"] === "Bad Request";
|
|
147
|
+
}
|
|
148
|
+
function extractParamFromValidatorMessage(message) {
|
|
149
|
+
const idx = message.indexOf(" ");
|
|
150
|
+
if (idx <= 0) return void 0;
|
|
151
|
+
const candidate = message.slice(0, idx);
|
|
152
|
+
return /^[A-Za-z_][\w.]*$/.test(candidate) ? candidate : void 0;
|
|
153
|
+
}
|
|
154
|
+
function normalizeValidationPipeBody(body) {
|
|
155
|
+
const fields = {};
|
|
156
|
+
for (const msg of body.message) {
|
|
157
|
+
const param2 = extractParamFromValidatorMessage(msg);
|
|
158
|
+
const key = param2 ?? "_";
|
|
159
|
+
(fields[key] ??= []).push(msg);
|
|
160
|
+
}
|
|
161
|
+
const fieldKeys = Object.keys(fields).filter((k) => k !== "_");
|
|
162
|
+
const param = fieldKeys.length === 1 ? fieldKeys[0] : void 0;
|
|
163
|
+
const payload = {
|
|
164
|
+
type: "validation_error",
|
|
165
|
+
code: "VALIDATION_FAILED",
|
|
166
|
+
message: body.message.join("; "),
|
|
167
|
+
safeToRetry: false,
|
|
168
|
+
metadata: { fieldErrors: fields }
|
|
169
|
+
};
|
|
170
|
+
if (param) payload.param = param;
|
|
171
|
+
return payload;
|
|
172
|
+
}
|
|
173
|
+
function normalizeHttpExceptionBody(desc) {
|
|
174
|
+
const { statusCode, responseBody, exceptionName, fallbackMessage } = desc;
|
|
175
|
+
const defaultType = (0, import_core.defaultErrorTypeForStatus)(statusCode);
|
|
176
|
+
if (typeof responseBody === "string") {
|
|
177
|
+
return {
|
|
178
|
+
type: defaultType,
|
|
179
|
+
code: exceptionName,
|
|
180
|
+
message: responseBody,
|
|
181
|
+
safeToRetry: false
|
|
182
|
+
};
|
|
183
|
+
}
|
|
184
|
+
if (responseBody && typeof responseBody === "object") {
|
|
185
|
+
const body = responseBody;
|
|
186
|
+
if (isValidationPipeBody(body)) {
|
|
187
|
+
return normalizeValidationPipeBody(body);
|
|
188
|
+
}
|
|
189
|
+
const code = typeof body["code"] === "string" && body["code"] || typeof body["error"] === "string" && body["error"] || exceptionName;
|
|
190
|
+
const message = typeof body["message"] === "string" && body["message"] || (Array.isArray(body["message"]) ? body["message"].join("; ") : "") || fallbackMessage;
|
|
191
|
+
const type = typeof body["type"] === "string" && body["type"] || defaultType;
|
|
192
|
+
const safeToRetry = typeof body["safeToRetry"] === "boolean" ? body["safeToRetry"] : false;
|
|
193
|
+
const payload = {
|
|
194
|
+
type,
|
|
195
|
+
code,
|
|
196
|
+
message,
|
|
197
|
+
safeToRetry
|
|
198
|
+
};
|
|
199
|
+
if (typeof body["param"] === "string") payload.param = body["param"];
|
|
200
|
+
if (body["metadata"] && typeof body["metadata"] === "object") {
|
|
201
|
+
payload.metadata = body["metadata"];
|
|
202
|
+
}
|
|
203
|
+
if (body["details"] !== void 0) payload.details = body["details"];
|
|
204
|
+
return payload;
|
|
205
|
+
}
|
|
206
|
+
return {
|
|
207
|
+
type: defaultType,
|
|
208
|
+
code: exceptionName || "INTERNAL_SERVER_ERROR",
|
|
209
|
+
message: fallbackMessage || "An unexpected error occurred",
|
|
210
|
+
safeToRetry: false
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
function payloadFromPafiSdkError(err) {
|
|
214
|
+
const body = buildSdkErrorBody(err);
|
|
215
|
+
const payload = {
|
|
216
|
+
type: body.type,
|
|
217
|
+
code: body.code,
|
|
218
|
+
message: body.message,
|
|
219
|
+
safeToRetry: body.safeToRetry
|
|
220
|
+
};
|
|
221
|
+
if (body.param) payload.param = body.param;
|
|
222
|
+
if (body.metadata) payload.metadata = body.metadata;
|
|
223
|
+
if (body.details !== void 0) payload.details = body.details;
|
|
224
|
+
return payload;
|
|
225
|
+
}
|
|
226
|
+
function sanitizeDbErrorMessage(message) {
|
|
227
|
+
if (/^[A-Z_]+: /.test(message) && message.length < 256) return message;
|
|
228
|
+
return "Internal database error";
|
|
229
|
+
}
|
|
230
|
+
function buildErrorEnvelope(input) {
|
|
231
|
+
const now = (input.ctx.now ?? (() => /* @__PURE__ */ new Date()))();
|
|
232
|
+
return {
|
|
233
|
+
success: false,
|
|
234
|
+
statusCode: input.status,
|
|
235
|
+
error: input.payload,
|
|
236
|
+
meta: {
|
|
237
|
+
timestamp: now.toISOString(),
|
|
238
|
+
requestId: input.ctx.requestId,
|
|
239
|
+
path: input.ctx.path
|
|
240
|
+
}
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
function payloadFromHttpException(desc) {
|
|
244
|
+
return normalizeHttpExceptionBody(desc);
|
|
245
|
+
}
|
|
246
|
+
function payloadFromGenericError(err) {
|
|
247
|
+
const name = err.name || "INTERNAL_SERVER_ERROR";
|
|
248
|
+
const isDbError = name === "QueryFailedError" || name === "EntityNotFoundError";
|
|
249
|
+
return {
|
|
250
|
+
type: "server_error",
|
|
251
|
+
code: name,
|
|
252
|
+
message: isDbError ? sanitizeDbErrorMessage(err.message) : err.message || "An unexpected error occurred",
|
|
253
|
+
safeToRetry: false
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
|
|
104
257
|
// src/policy/defaultPolicy.ts
|
|
105
258
|
var DefaultPolicyEngine = class {
|
|
106
259
|
ledger;
|
|
@@ -2781,31 +2934,6 @@ async function handleDelegateSubmit(params) {
|
|
|
2781
2934
|
return { userOpHash: result.userOpHash };
|
|
2782
2935
|
}
|
|
2783
2936
|
|
|
2784
|
-
// src/api/errorMapper.ts
|
|
2785
|
-
function createSdkErrorMapper(factories) {
|
|
2786
|
-
return (err) => {
|
|
2787
|
-
if (!(err instanceof import_core.PafiSdkError)) {
|
|
2788
|
-
throw err;
|
|
2789
|
-
}
|
|
2790
|
-
const body = {
|
|
2791
|
-
code: err.code,
|
|
2792
|
-
message: err.message,
|
|
2793
|
-
details: err.details,
|
|
2794
|
-
safeToRetry: err.safeToRetry
|
|
2795
|
-
};
|
|
2796
|
-
switch (err.httpStatus) {
|
|
2797
|
-
case "not_found":
|
|
2798
|
-
throw factories.notFound(body);
|
|
2799
|
-
case "forbidden":
|
|
2800
|
-
throw factories.forbidden(body);
|
|
2801
|
-
case "unprocessable":
|
|
2802
|
-
throw factories.unprocessable(body);
|
|
2803
|
-
case "service_unavailable":
|
|
2804
|
-
throw factories.serviceUnavailable(body);
|
|
2805
|
-
}
|
|
2806
|
-
};
|
|
2807
|
-
}
|
|
2808
|
-
|
|
2809
2937
|
// src/api/issuerApiAdapter.ts
|
|
2810
2938
|
var import_node_crypto3 = require("crypto");
|
|
2811
2939
|
var import_viem11 = require("viem");
|
|
@@ -4444,7 +4572,7 @@ var MemoryRedemptionHistoryStore = class {
|
|
|
4444
4572
|
};
|
|
4445
4573
|
|
|
4446
4574
|
// src/index.ts
|
|
4447
|
-
var PAFI_ISSUER_SDK_VERSION = true ? "0.
|
|
4575
|
+
var PAFI_ISSUER_SDK_VERSION = true ? "0.9.0" : "dev";
|
|
4448
4576
|
// Annotate the CommonJS export names for ESM import in node:
|
|
4449
4577
|
0 && (module.exports = {
|
|
4450
4578
|
AdapterMisconfiguredError,
|
|
@@ -4489,14 +4617,18 @@ var PAFI_ISSUER_SDK_VERSION = true ? "0.8.0" : "dev";
|
|
|
4489
4617
|
RedemptionService,
|
|
4490
4618
|
RelayError,
|
|
4491
4619
|
RelayService,
|
|
4620
|
+
SDK_ERROR_HTTP_STATUS_CODE,
|
|
4492
4621
|
SettlementClient,
|
|
4493
4622
|
ValidationError,
|
|
4494
4623
|
authenticateRequest,
|
|
4624
|
+
buildErrorEnvelope,
|
|
4625
|
+
buildSdkErrorBody,
|
|
4495
4626
|
createIssuerService,
|
|
4496
4627
|
createNativePtQuoter,
|
|
4497
4628
|
createSdkErrorMapper,
|
|
4498
4629
|
createSubgraphNativeUsdtQuoter,
|
|
4499
4630
|
createSubgraphPoolsProvider,
|
|
4631
|
+
defaultErrorTypeForStatus,
|
|
4500
4632
|
defaultPolicyFor,
|
|
4501
4633
|
evaluateRedemption,
|
|
4502
4634
|
handleClaimStatus,
|
|
@@ -4505,6 +4637,9 @@ var PAFI_ISSUER_SDK_VERSION = true ? "0.8.0" : "dev";
|
|
|
4505
4637
|
handleMobileSubmit,
|
|
4506
4638
|
handleRedeemStatus,
|
|
4507
4639
|
mergePaymasterFields,
|
|
4640
|
+
payloadFromGenericError,
|
|
4641
|
+
payloadFromHttpException,
|
|
4642
|
+
payloadFromPafiSdkError,
|
|
4508
4643
|
prepareMobileUserOp,
|
|
4509
4644
|
relayUserOp,
|
|
4510
4645
|
requestPaymaster,
|