remesso-sdk 0.0.0-stage → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +379 -2
  3. package/dist/abi.d.ts +63 -0
  4. package/dist/abi.js +14 -0
  5. package/dist/agents.d.ts +15 -0
  6. package/dist/agents.js +39 -0
  7. package/dist/attribution.d.ts +3 -0
  8. package/dist/attribution.js +29 -0
  9. package/dist/client.d.ts +75 -0
  10. package/dist/client.js +60 -0
  11. package/dist/context.d.ts +42 -0
  12. package/dist/context.js +157 -0
  13. package/dist/deployment.d.ts +19 -0
  14. package/dist/deployment.js +80 -0
  15. package/dist/errors.d.ts +30 -0
  16. package/dist/errors.js +10 -0
  17. package/dist/events.d.ts +59 -0
  18. package/dist/events.js +53 -0
  19. package/dist/generated/abi.d.ts +1543 -0
  20. package/dist/generated/abi.js +1979 -0
  21. package/dist/generated/deployment.d.ts +114 -0
  22. package/dist/generated/deployment.js +127 -0
  23. package/dist/index.d.ts +16 -0
  24. package/dist/index.js +15 -0
  25. package/dist/links.d.ts +25 -0
  26. package/dist/links.js +60 -0
  27. package/dist/node.d.ts +5 -0
  28. package/dist/node.js +60 -0
  29. package/dist/payments.d.ts +39 -0
  30. package/dist/payments.js +232 -0
  31. package/dist/policies.d.ts +54 -0
  32. package/dist/policies.js +148 -0
  33. package/dist/requests.d.ts +103 -0
  34. package/dist/requests.js +145 -0
  35. package/dist/schedules.d.ts +111 -0
  36. package/dist/schedules.js +232 -0
  37. package/dist/store.d.ts +24 -0
  38. package/dist/store.js +19 -0
  39. package/dist/vendor/erc8021.d.ts +9 -0
  40. package/dist/vendor/erc8021.js +82 -0
  41. package/dist/vendor/fee.d.ts +3 -0
  42. package/dist/vendor/fee.js +40 -0
  43. package/dist/vendor/payee-profile.d.ts +27 -0
  44. package/dist/vendor/payee-profile.js +73 -0
  45. package/dist/vendor/request-decline.d.ts +55 -0
  46. package/dist/vendor/request-decline.js +60 -0
  47. package/dist/vendor/safe-fetch.d.ts +2 -0
  48. package/dist/vendor/safe-fetch.js +154 -0
  49. package/dist/vendor/standard-webhooks.d.ts +8 -0
  50. package/dist/vendor/standard-webhooks.js +83 -0
  51. package/dist/vendor/webhook-actions.d.ts +84 -0
  52. package/dist/vendor/webhook-actions.js +123 -0
  53. package/dist/webhooks.d.ts +88 -0
  54. package/dist/webhooks.js +113 -0
  55. package/package.json +58 -4
