@odatano/x402 0.2.0 → 0.3.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.
Files changed (62) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +5 -0
  3. package/cds-plugin.js +2 -0
  4. package/db/x402-grants.cds +49 -0
  5. package/db/x402-receipts.cds +44 -0
  6. package/package.json +4 -3
  7. package/srv/bridge.d.ts +9 -12
  8. package/srv/bridge.js +10 -13
  9. package/srv/client/axios.d.ts +1 -1
  10. package/srv/client/axios.js +45 -8
  11. package/srv/client/envelope.d.ts +1 -1
  12. package/srv/client/envelope.js +1 -1
  13. package/srv/client/errors.d.ts +86 -0
  14. package/srv/client/errors.js +107 -0
  15. package/srv/client/fetch.d.ts +2 -2
  16. package/srv/client/fetch.js +71 -11
  17. package/srv/client/pay-handlers.d.ts +4 -4
  18. package/srv/client/pay-handlers.js +3 -3
  19. package/srv/client/types.d.ts +19 -7
  20. package/srv/client/types.js +3 -3
  21. package/srv/core/asset.d.ts +1 -1
  22. package/srv/core/decode.d.ts +2 -2
  23. package/srv/core/decode.js +5 -5
  24. package/srv/core/errors.js +3 -3
  25. package/srv/core/network.d.ts +1 -1
  26. package/srv/core/network.js +1 -1
  27. package/srv/core/requirements.d.ts +37 -5
  28. package/srv/core/requirements.js +43 -4
  29. package/srv/core/types.d.ts +68 -6
  30. package/srv/core/types.js +3 -3
  31. package/srv/core/validate.d.ts +31 -7
  32. package/srv/core/validate.js +84 -9
  33. package/srv/facilitator/adapter.d.ts +8 -8
  34. package/srv/facilitator/adapter.js +5 -5
  35. package/srv/facilitator/http.d.ts +4 -4
  36. package/srv/facilitator/http.js +5 -5
  37. package/srv/facilitator/nonce.d.ts +4 -4
  38. package/srv/facilitator/nonce.js +4 -4
  39. package/srv/facilitator/server.d.ts +68 -0
  40. package/srv/facilitator/server.js +167 -0
  41. package/srv/facilitator/settle.d.ts +2 -2
  42. package/srv/facilitator/settle.js +4 -4
  43. package/srv/facilitator/verify.d.ts +5 -5
  44. package/srv/facilitator/verify.js +19 -5
  45. package/srv/helpers/build-unsigned-tx.d.ts +5 -5
  46. package/srv/helpers/build-unsigned-tx.js +3 -3
  47. package/srv/helpers/verify-confirmed.d.ts +1 -1
  48. package/srv/helpers/verify-confirmed.js +1 -1
  49. package/srv/index.d.ts +4 -2
  50. package/srv/index.js +9 -3
  51. package/srv/middleware/cap.d.ts +47 -9
  52. package/srv/middleware/cap.js +111 -43
  53. package/srv/middleware/express.d.ts +15 -10
  54. package/srv/middleware/express.js +18 -19
  55. package/srv/middleware/grants.d.ts +64 -0
  56. package/srv/middleware/grants.js +113 -0
  57. package/srv/middleware/pricing.d.ts +41 -0
  58. package/srv/middleware/pricing.js +78 -0
  59. package/srv/middleware/receipts.d.ts +38 -0
  60. package/srv/middleware/receipts.js +68 -0
  61. package/srv/plugin.d.ts +2 -2
  62. package/srv/plugin.js +2 -2
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CAP-backed persistence for accepted x402 payments.
3
+ *
4
+ * Called from `gateService` when its `receipts` option is set. One INSERT
5
+ * per accepted payment; runs AFTER settle confirms and BEFORE the 200
6
+ * response is served to the buyer. Best-effort: any INSERT failure is
7
+ * logged and SWALLOWED, the canonical record is on chain and we never
8
+ * want a flaky DB to deny a paying buyer their response.
9
+ *
10
+ * Entity shape: see `db/x402-receipts.cds`. The schema is shipped in the
11
+ * plugin's `db/`; CAP auto-discovers it when `@odatano/x402` is in
12
+ * node_modules. Consumers wanting a custom shape can pass
13
+ * `receipts: { entity: 'my.namespace.MyTable' }`, the table needs to
14
+ * carry the columns we INSERT below.
15
+ *
16
+ * Idempotency: txHash carries `@assert.unique`. A duplicate INSERT
17
+ * (e.g. settle returning twice for the same buyer) hits a unique-key
18
+ * violation and we log + continue. Buyers' UX is unaffected.
19
+ */
20
+ import type { PaymentClaim } from '../core/types';
21
+ /** Canonical entity name shipped by the plugin. */
22
+ export declare const DEFAULT_RECEIPTS_ENTITY = "odatano.x402.X402Receipts";
23
+ /**
24
+ * Insert one receipt for an accepted payment. Returns a promise that
25
+ * always resolves (never throws), errors are logged.
26
+ *
27
+ * The `route` argument is the resource URL the buyer paid for, the same
28
+ * value embedded in `accepts[0].resource.url`. We pass it explicitly
29
+ * rather than re-deriving it inside this module so the persisted route
30
+ * matches what the 402 advertised, even when the consumer set a custom
31
+ * `resourceUrl` builder.
32
+ */
33
+ export declare function persistReceipt(entityName: string, claim: PaymentClaim, route: string): Promise<void>;
34
+ /** Resolve the entity name from the `receipts` option. */
35
+ export declare function resolveReceiptsEntity(receipts: boolean | {
36
+ entity?: string;
37
+ } | undefined): string | null;
38
+ //# sourceMappingURL=receipts.d.ts.map
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ /**
3
+ * CAP-backed persistence for accepted x402 payments.
4
+ *
5
+ * Called from `gateService` when its `receipts` option is set. One INSERT
6
+ * per accepted payment; runs AFTER settle confirms and BEFORE the 200
7
+ * response is served to the buyer. Best-effort: any INSERT failure is
8
+ * logged and SWALLOWED, the canonical record is on chain and we never
9
+ * want a flaky DB to deny a paying buyer their response.
10
+ *
11
+ * Entity shape: see `db/x402-receipts.cds`. The schema is shipped in the
12
+ * plugin's `db/`; CAP auto-discovers it when `@odatano/x402` is in
13
+ * node_modules. Consumers wanting a custom shape can pass
14
+ * `receipts: { entity: 'my.namespace.MyTable' }`, the table needs to
15
+ * carry the columns we INSERT below.
16
+ *
17
+ * Idempotency: txHash carries `@assert.unique`. A duplicate INSERT
18
+ * (e.g. settle returning twice for the same buyer) hits a unique-key
19
+ * violation and we log + continue. Buyers' UX is unaffected.
20
+ */
21
+ var __importDefault = (this && this.__importDefault) || function (mod) {
22
+ return (mod && mod.__esModule) ? mod : { "default": mod };
23
+ };
24
+ Object.defineProperty(exports, "__esModule", { value: true });
25
+ exports.DEFAULT_RECEIPTS_ENTITY = void 0;
26
+ exports.persistReceipt = persistReceipt;
27
+ exports.resolveReceiptsEntity = resolveReceiptsEntity;
28
+ const cds_1 = __importDefault(require("@sap/cds"));
29
+ const log = cds_1.default.log('x402');
30
+ /** Canonical entity name shipped by the plugin. */
31
+ exports.DEFAULT_RECEIPTS_ENTITY = 'odatano.x402.X402Receipts';
32
+ /**
33
+ * Insert one receipt for an accepted payment. Returns a promise that
34
+ * always resolves (never throws), errors are logged.
35
+ *
36
+ * The `route` argument is the resource URL the buyer paid for, the same
37
+ * value embedded in `accepts[0].resource.url`. We pass it explicitly
38
+ * rather than re-deriving it inside this module so the persisted route
39
+ * matches what the 402 advertised, even when the consumer set a custom
40
+ * `resourceUrl` builder.
41
+ */
42
+ async function persistReceipt(entityName, claim, route) {
43
+ try {
44
+ await INSERT.into(entityName).entries({
45
+ ID: cds_1.default.utils.uuid(),
46
+ txHash: claim.txHash,
47
+ payerAddr: claim.payerAddr ?? null,
48
+ payTo: claim.payTo,
49
+ asset: claim.asset,
50
+ amount: claim.amountUnits,
51
+ network: claim.network,
52
+ route,
53
+ nonceRef: claim.nonceRef,
54
+ at: new Date().toISOString(),
55
+ });
56
+ }
57
+ catch (err) {
58
+ log.warn(`x402 receipts INSERT into ${entityName} failed (non-fatal):`, err?.message ?? err);
59
+ }
60
+ }
61
+ /** Resolve the entity name from the `receipts` option. */
62
+ function resolveReceiptsEntity(receipts) {
63
+ if (!receipts)
64
+ return null;
65
+ if (receipts === true)
66
+ return exports.DEFAULT_RECEIPTS_ENTITY;
67
+ return receipts.entity ?? exports.DEFAULT_RECEIPTS_ENTITY;
68
+ }
package/srv/plugin.d.ts CHANGED
@@ -2,13 +2,13 @@
2
2
  * CAP plugin registration for `@odatano/x402`.
