@reinconsole/gate 0.1.0 → 0.1.1
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/README.md +1 -1
- package/dist/index.cjs +53 -60
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +13 -37
- package/dist/index.d.ts +13 -37
- package/dist/index.js +33 -54
- package/dist/index.js.map +1 -1
- package/package.json +7 -6
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
The supply side of **[Rein](https://github.com/bugiiiii11/rein)** — vendor-side [x402](https://www.x402.org) monetization middleware. Price your routes once and every payment into your API is quoted, cross-checked, screened, rate-limited, settled, and receipted before your handler runs.
|
|
4
4
|
|
|
5
|
-
> **Status: v0.1 — early open-source infrastructure, live on testnet.** Verified live on Base Sepolia against the hosted x402.org facilitator. APIs may change before 1.0. See it running: [Rein console](https://reinconsole
|
|
5
|
+
> **Status: v0.1 — early open-source infrastructure, live on testnet.** Verified live on Base Sepolia against the hosted x402.org facilitator. APIs may change before 1.0. See it running: [Rein console](https://app.reinconsole.com).
|
|
6
6
|
|
|
7
7
|
## Install
|
|
8
8
|
|
package/dist/index.cjs
CHANGED
|
@@ -15,59 +15,19 @@ var GateError = class extends Error {
|
|
|
15
15
|
this.code = code;
|
|
16
16
|
this.name = "GateError";
|
|
17
17
|
this.retryAfterSeconds = options.retryAfterSeconds;
|
|
18
|
+
this.paymentResponse = options.paymentResponse;
|
|
18
19
|
}
|
|
19
20
|
code;
|
|
20
21
|
/** Seconds until the refused payment could be admitted (throttle codes). */
|
|
21
22
|
retryAfterSeconds;
|
|
23
|
+
/**
|
|
24
|
+
* The rails' own failed settlement response, when there is one (a
|
|
25
|
+
* facilitator settle that answered `success: false`). Refusals of v2
|
|
26
|
+
* payments relay it verbatim in the PAYMENT-RESPONSE header instead of a
|
|
27
|
+
* synthesized one, so the payer sees the facilitator's real errorReason.
|
|
28
|
+
*/
|
|
29
|
+
paymentResponse;
|
|
22
30
|
};
|
|
23
|
-
|
|
24
|
-
// src/v2.ts
|
|
25
|
-
var CAIP2_ALIASES = {
|
|
26
|
-
base: "eip155:8453",
|
|
27
|
-
"base-sepolia": "eip155:84532",
|
|
28
|
-
polygon: "eip155:137",
|
|
29
|
-
"polygon-amoy": "eip155:80002",
|
|
30
|
-
bnb: "eip155:56",
|
|
31
|
-
bsc: "eip155:56",
|
|
32
|
-
solana: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
|
|
33
|
-
"solana-devnet": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"
|
|
34
|
-
};
|
|
35
|
-
function caip2Of(network) {
|
|
36
|
-
const key = network.toLowerCase();
|
|
37
|
-
return CAIP2_ALIASES[key] ?? key;
|
|
38
|
-
}
|
|
39
|
-
function sameNetwork(a, b) {
|
|
40
|
-
return caip2Of(a) === caip2Of(b);
|
|
41
|
-
}
|
|
42
|
-
function v2Requirements(requirement) {
|
|
43
|
-
return {
|
|
44
|
-
scheme: requirement.scheme,
|
|
45
|
-
network: caip2Of(requirement.network),
|
|
46
|
-
amount: requirement.maxAmountRequired,
|
|
47
|
-
asset: requirement.asset,
|
|
48
|
-
payTo: requirement.payTo,
|
|
49
|
-
...requirement.maxTimeoutSeconds !== void 0 ? { maxTimeoutSeconds: requirement.maxTimeoutSeconds } : {},
|
|
50
|
-
...requirement.extra ? { extra: requirement.extra } : {}
|
|
51
|
-
};
|
|
52
|
-
}
|
|
53
|
-
function buildPaymentRequiredV2(requirement, error) {
|
|
54
|
-
return {
|
|
55
|
-
x402Version: 2,
|
|
56
|
-
error,
|
|
57
|
-
...requirement.resource ? {
|
|
58
|
-
resource: {
|
|
59
|
-
url: requirement.resource,
|
|
60
|
-
...requirement.description ? { description: requirement.description } : {},
|
|
61
|
-
...requirement.mimeType ? { mimeType: requirement.mimeType } : {}
|
|
62
|
-
}
|
|
63
|
-
} : {},
|
|
64
|
-
accepts: [v2Requirements(requirement)],
|
|
65
|
-
extensions: {}
|
|
66
|
-
};
|
|
67
|
-
}
|
|
68
|
-
function encodeBase64Json(value) {
|
|
69
|
-
return Buffer.from(JSON.stringify(value)).toString("base64");
|
|
70
|
-
}
|
|
71
31
|
var UintString = zod.z.string().regex(/^\d+$/, "must be a decimal integer string");
|
|
72
32
|
var Transfer = zod.z.object({
|
|
73
33
|
from: zod.z.string().min(1),
|
|
@@ -209,7 +169,7 @@ function mockFacilitatorRails(facilitator) {
|
|
|
209
169
|
function facilitatorClientRails(client) {
|
|
210
170
|
const dialectRequirements = (paymentHeader, requirement) => {
|
|
211
171
|
const { envelope, version } = inspectPaymentHeader(paymentHeader);
|
|
212
|
-
return { envelope, requirements: version === 2 ? v2Requirements(requirement) : requirement };
|
|
172
|
+
return { envelope, requirements: version === 2 ? sdk.v2Requirements(requirement) : requirement };
|
|
213
173
|
};
|
|
214
174
|
return {
|
|
215
175
|
async verify(paymentHeader, requirement) {
|
|
@@ -233,7 +193,9 @@ function facilitatorClientRails(client) {
|
|
|
233
193
|
classifyTransport(err);
|
|
234
194
|
}
|
|
235
195
|
if (!settled.success) {
|
|
236
|
-
throw new GateError("settle_failed", settled.errorReason ?? "payment settlement failed"
|
|
196
|
+
throw new GateError("settle_failed", settled.errorReason ?? "payment settlement failed", {
|
|
197
|
+
paymentResponse: settled
|
|
198
|
+
});
|
|
237
199
|
}
|
|
238
200
|
return {
|
|
239
201
|
header: encodeSettlementHeader(settled),
|
|
@@ -470,9 +432,11 @@ var Gate = class {
|
|
|
470
432
|
};
|
|
471
433
|
}
|
|
472
434
|
let payer;
|
|
435
|
+
let wire;
|
|
473
436
|
try {
|
|
474
437
|
const payment = inspectPaymentHeader(request.payment);
|
|
475
438
|
payer = payment.payer;
|
|
439
|
+
wire = payment.version;
|
|
476
440
|
this.checkRate(payment.payer);
|
|
477
441
|
this.checkConsistency(payment, requirement);
|
|
478
442
|
this.screenPayer(payment.payer);
|
|
@@ -498,7 +462,7 @@ var Gate = class {
|
|
|
498
462
|
return { kind: "paid", receipt, settlementHeader: settlement.header };
|
|
499
463
|
} catch (err) {
|
|
500
464
|
if (!(err instanceof GateError)) throw err;
|
|
501
|
-
return this.refuse(err, url.pathname, requirement, payer);
|
|
465
|
+
return this.refuse(err, url.pathname, requirement, payer, wire);
|
|
502
466
|
}
|
|
503
467
|
}
|
|
504
468
|
stats() {
|
|
@@ -542,7 +506,7 @@ var Gate = class {
|
|
|
542
506
|
`payment scheme "${payment.scheme}" does not match the quoted "${requirement.scheme}"`
|
|
543
507
|
);
|
|
544
508
|
}
|
|
545
|
-
if (!sameNetwork(payment.network, requirement.network)) {
|
|
509
|
+
if (!sdk.sameNetwork(payment.network, requirement.network)) {
|
|
546
510
|
throw new GateError(
|
|
547
511
|
"network_mismatch",
|
|
548
512
|
`payment is on "${payment.network}" but the quote wants "${requirement.network}"`
|
|
@@ -699,7 +663,7 @@ var Gate = class {
|
|
|
699
663
|
);
|
|
700
664
|
}
|
|
701
665
|
}
|
|
702
|
-
refuse(err, resource, requirement, payer) {
|
|
666
|
+
refuse(err, resource, requirement, payer, wire) {
|
|
703
667
|
this.fire(() => this.store.recordRefusal());
|
|
704
668
|
this.emit({
|
|
705
669
|
type: "gate.refused",
|
|
@@ -749,14 +713,15 @@ var Gate = class {
|
|
|
749
713
|
code: err.code,
|
|
750
714
|
reason: err.message,
|
|
751
715
|
body: { x402Version: 1, accepts: [requirement], error: err.message },
|
|
752
|
-
...this.v2Quote(requirement, err.message)
|
|
716
|
+
...this.v2Quote(requirement, err.message),
|
|
717
|
+
...wire === 2 ? { paymentResponseHeader: v2FailureHeader(err, requirement, payer) } : {}
|
|
753
718
|
};
|
|
754
719
|
}
|
|
755
720
|
/** The v2 half of a dual-stack 402 (see advertiseV2), or nothing. */
|
|
756
721
|
v2Quote(requirement, error) {
|
|
757
722
|
if (!this.advertiseV2) return {};
|
|
758
723
|
return {
|
|
759
|
-
paymentRequiredHeader: encodeBase64Json(buildPaymentRequiredV2(requirement, error))
|
|
724
|
+
paymentRequiredHeader: sdk.encodeBase64Json(sdk.buildPaymentRequiredV2(requirement, error))
|
|
760
725
|
};
|
|
761
726
|
}
|
|
762
727
|
};
|
|
@@ -766,6 +731,17 @@ function createGate(options) {
|
|
|
766
731
|
function replayKey(paymentHeader) {
|
|
767
732
|
return crypto.createHash("sha256").update(paymentHeader).digest("hex");
|
|
768
733
|
}
|
|
734
|
+
function v2FailureHeader(err, requirement, payer) {
|
|
735
|
+
return sdk.encodeBase64Json(
|
|
736
|
+
err.paymentResponse ?? {
|
|
737
|
+
success: false,
|
|
738
|
+
errorReason: err.code,
|
|
739
|
+
transaction: "",
|
|
740
|
+
network: sdk.caip2Of(requirement.network),
|
|
741
|
+
...payer !== void 0 ? { payer } : {}
|
|
742
|
+
}
|
|
743
|
+
);
|
|
744
|
+
}
|
|
769
745
|
function messageOf2(err) {
|
|
770
746
|
return err instanceof Error ? err.message : String(err);
|
|
771
747
|
}
|
|
@@ -792,6 +768,7 @@ function gateMiddleware(gate, options = {}) {
|
|
|
792
768
|
res.writeHead(outcome.status, {
|
|
793
769
|
"content-type": "application/json",
|
|
794
770
|
...outcome.paymentRequiredHeader !== void 0 ? { "payment-required": outcome.paymentRequiredHeader } : {},
|
|
771
|
+
...outcome.kind === "refused" && outcome.paymentResponseHeader !== void 0 ? { "payment-response": outcome.paymentResponseHeader } : {},
|
|
795
772
|
...outcome.kind === "refused" && outcome.retryAfterSeconds !== void 0 ? { "retry-after": String(outcome.retryAfterSeconds) } : {}
|
|
796
773
|
});
|
|
797
774
|
res.end(JSON.stringify(outcome.body));
|
|
@@ -835,21 +812,39 @@ function createGatedFetch(gate, options = {}) {
|
|
|
835
812
|
headers: {
|
|
836
813
|
"content-type": "application/json",
|
|
837
814
|
...outcome.paymentRequiredHeader !== void 0 ? { "payment-required": outcome.paymentRequiredHeader } : {},
|
|
815
|
+
...outcome.kind === "refused" && outcome.paymentResponseHeader !== void 0 ? { "payment-response": outcome.paymentResponseHeader } : {},
|
|
838
816
|
...outcome.kind === "refused" && outcome.retryAfterSeconds !== void 0 ? { "retry-after": String(outcome.retryAfterSeconds) } : {}
|
|
839
817
|
}
|
|
840
818
|
});
|
|
841
819
|
};
|
|
842
820
|
}
|
|
843
821
|
|
|
822
|
+
Object.defineProperty(exports, "buildPaymentRequiredV2", {
|
|
823
|
+
enumerable: true,
|
|
824
|
+
get: function () { return sdk.buildPaymentRequiredV2; }
|
|
825
|
+
});
|
|
826
|
+
Object.defineProperty(exports, "caip2Of", {
|
|
827
|
+
enumerable: true,
|
|
828
|
+
get: function () { return sdk.caip2Of; }
|
|
829
|
+
});
|
|
830
|
+
Object.defineProperty(exports, "encodeBase64Json", {
|
|
831
|
+
enumerable: true,
|
|
832
|
+
get: function () { return sdk.encodeBase64Json; }
|
|
833
|
+
});
|
|
834
|
+
Object.defineProperty(exports, "sameNetwork", {
|
|
835
|
+
enumerable: true,
|
|
836
|
+
get: function () { return sdk.sameNetwork; }
|
|
837
|
+
});
|
|
838
|
+
Object.defineProperty(exports, "v2Requirements", {
|
|
839
|
+
enumerable: true,
|
|
840
|
+
get: function () { return sdk.v2Requirements; }
|
|
841
|
+
});
|
|
844
842
|
exports.Gate = Gate;
|
|
845
843
|
exports.GateError = GateError;
|
|
846
844
|
exports.InMemoryGateStore = InMemoryGateStore;
|
|
847
845
|
exports.RailsUnreachableError = RailsUnreachableError;
|
|
848
|
-
exports.buildPaymentRequiredV2 = buildPaymentRequiredV2;
|
|
849
|
-
exports.caip2Of = caip2Of;
|
|
850
846
|
exports.createGate = createGate;
|
|
851
847
|
exports.createGatedFetch = createGatedFetch;
|
|
852
|
-
exports.encodeBase64Json = encodeBase64Json;
|
|
853
848
|
exports.facilitatorClientRails = facilitatorClientRails;
|
|
854
849
|
exports.gateMiddleware = gateMiddleware;
|
|
855
850
|
exports.inspectPaymentHeader = inspectPaymentHeader;
|
|
@@ -857,8 +852,6 @@ exports.matchRoute = matchRoute;
|
|
|
857
852
|
exports.mockFacilitatorRails = mockFacilitatorRails;
|
|
858
853
|
exports.requirementFor = requirementFor;
|
|
859
854
|
exports.routeDecimals = routeDecimals;
|
|
860
|
-
exports.sameNetwork = sameNetwork;
|
|
861
|
-
exports.v2Requirements = v2Requirements;
|
|
862
855
|
exports.validateVelocity = validateVelocity;
|
|
863
856
|
//# sourceMappingURL=index.cjs.map
|
|
864
857
|
//# sourceMappingURL=index.cjs.map
|