@@ -0,0 +1,114 @@
1
+ export declare const deployment: {
2
+ readonly version: 1;
3
+ readonly generatedBy: "scripts/build-deployments.ts, from /functions/v1/agent and chain reads. Do not edit by hand.";
4
+ readonly chain: {
5
+ readonly name: "Celo";
6
+ readonly chainId: 42220;
7
+ readonly caip2: "eip155:42220";
8
+ readonly rpc: "https://forno.celo.org";
9
+ };
10
+ readonly contracts: {
11
+ readonly RemessoExecutorV5: {
12
+ readonly address: "0x3C357af3300f383Ea49B6D6ED8e084199a92bEd8";
13
+ readonly deployBlock: 80268721;
14
+ readonly executor: "0xA351d65c15b8a342B6ECbC7f2B9eFE62B17cdb21";
15
+ readonly currentExecutorSentinel: "0x0000000000000000000000000000000000000001";
16
+ readonly feeBps: 25;
17
+ };
18
+ readonly RemessoAgentAllowance: {
19
+ readonly address: "0xA6351fAeEb097698289586C4D6188530300DB209";
20
+ readonly deployBlock: 80467202;
21
+ };
22
+ readonly ERC8004IdentityRegistry: {
23
+ readonly address: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432";
24
+ };
25
+ };
26
+ readonly tokens: readonly [{
27
+ readonly symbol: "USDT";
28
+ readonly address: "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e";
29
+ readonly decimals: 6;
30
+ readonly currency: "USD";
31
+ readonly directAllowed: true;
32
+ readonly feeCurrency: "0x0E2A3e05bc9A16F5292A6170456A710cb89C6f72";
33
+ readonly minPerRun: "1000000";
34
+ readonly maxPerRun: "1000000000";
35
+ }, {
36
+ readonly symbol: "USDC";
37
+ readonly address: "0xcebA9300f2b948710d2653dD7B07f33A8B32118C";
38
+ readonly decimals: 6;
39
+ readonly currency: "USD";
40
+ readonly directAllowed: true;
41
+ readonly feeCurrency: "0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B";
42
+ readonly minPerRun: "1000000";
43
+ readonly maxPerRun: "1000000000";
44
+ }, {
45
+ readonly symbol: "USDm";
46
+ readonly address: "0x765DE816845861e75A25fCA122bb6898B8B1282a";
47
+ readonly decimals: 18;
48
+ readonly currency: "USD";
49
+ readonly directAllowed: true;
50
+ readonly feeCurrency: "0x765DE816845861e75A25fCA122bb6898B8B1282a";
51
+ readonly minPerRun: "1000000000000000000";
52
+ readonly maxPerRun: "1000000000000000000000";
53
+ }, {
54
+ readonly symbol: "USA₮";
55
+ readonly address: "0xD2ab3C9A02DBBAB236BfEC45D1d755DF4267F771";
56
+ readonly decimals: 6;
57
+ readonly currency: "USD";
58
+ readonly directAllowed: true;
59
+ readonly feeCurrency: "0x0357EE22278c922e1D36cFe6b899269b161880C4";
60
+ readonly minPerRun: "1000000";
61
+ readonly maxPerRun: "1000000000";
62
+ }, {
63
+ readonly symbol: "wARS";
64
+ readonly address: "0x0DC4F92879B7670e5f4e4e6e3c801D229129D90D";
65
+ readonly decimals: 18;
66
+ readonly currency: "ARS";
67
+ readonly directAllowed: true;
68
+ readonly feeCurrency: null;
69
+ readonly minPerRun: "1500000000000000000000";
70
+ readonly maxPerRun: "1500000000000000000000000";
71
+ }, {
72
+ readonly symbol: "wBRL";
73
+ readonly address: "0xD76f5Faf6888e24D9F04Bf92a0c8B921FE4390e0";
74
+ readonly decimals: 18;
75
+ readonly currency: "BRL";
76
+ readonly directAllowed: true;
77
+ readonly feeCurrency: null;
78
+ readonly minPerRun: "5000000000000000000";
79
+ readonly maxPerRun: "5000000000000000000000";
80
+ }, {
81
+ readonly symbol: "wCOP";
82
+ readonly address: "0x8a1D45e102e886510e891d2Ec656a708991e2D76";
83
+ readonly decimals: 18;
84
+ readonly currency: "COP";
85
+ readonly directAllowed: true;
86
+ readonly feeCurrency: null;
87
+ readonly minPerRun: "3200000000000000000000";
88
+ readonly maxPerRun: "3200000000000000000000000";
89
+ }, {
90
+ readonly symbol: "cNGN";
91
+ readonly address: "0xF6829D7393dAe24509eb1E52eE8e572e2E271a4f";
92
+ readonly decimals: 6;
93
+ readonly currency: "NGN";
94
+ readonly directAllowed: true;
95
+ readonly feeCurrency: null;
96
+ readonly minPerRun: "1300000000";
97
+ readonly maxPerRun: "1300000000000";
98
+ }];
99
+ readonly functions: {
100
+ readonly base: "https://engaboljiqudghvzmebq.supabase.co/functions/v1";
101
+ readonly agent: "https://engaboljiqudghvzmebq.supabase.co/functions/v1/agent";
102
+ readonly "request-payment": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/request-payment";
103
+ readonly "payment-events": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/payment-events";
104
+ readonly webhooks: "https://engaboljiqudghvzmebq.supabase.co/functions/v1/webhooks";
105
+ readonly "trigger-run": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/trigger-run";
106
+ readonly "rate-service": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/rate-service";
107
+ readonly "latam-rate": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/latam-rate";
108
+ readonly "latam-route": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/latam-route";
109
+ };
110
+ readonly app: {
111
+ readonly origin: "https://remesso.xyz";
112
+ readonly mcp: "https://remesso.xyz/mcp";
113
+ };
114
+ };
@@ -0,0 +1,127 @@
1
+ // Copied from deployments/celo-mainnet.json by scripts/build-sdk.ts. Edit the original and re-run;
2
+ // `build-sdk.ts --check` fails while the two differ.
3
+ /// Celo mainnet as Remesso runs it: contracts, tokens with their per-run
4
+ /// limits, the fee, and the public endpoints.
5
+ export const deployment = {
6
+ "version": 1,
7
+ "generatedBy": "scripts/build-deployments.ts, from /functions/v1/agent and chain reads. Do not edit by hand.",
8
+ "chain": {
9
+ "name": "Celo",
10
+ "chainId": 42220,
11
+ "caip2": "eip155:42220",
12
+ "rpc": "https://forno.celo.org"
13
+ },
14
+ "contracts": {
15
+ "RemessoExecutorV5": {
16
+ "address": "0x3C357af3300f383Ea49B6D6ED8e084199a92bEd8",
17
+ "deployBlock": 80268721,
18
+ "executor": "0xA351d65c15b8a342B6ECbC7f2B9eFE62B17cdb21",
19
+ "currentExecutorSentinel": "0x0000000000000000000000000000000000000001",
20
+ "feeBps": 25
21
+ },
22
+ "RemessoAgentAllowance": {
23
+ "address": "0xA6351fAeEb097698289586C4D6188530300DB209",
24
+ "deployBlock": 80467202
25
+ },
26
+ "ERC8004IdentityRegistry": {
27
+ "address": "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432"
28
+ }
29
+ },
30
+ "tokens": [
31
+ {
32
+ "symbol": "USDT",
33
+ "address": "0x48065fbBE25f71C9282ddf5e1cD6D6A887483D5e",
34
+ "decimals": 6,
35
+ "currency": "USD",
36
+ "directAllowed": true,
37
+ "feeCurrency": "0x0E2A3e05bc9A16F5292A6170456A710cb89C6f72",
38
+ "minPerRun": "1000000",
39
+ "maxPerRun": "1000000000"
40
+ },
41
+ {
42
+ "symbol": "USDC",
43
+ "address": "0xcebA9300f2b948710d2653dD7B07f33A8B32118C",
44
+ "decimals": 6,
45
+ "currency": "USD",
46
+ "directAllowed": true,
47
+ "feeCurrency": "0x2F25deB3848C207fc8E0c34035B3Ba7fC157602B",
48
+ "minPerRun": "1000000",
49
+ "maxPerRun": "1000000000"
50
+ },
51
+ {
52
+ "symbol": "USDm",
53
+ "address": "0x765DE816845861e75A25fCA122bb6898B8B1282a",
54
+ "decimals": 18,
55
+ "currency": "USD",
56
+ "directAllowed": true,
57
+ "feeCurrency": "0x765DE816845861e75A25fCA122bb6898B8B1282a",
58
+ "minPerRun": "1000000000000000000",
59
+ "maxPerRun": "1000000000000000000000"
60
+ },
61
+ {
62
+ "symbol": "USA₮",
63
+ "address": "0xD2ab3C9A02DBBAB236BfEC45D1d755DF4267F771",
64
+ "decimals": 6,
65
+ "currency": "USD",
66
+ "directAllowed": true,
67
+ "feeCurrency": "0x0357EE22278c922e1D36cFe6b899269b161880C4",
68
+ "minPerRun": "1000000",
69
+ "maxPerRun": "1000000000"
70
+ },
71
+ {
72
+ "symbol": "wARS",
73
+ "address": "0x0DC4F92879B7670e5f4e4e6e3c801D229129D90D",
74
+ "decimals": 18,
75
+ "currency": "ARS",
76
+ "directAllowed": true,
77
+ "feeCurrency": null,
78
+ "minPerRun": "1500000000000000000000",
79
+ "maxPerRun": "1500000000000000000000000"
80
+ },
81
+ {
82
+ "symbol": "wBRL",
83
+ "address": "0xD76f5Faf6888e24D9F04Bf92a0c8B921FE4390e0",
84
+ "decimals": 18,
85
+ "currency": "BRL",
86
+ "directAllowed": true,
87
+ "feeCurrency": null,
88
+ "minPerRun": "5000000000000000000",
89
+ "maxPerRun": "5000000000000000000000"
90
+ },
91
+ {
92
+ "symbol": "wCOP",
93
+ "address": "0x8a1D45e102e886510e891d2Ec656a708991e2D76",
94
+ "decimals": 18,
95
+ "currency": "COP",
96
+ "directAllowed": true,
97
+ "feeCurrency": null,
98
+ "minPerRun": "3200000000000000000000",
99
+ "maxPerRun": "3200000000000000000000000"
100
+ },
101
+ {
102
+ "symbol": "cNGN",
103
+ "address": "0xF6829D7393dAe24509eb1E52eE8e572e2E271a4f",
104
+ "decimals": 6,
105
+ "currency": "NGN",
106
+ "directAllowed": true,
107
+ "feeCurrency": null,
108
+ "minPerRun": "1300000000",
109
+ "maxPerRun": "1300000000000"
110
+ }
111
+ ],
112
+ "functions": {
113
+ "base": "https://engaboljiqudghvzmebq.supabase.co/functions/v1",
114
+ "agent": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/agent",
115
+ "request-payment": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/request-payment",
116
+ "payment-events": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/payment-events",
117
+ "webhooks": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/webhooks",
118
+ "trigger-run": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/trigger-run",
119
+ "rate-service": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/rate-service",
120
+ "latam-rate": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/latam-rate",
121
+ "latam-route": "https://engaboljiqudghvzmebq.supabase.co/functions/v1/latam-route"
122
+ },
123
+ "app": {
124
+ "origin": "https://remesso.xyz",
125
+ "mcp": "https://remesso.xyz/mcp"
126
+ }
127
+ };
@@ -0,0 +1,16 @@
1
+ export { createRemesso, type Remesso, type RemessoOptions } from "./client.js";
2
+ export { RemessoError, type RemessoErrorCode } from "./errors.js";
3
+ export { ALLOWANCE, CHAIN_ID, CURRENT_EXECUTOR, deployment, EXECUTOR, FEE_BPS, findToken, formatAmount, REGISTRY, runLimits, type Token, token, toUnits, } from "./deployment.js";
4
+ export { feeOf, grossFor, netOf } from "./vendor/fee.js";
5
+ export { allowanceAbi, erc20Abi, executorAbi, registryAbi } from "./abi.js";
6
+ export { ATTRIBUTION, attributionFor } from "./attribution.js";
7
+ export { CADENCES, type Cadence, type CreatedSchedule, type CreateScheduleInput, type Schedule } from "./schedules.js";
8
+ export { memo32, type PayInput, type PaymentResult } from "./payments.js";
9
+ export type { CreatePolicyInput, Policy } from "./policies.js";
10
+ export type { CreateRequestInput, RequestState, RequestStatus, RequestSummary } from "./requests.js";
11
+ export type { EventKind, EventQuery, PaymentEvent } from "./events.js";
12
+ export { parseWebhook, verifyWebhook, webhookHandler, type WebhookHandlerOptions, type WebhookMessage, type WebhookType, } from "./webhooks.js";
13
+ export type { FoundAgent } from "./agents.js";
14
+ export type { PayeeProfile } from "./vendor/payee-profile.js";
15
+ export { type PayLink, type PayLinkInput, parsePayLink, payLink } from "./links.js";
16
+ export { memoryStore, type PaymentRecord, type PaymentStore } from "./store.js";
package/dist/index.js ADDED
@@ -0,0 +1,15 @@
1
+ /// remesso-sdk: recurring and agent payments on Celo.
2
+ ///
3
+ /// Celo mainnet only: there is no testnet. The contracts are live and have
4
+ /// not been audited by a person, so start with small amounts.
5
+ export { createRemesso } from "./client.js";
6
+ export { RemessoError } from "./errors.js";
7
+ export { ALLOWANCE, CHAIN_ID, CURRENT_EXECUTOR, deployment, EXECUTOR, FEE_BPS, findToken, formatAmount, REGISTRY, runLimits, token, toUnits, } from "./deployment.js";
8
+ export { feeOf, grossFor, netOf } from "./vendor/fee.js";
9
+ export { allowanceAbi, erc20Abi, executorAbi, registryAbi } from "./abi.js";
10
+ export { ATTRIBUTION, attributionFor } from "./attribution.js";
11
+ export { CADENCES } from "./schedules.js";
12
+ export { memo32 } from "./payments.js";
13
+ export { parseWebhook, verifyWebhook, webhookHandler, } from "./webhooks.js";
14
+ export { parsePayLink, payLink } from "./links.js";
15
+ export { memoryStore } from "./store.js";
@@ -0,0 +1,25 @@
1
+ export type PayLinkInput = {
2
+ to: string;
3
+ /** Who is asking, shown on the form. */
4
+ from?: string;
5
+ /** What the recipient should receive per payment, decimal. */
6
+ amount?: string;
7
+ token?: string;
8
+ every?: "week" | "fortnight" | "month" | "quarter";
9
+ runs?: number;
10
+ note?: string;
11
+ /** The payment request this link answers. */
12
+ request?: string;
13
+ };
14
+ export type PayLink = {
15
+ to?: `0x${string}`;
16
+ from?: string;
17
+ amount?: string;
18
+ token?: string;
19
+ intervalSeconds?: number;
20
+ runs?: number;
21
+ note?: string;
22
+ request?: string;
23
+ };
24
+ export declare function payLink(p: PayLinkInput, origin?: string): string;
25
+ export declare function parsePayLink(urlOrQuery: string): PayLink;
package/dist/links.js ADDED
@@ -0,0 +1,60 @@
1
+ /// A link that says "pay me here", and the parser that reads one. Ported from
2
+ /// `web/lib/payLink.ts`, which the app reads links with.
3
+ ///
4
+ /// A link fills in a form. It can't create a schedule, approve an allowance or
5
+ /// sign anything: the payer reviews every field and signs in their own wallet,
6
+ /// and the form says a link filled it. Everything is validated, not trusted:
7
+ /// a link is input from a stranger.
8
+ import { isAddress } from "viem";
9
+ import { deployment, findToken } from "./deployment.js";
10
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
11
+ /// The cadences the form's picker offers. Anything else is dropped.
12
+ const CADENCE = {
13
+ week: 604_800, weekly: 604_800,
14
+ fortnight: 1_209_600, fortnightly: 1_209_600,
15
+ month: 2_592_000, monthly: 2_592_000,
16
+ quarter: 7_776_000, quarterly: 7_776_000,
17
+ };
18
+ /// The link that opens the payer's Remesso form prefilled.
19
+ export function payLink(p, origin = deployment.app.origin) {
20
+ const q = new URLSearchParams();
21
+ q.set("to", p.to);
22
+ const token = p.token ? findToken(p.token)?.symbol ?? p.token : undefined;
23
+ for (const [k, v] of Object.entries({ from: p.from, amount: p.amount, token, every: p.every, runs: p.runs, note: p.note, req: p.request })) {
24
+ if (v != null && v !== "")
25
+ q.set(k, String(v));
26
+ }
27
+ return `${origin.replace(/\/+$/, "")}/schedules/new?${q.toString()}`;
28
+ }
29
+ /// What a link says, keeping only what validates.
30
+ export function parsePayLink(urlOrQuery) {
31
+ const s = String(urlOrQuery);
32
+ const q = new URLSearchParams(s.includes("?") ? s.slice(s.indexOf("?") + 1) : s);
33
+ const out = {};
34
+ const to = (q.get("to") ?? "").trim();
35
+ if (isAddress(to))
36
+ out.to = to;
37
+ const from = (q.get("from") ?? q.get("name") ?? "").trim();
38
+ if (from)
39
+ out.from = from.slice(0, 40);
40
+ const note = (q.get("note") ?? "").trim();
41
+ if (note)
42
+ out.note = note.slice(0, 120);
43
+ const amount = (q.get("amount") ?? "").trim();
44
+ if (/^\d{1,12}(\.\d{1,18})?$/.test(amount) && Number(amount) > 0)
45
+ out.amount = amount;
46
+ const token = findToken((q.get("token") ?? "").trim());
47
+ if (token && token.directAllowed)
48
+ out.token = token.symbol;
49
+ const every = (q.get("every") ?? "").trim().toLowerCase();
50
+ const seconds = CADENCE[every] ?? (/^\d+$/.test(every) ? Number(every) : NaN);
51
+ if (Object.values(CADENCE).includes(seconds))
52
+ out.intervalSeconds = seconds;
53
+ const runs = (q.get("runs") ?? "").trim();
54
+ if (/^\d{1,4}$/.test(runs) && Number(runs) > 0)
55
+ out.runs = Number(runs);
56
+ const req = (q.get("req") ?? "").trim();
57
+ if (UUID.test(req))
58
+ out.request = req.toLowerCase();
59
+ return out;
60
+ }
package/dist/node.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import { type PaymentStore } from "./store.js";
3
+ export { safeFetchText } from "./vendor/safe-fetch.js";
4
+ export declare function fileStore(path?: string): PaymentStore;
5
+ export declare function toNodeListener(handler: (req: Request) => Promise<Response>): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
package/dist/node.js ADDED
@@ -0,0 +1,60 @@
1
+ /// Node-only parts: a payment store on disk, the safe fetch for remote
2
+ /// registration files, and an adapter from the fetch-style webhook handler to
3
+ /// `http.createServer` or Express.
4
+ import { chmodSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
5
+ import { homedir } from "node:os";
6
+ import { dirname, join } from "node:path";
7
+ import { upsert } from "./store.js";
8
+ export { safeFetchText } from "./vendor/safe-fetch.js";
9
+ /// Agent payment records in a JSON file (mode 0600), so a retry after a
10
+ /// restart still pays once. Default `~/.remesso-sdk/payments.json`. One
11
+ /// process per file: it isn't locked.
12
+ export function fileStore(path = join(homedir(), ".remesso-sdk", "payments.json")) {
13
+ const load = () => {
14
+ try {
15
+ return JSON.parse(readFileSync(path, "utf8")).payments ?? [];
16
+ }
17
+ catch {
18
+ return [];
19
+ }
20
+ };
21
+ return {
22
+ byKey: async (key, deployment) => load().reverse().find((p) => p.key === key && p.deployment === deployment),
23
+ since: async (since) => load().filter((p) => Date.parse(p.at) > since),
24
+ save: async (rec) => {
25
+ mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
26
+ const tmp = `${path}.${process.pid}.tmp`;
27
+ writeFileSync(tmp, JSON.stringify({ version: 1, payments: upsert(load(), rec) }, null, 2), { mode: 0o600 });
28
+ renameSync(tmp, path); // whole or not at all: a crash mid-write keeps the old file
29
+ chmodSync(path, 0o600);
30
+ },
31
+ };
32
+ }
33
+ /// `http.createServer(toNodeListener(webhookHandler({...})))`, or as Express
34
+ /// middleware on a route: it reads the raw body itself, so mount it before
35
+ /// any JSON body parser.
36
+ export function toNodeListener(handler) {
37
+ return async (req, res) => {
38
+ try {
39
+ const chunks = [];
40
+ for await (const c of req)
41
+ chunks.push(c);
42
+ const headers = new Headers();
43
+ for (const [k, v] of Object.entries(req.headers))
44
+ if (typeof v === "string")
45
+ headers.set(k, v);
46
+ const url = `http://${req.headers.host ?? "localhost"}${req.url ?? "/"}`;
47
+ const out = await handler(new Request(url, {
48
+ method: req.method,
49
+ headers,
50
+ body: req.method === "GET" || req.method === "HEAD" ? undefined : Buffer.concat(chunks),
51
+ }));
52
+ res.writeHead(out.status, Object.fromEntries(out.headers));
53
+ res.end(Buffer.from(await out.arrayBuffer()));
54
+ }
55
+ catch (e) {
56
+ res.writeHead(500, { "content-type": "application/json" });
57
+ res.end(JSON.stringify({ error: e.message }));
58
+ }
59
+ };
60
+ }
@@ -0,0 +1,39 @@
1
+ import { type Address, type Hex } from "viem";
2
+ import { type Ctx } from "./context.js";
3
+ import type { Policies } from "./policies.js";
4
+ export type PayInput = {
5
+ to: string;
6
+ /** Decimal, in the policy token's units: "0.10". */
7
+ amount: string;
8
+ /** Symbol or address. Default: the token of the policy used. */
9
+ token?: string;
10
+ /** Which policy to pay under. Default: an active one for the token that can cover the amount. */
11
+ policyId?: bigint | number | string;
12
+ /** Up to 32 bytes, recorded on-chain in the Paid event. A request's reference goes here. */
13
+ memo?: string;
14
+ /**
15
+ * One per payment you intend (an invoice or request id is ideal). A retry with the
16
+ * same key reports the first payment's outcome and never pays twice.
17
+ */
18
+ idempotencyKey?: string;
19
+ /** Pay even though an identical payment went out in the last ten minutes. */
20
+ allowRepeat?: boolean;
21
+ /** How long to wait for the receipt before answering "pending". Default 45s. */
22
+ waitMs?: number;
23
+ };
24
+ export type PaymentResult = {
25
+ status: "confirmed" | "pending";
26
+ hash: Hex;
27
+ policyId: bigint;
28
+ to: Address;
29
+ amount: bigint;
30
+ token: Address;
31
+ /** "1.5 USDT" */
32
+ sent: string;
33
+ explorer: string;
34
+ /** True when this key had already paid and nothing new was sent. */
35
+ repeat?: boolean;
36
+ };
37
+ export declare const DEPLOYMENT: string;
38
+ export declare function memo32(memo?: string): Hex;
39
+ export declare function makePay(ctx: Ctx, policies: Policies): (input: PayInput) => Promise<PaymentResult>;