3
3
  *
4
4
  * Unlike `@odatano/core`, this plugin doesn't auto-serve any CDS
5
- * entities x402 is a library, not a service. We use the
5
+ * entities, x402 is a library, not a service. We use the
6
6
  * `cds.on('served')` hook only to initialise the bridge (warm up the
7
7
  * @odatano/core connection) and the `cds.on('shutdown')` hook to clean
8
8
  * up. Consumers wire middleware / gateService themselves inside their
9
9
  * own service init().
10
10
  *
11
- * NEVER throws on init failure the plugin must not crash the host
11
+ * NEVER throws on init failure, the plugin must not crash the host
12
12
  * CAP application. Errors are logged; calls into the bridge later
13
13
  * will fail with `BRIDGE_UNAVAILABLE`.
14
14
  */
package/srv/plugin.js CHANGED
@@ -3,13 +3,13 @@
3
3
  * CAP plugin registration for `@odatano/x402`.
4
4
  *
5
5
  * Unlike `@odatano/core`, this plugin doesn't auto-serve any CDS
6
- * entities x402 is a library, not a service. We use the
6
+ * entities, x402 is a library, not a service. We use the
7
7
  * `cds.on('served')` hook only to initialise the bridge (warm up the
8
8
  * @odatano/core connection) and the `cds.on('shutdown')` hook to clean
9
9
  * up. Consumers wire middleware / gateService themselves inside their
10
10
  * own service init().
11
11
  *
12
- * NEVER throws on init failure the plugin must not crash the host
12
+ * NEVER throws on init failure, the plugin must not crash the host
13
13
  * CAP application. Errors are logged; calls into the bridge later
14
14
  * will fail with `BRIDGE_UNAVAILABLE`.
15
15
  */