dnsofmoney 0.4.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/README.md +110 -0
- package/dist/client.d.ts +100 -0
- package/dist/client.js +357 -0
- package/dist/exceptions.d.ts +26 -0
- package/dist/exceptions.js +56 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +17 -0
- package/dist/models.d.ts +108 -0
- package/dist/models.js +2 -0
- package/package.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# dnsofmoney — TypeScript SDK
|
|
2
|
+
|
|
3
|
+
Resolve, register, send to, and check availability of `pay:` aliases using the DNS of Money API.
|
|
4
|
+
|
|
5
|
+
**No external dependencies** — uses only the built-in `fetch()` API.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install dnsofmoney
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
> Not yet on npm — coming soon. For now, clone the repo and build from source:
|
|
14
|
+
> ```bash
|
|
15
|
+
> cd sdk/typescript && npm install && npm run build
|
|
16
|
+
> ```
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
### Resolve a pay: alias
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { resolve } from "dnsofmoney";
|
|
24
|
+
|
|
25
|
+
const result = await resolve("pay:vendor.alpha");
|
|
26
|
+
console.log(result.entity?.display_name);
|
|
27
|
+
console.log(result.endpoints[0].rail);
|
|
28
|
+
console.log(result.resolution_status);
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Register a pay: alias
|
|
32
|
+
|
|
33
|
+
```typescript
|
|
34
|
+
import { register } from "dnsofmoney";
|
|
35
|
+
|
|
36
|
+
const result = await register(
|
|
37
|
+
"pay:your.name",
|
|
38
|
+
"Your Name",
|
|
39
|
+
"fednow",
|
|
40
|
+
"fas_live_...",
|
|
41
|
+
);
|
|
42
|
+
console.log(result.alias_name);
|
|
43
|
+
console.log(result.registration_number);
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Check availability
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
import { checkAvailability } from "dnsofmoney";
|
|
50
|
+
|
|
51
|
+
const available = await checkAvailability("pay:desired.name");
|
|
52
|
+
console.log(available ? "Available!" : "Taken.");
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Preview a payment (dry-run, no API key)
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
import { sendPreview } from "dnsofmoney";
|
|
59
|
+
|
|
60
|
+
const preview = await sendPreview("pay:vendor.alpha");
|
|
61
|
+
console.log(preview.resolved, preview.rail, preview.destination_address);
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### Send money to a pay: alias
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
import { send } from "dnsofmoney";
|
|
68
|
+
|
|
69
|
+
const receipt = await send("pay:vendor.alpha", 5.0, "fas_live_...", {
|
|
70
|
+
currency: "XRP",
|
|
71
|
+
memo: "invoice 1234",
|
|
72
|
+
// idempotencyKey auto-generated if omitted — safe to retry
|
|
73
|
+
});
|
|
74
|
+
console.log(receipt.status, receipt.rail, receipt.tx_hash);
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### Client instance (reuse connections)
|
|
78
|
+
|
|
79
|
+
```typescript
|
|
80
|
+
import { DNSOfMoneyClient } from "dnsofmoney";
|
|
81
|
+
|
|
82
|
+
const client = new DNSOfMoneyClient({ apiKey: "fas_live_..." });
|
|
83
|
+
const result = await client.resolve("pay:vendor.alpha");
|
|
84
|
+
const available = await client.checkAvailability("pay:new.name");
|
|
85
|
+
const preview = await client.sendPreview("pay:vendor.alpha");
|
|
86
|
+
const receipt = await client.send("pay:vendor.alpha", 5.0, { currency: "XRP" });
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
## Error Handling
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
import { resolve, AliasNotFoundError, AuthenticationError } from "dnsofmoney";
|
|
93
|
+
|
|
94
|
+
try {
|
|
95
|
+
const result = await resolve("pay:nonexistent.alias");
|
|
96
|
+
} catch (err) {
|
|
97
|
+
if (err instanceof AliasNotFoundError) {
|
|
98
|
+
console.log("Alias does not exist");
|
|
99
|
+
} else if (err instanceof AuthenticationError) {
|
|
100
|
+
console.log("Invalid API key");
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Links
|
|
106
|
+
|
|
107
|
+
- [Full documentation](https://docs.dnsofmoney.com)
|
|
108
|
+
- [FAS-1 specification](https://github.com/dnsofmoney/dns-of-money/blob/main/docs/FAS-1-spec.md)
|
|
109
|
+
- [Examples](https://github.com/dnsofmoney/dns-of-money/tree/main/examples)
|
|
110
|
+
- [JSON schemas](https://github.com/dnsofmoney/dns-of-money/tree/main/schemas)
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* DNS of Money SDK — TypeScript client.
|
|
3
|
+
*
|
|
4
|
+
* Resolve, register, and check availability of pay: aliases.
|
|
5
|
+
* Uses only the built-in fetch() API — no external dependencies.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* import { DNSOfMoneyClient } from "dnsofmoney";
|
|
9
|
+
*
|
|
10
|
+
* const client = new DNSOfMoneyClient({ apiKey: "fas_live_..." });
|
|
11
|
+
* const result = await client.resolve("pay:vendor.alpha");
|
|
12
|
+
*/
|
|
13
|
+
import type { RegistrationResponse, ResolutionResponse, SendOptions, SendPreview, SendResult } from "./models";
|
|
14
|
+
export interface ClientOptions {
|
|
15
|
+
apiKey?: string;
|
|
16
|
+
baseUrl?: string;
|
|
17
|
+
timeout?: number;
|
|
18
|
+
}
|
|
19
|
+
export declare class DNSOfMoneyClient {
|
|
20
|
+
private readonly apiKey?;
|
|
21
|
+
private readonly baseUrl;
|
|
22
|
+
private readonly timeout;
|
|
23
|
+
constructor(options?: ClientOptions);
|
|
24
|
+
/**
|
|
25
|
+
* Resolve a pay: alias to payment credentials.
|
|
26
|
+
*
|
|
27
|
+
* No API key required for public aliases. Authenticated callers
|
|
28
|
+
* receive higher-tier responses with additional fields.
|
|
29
|
+
*
|
|
30
|
+
* @param aliasUri - A FAS-1 pay: URI (e.g., "pay:vendor.alpha").
|
|
31
|
+
* @throws {AliasNotFoundError} If the alias does not exist.
|
|
32
|
+
*/
|
|
33
|
+
resolve(aliasUri: string): Promise<ResolutionResponse>;
|
|
34
|
+
/**
|
|
35
|
+
* Register a new pay: alias.
|
|
36
|
+
*
|
|
37
|
+
* Requires API key. The alias must not already be taken or reserved.
|
|
38
|
+
*
|
|
39
|
+
* @throws {AliasTakenError} If the alias is already registered.
|
|
40
|
+
* @throws {CapReachedError} If the founding tier cap has been reached.
|
|
41
|
+
* @throws {AuthenticationError} If the API key is missing or invalid.
|
|
42
|
+
*/
|
|
43
|
+
register(aliasName: string, displayName: string, preferredRail: string, extra?: Record<string, unknown>): Promise<RegistrationResponse>;
|
|
44
|
+
/**
|
|
45
|
+
* Check if a pay: alias is available to register.
|
|
46
|
+
*
|
|
47
|
+
* No API key required.
|
|
48
|
+
*
|
|
49
|
+
* @returns true if available, false if taken or reserved.
|
|
50
|
+
*/
|
|
51
|
+
checkAvailability(aliasName: string): Promise<boolean>;
|
|
52
|
+
/**
|
|
53
|
+
* Preview where a payment would go without executing.
|
|
54
|
+
*
|
|
55
|
+
* No API key required. Returns the destination address (masked),
|
|
56
|
+
* rail, fee estimate, and identity info.
|
|
57
|
+
*
|
|
58
|
+
* @param alias - A pay: alias (e.g., "pay:vendor.alpha") or bare name ("vendor.alpha").
|
|
59
|
+
* @throws {AliasNotFoundError} If the alias does not exist.
|
|
60
|
+
*/
|
|
61
|
+
sendPreview(alias: string): Promise<SendPreview>;
|
|
62
|
+
/**
|
|
63
|
+
* Send money to a pay: alias.
|
|
64
|
+
*
|
|
65
|
+
* Requires API key. Resolves the alias globally, routes to the best
|
|
66
|
+
* payment rail, generates an ISO 20022 message, and executes settlement.
|
|
67
|
+
*
|
|
68
|
+
* @param alias - Target pay: alias (e.g., "pay:vendor.alpha").
|
|
69
|
+
* @param amount - Amount in currency units.
|
|
70
|
+
* @param options - Optional currency, memo, and idempotencyKey. An
|
|
71
|
+
* idempotency key is auto-generated if not provided.
|
|
72
|
+
* @throws {AliasNotFoundError} If the alias does not exist.
|
|
73
|
+
* @throws {AuthenticationError} If the API key is missing or invalid.
|
|
74
|
+
*/
|
|
75
|
+
send(alias: string, amount: number, options?: SendOptions): Promise<SendResult>;
|
|
76
|
+
private headers;
|
|
77
|
+
private get;
|
|
78
|
+
private post;
|
|
79
|
+
private handleResponse;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a pay: alias. See DNSOfMoneyClient.resolve for full docs.
|
|
83
|
+
*/
|
|
84
|
+
export declare function resolve(aliasUri: string, apiKey?: string, baseUrl?: string): Promise<ResolutionResponse>;
|
|
85
|
+
/**
|
|
86
|
+
* Register a pay: alias. See DNSOfMoneyClient.register for full docs.
|
|
87
|
+
*/
|
|
88
|
+
export declare function register(aliasName: string, displayName: string, preferredRail: string, apiKey: string, baseUrl?: string, extra?: Record<string, unknown>): Promise<RegistrationResponse>;
|
|
89
|
+
/**
|
|
90
|
+
* Check alias availability. See DNSOfMoneyClient.checkAvailability for full docs.
|
|
91
|
+
*/
|
|
92
|
+
export declare function checkAvailability(aliasName: string, baseUrl?: string): Promise<boolean>;
|
|
93
|
+
/**
|
|
94
|
+
* Preview a send-to-alias payment. See DNSOfMoneyClient.sendPreview for full docs.
|
|
95
|
+
*/
|
|
96
|
+
export declare function sendPreview(alias: string, baseUrl?: string): Promise<SendPreview>;
|
|
97
|
+
/**
|
|
98
|
+
* Send money to a pay: alias. See DNSOfMoneyClient.send for full docs.
|
|
99
|
+
*/
|
|
100
|
+
export declare function send(alias: string, amount: number, apiKey: string, options?: SendOptions, baseUrl?: string): Promise<SendResult>;
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,357 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DNS of Money SDK — TypeScript client.
|
|
4
|
+
*
|
|
5
|
+
* Resolve, register, and check availability of pay: aliases.
|
|
6
|
+
* Uses only the built-in fetch() API — no external dependencies.
|
|
7
|
+
*
|
|
8
|
+
* Usage:
|
|
9
|
+
* import { DNSOfMoneyClient } from "dnsofmoney";
|
|
10
|
+
*
|
|
11
|
+
* const client = new DNSOfMoneyClient({ apiKey: "fas_live_..." });
|
|
12
|
+
* const result = await client.resolve("pay:vendor.alpha");
|
|
13
|
+
*/
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.DNSOfMoneyClient = void 0;
|
|
16
|
+
exports.resolve = resolve;
|
|
17
|
+
exports.register = register;
|
|
18
|
+
exports.checkAvailability = checkAvailability;
|
|
19
|
+
exports.sendPreview = sendPreview;
|
|
20
|
+
exports.send = send;
|
|
21
|
+
const exceptions_1 = require("./exceptions");
|
|
22
|
+
const DEFAULT_BASE_URL = "https://api.dnsofmoney.com";
|
|
23
|
+
class DNSOfMoneyClient {
|
|
24
|
+
constructor(options = {}) {
|
|
25
|
+
this.apiKey = options.apiKey;
|
|
26
|
+
this.baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
27
|
+
this.timeout = options.timeout ?? 10000;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a pay: alias to payment credentials.
|
|
31
|
+
*
|
|
32
|
+
* No API key required for public aliases. Authenticated callers
|
|
33
|
+
* receive higher-tier responses with additional fields.
|
|
34
|
+
*
|
|
35
|
+
* @param aliasUri - A FAS-1 pay: URI (e.g., "pay:vendor.alpha").
|
|
36
|
+
* @throws {AliasNotFoundError} If the alias does not exist.
|
|
37
|
+
*/
|
|
38
|
+
async resolve(aliasUri) {
|
|
39
|
+
const raw = await this.get(`/resolve/${aliasUri}`);
|
|
40
|
+
const data = raw.success !== undefined ? (raw.data ?? raw) : raw;
|
|
41
|
+
return parseResolution(data);
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Register a new pay: alias.
|
|
45
|
+
*
|
|
46
|
+
* Requires API key. The alias must not already be taken or reserved.
|
|
47
|
+
*
|
|
48
|
+
* @throws {AliasTakenError} If the alias is already registered.
|
|
49
|
+
* @throws {CapReachedError} If the founding tier cap has been reached.
|
|
50
|
+
* @throws {AuthenticationError} If the API key is missing or invalid.
|
|
51
|
+
*/
|
|
52
|
+
async register(aliasName, displayName, preferredRail, extra = {}) {
|
|
53
|
+
const body = {
|
|
54
|
+
alias_name: aliasName,
|
|
55
|
+
display_name: displayName,
|
|
56
|
+
preferred_rail: preferredRail,
|
|
57
|
+
...extra,
|
|
58
|
+
};
|
|
59
|
+
const data = await this.post("/v1/aliases", body);
|
|
60
|
+
return {
|
|
61
|
+
alias_name: data.alias_name ?? aliasName,
|
|
62
|
+
registration_number: data.registration_number,
|
|
63
|
+
anchor_status: data.anchor_status,
|
|
64
|
+
proof: data.proof,
|
|
65
|
+
created_at: data.created_at,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Check if a pay: alias is available to register.
|
|
70
|
+
*
|
|
71
|
+
* No API key required.
|
|
72
|
+
*
|
|
73
|
+
* @returns true if available, false if taken or reserved.
|
|
74
|
+
*/
|
|
75
|
+
async checkAvailability(aliasName) {
|
|
76
|
+
const data = await this.get(`/v1/aliases/check/${aliasName}`);
|
|
77
|
+
return data.status === "available";
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Preview where a payment would go without executing.
|
|
81
|
+
*
|
|
82
|
+
* No API key required. Returns the destination address (masked),
|
|
83
|
+
* rail, fee estimate, and identity info.
|
|
84
|
+
*
|
|
85
|
+
* @param alias - A pay: alias (e.g., "pay:vendor.alpha") or bare name ("vendor.alpha").
|
|
86
|
+
* @throws {AliasNotFoundError} If the alias does not exist.
|
|
87
|
+
*/
|
|
88
|
+
async sendPreview(alias) {
|
|
89
|
+
const data = await this.get(`/api/v1/send/preview/${alias}`);
|
|
90
|
+
return {
|
|
91
|
+
alias: data.alias ?? alias,
|
|
92
|
+
resolved: data.resolved ?? false,
|
|
93
|
+
destination_address: data.destination_address,
|
|
94
|
+
display_name: data.display_name,
|
|
95
|
+
rail: data.rail,
|
|
96
|
+
currency: data.currency ?? "USD",
|
|
97
|
+
fee_estimate: data.fee_estimate,
|
|
98
|
+
identity: data.identity,
|
|
99
|
+
};
|
|
100
|
+
}
|
|
101
|
+
/**
|
|
102
|
+
* Send money to a pay: alias.
|
|
103
|
+
*
|
|
104
|
+
* Requires API key. Resolves the alias globally, routes to the best
|
|
105
|
+
* payment rail, generates an ISO 20022 message, and executes settlement.
|
|
106
|
+
*
|
|
107
|
+
* @param alias - Target pay: alias (e.g., "pay:vendor.alpha").
|
|
108
|
+
* @param amount - Amount in currency units.
|
|
109
|
+
* @param options - Optional currency, memo, and idempotencyKey. An
|
|
110
|
+
* idempotency key is auto-generated if not provided.
|
|
111
|
+
* @throws {AliasNotFoundError} If the alias does not exist.
|
|
112
|
+
* @throws {AuthenticationError} If the API key is missing or invalid.
|
|
113
|
+
*/
|
|
114
|
+
async send(alias, amount, options = {}) {
|
|
115
|
+
const currency = options.currency ?? "USD";
|
|
116
|
+
const body = {
|
|
117
|
+
alias,
|
|
118
|
+
amount,
|
|
119
|
+
currency,
|
|
120
|
+
idempotency_key: options.idempotencyKey ?? generateIdempotencyKey(),
|
|
121
|
+
};
|
|
122
|
+
if (options.memo !== undefined) {
|
|
123
|
+
body.memo = options.memo;
|
|
124
|
+
}
|
|
125
|
+
const data = await this.post("/api/v1/send", body);
|
|
126
|
+
return {
|
|
127
|
+
transaction_id: data.transaction_id ?? "",
|
|
128
|
+
status: data.status ?? "",
|
|
129
|
+
alias: data.alias ?? alias,
|
|
130
|
+
amount: data.amount ?? amount,
|
|
131
|
+
currency: data.currency ?? currency,
|
|
132
|
+
rail: data.rail ?? "",
|
|
133
|
+
tx_hash: data.tx_hash,
|
|
134
|
+
settle_time_seconds: data.settle_time_seconds,
|
|
135
|
+
memo: data.memo,
|
|
136
|
+
created_at: data.created_at,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
// ── Internal HTTP helpers ─────────────────────────────────────────────
|
|
140
|
+
headers() {
|
|
141
|
+
const h = { Accept: "application/json" };
|
|
142
|
+
if (this.apiKey) {
|
|
143
|
+
h["X-API-Key"] = this.apiKey;
|
|
144
|
+
}
|
|
145
|
+
return h;
|
|
146
|
+
}
|
|
147
|
+
async get(path) {
|
|
148
|
+
const controller = new AbortController();
|
|
149
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
150
|
+
try {
|
|
151
|
+
const resp = await fetch(`${this.baseUrl}${path}`, {
|
|
152
|
+
method: "GET",
|
|
153
|
+
headers: this.headers(),
|
|
154
|
+
signal: controller.signal,
|
|
155
|
+
});
|
|
156
|
+
return this.handleResponse(resp);
|
|
157
|
+
}
|
|
158
|
+
finally {
|
|
159
|
+
clearTimeout(timer);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
async post(path, body) {
|
|
163
|
+
const controller = new AbortController();
|
|
164
|
+
const timer = setTimeout(() => controller.abort(), this.timeout);
|
|
165
|
+
try {
|
|
166
|
+
const resp = await fetch(`${this.baseUrl}${path}`, {
|
|
167
|
+
method: "POST",
|
|
168
|
+
headers: { ...this.headers(), "Content-Type": "application/json" },
|
|
169
|
+
body: JSON.stringify(body),
|
|
170
|
+
signal: controller.signal,
|
|
171
|
+
});
|
|
172
|
+
return this.handleResponse(resp);
|
|
173
|
+
}
|
|
174
|
+
finally {
|
|
175
|
+
clearTimeout(timer);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
async handleResponse(resp) {
|
|
179
|
+
if (resp.ok) {
|
|
180
|
+
return resp.json();
|
|
181
|
+
}
|
|
182
|
+
let body = {};
|
|
183
|
+
try {
|
|
184
|
+
body = await resp.json();
|
|
185
|
+
}
|
|
186
|
+
catch {
|
|
187
|
+
// non-JSON error body — ignore
|
|
188
|
+
}
|
|
189
|
+
const errorCode = body.error_code ?? "";
|
|
190
|
+
const detail = body.detail ?? "";
|
|
191
|
+
if (resp.status === 401)
|
|
192
|
+
throw new exceptions_1.AuthenticationError();
|
|
193
|
+
if (resp.status === 404)
|
|
194
|
+
throw new exceptions_1.AliasNotFoundError(detail || "unknown alias");
|
|
195
|
+
if (resp.status === 409) {
|
|
196
|
+
if (errorCode === "CAP_EXCEEDED")
|
|
197
|
+
throw new exceptions_1.CapReachedError();
|
|
198
|
+
throw new exceptions_1.AliasTakenError(detail || "alias taken");
|
|
199
|
+
}
|
|
200
|
+
if (resp.status === 429) {
|
|
201
|
+
throw new exceptions_1.RateLimitError(body.retry_after);
|
|
202
|
+
}
|
|
203
|
+
throw new exceptions_1.DNSOfMoneyError(`HTTP ${resp.status}: ${resp.statusText}`, resp.status);
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
exports.DNSOfMoneyClient = DNSOfMoneyClient;
|
|
207
|
+
// ── Helpers ────────────────────────────────────────────────────────────────
|
|
208
|
+
/**
|
|
209
|
+
* Generate a unique idempotency key for a send. Prefers crypto.randomUUID
|
|
210
|
+
* (Node 19+, all modern browsers); falls back to a timestamp+random hex token.
|
|
211
|
+
*/
|
|
212
|
+
function generateIdempotencyKey() {
|
|
213
|
+
const c = globalThis.crypto;
|
|
214
|
+
if (c?.randomUUID) {
|
|
215
|
+
return `sdk-${c.randomUUID()}`;
|
|
216
|
+
}
|
|
217
|
+
const rand = Math.random().toString(16).slice(2);
|
|
218
|
+
return `sdk-${Date.now().toString(16)}${rand}`;
|
|
219
|
+
}
|
|
220
|
+
// ── Module-level convenience functions ────────────────────────────────────
|
|
221
|
+
/**
|
|
222
|
+
* Resolve a pay: alias. See DNSOfMoneyClient.resolve for full docs.
|
|
223
|
+
*/
|
|
224
|
+
async function resolve(aliasUri, apiKey, baseUrl = DEFAULT_BASE_URL) {
|
|
225
|
+
return new DNSOfMoneyClient({ apiKey, baseUrl }).resolve(aliasUri);
|
|
226
|
+
}
|
|
227
|
+
/**
|
|
228
|
+
* Register a pay: alias. See DNSOfMoneyClient.register for full docs.
|
|
229
|
+
*/
|
|
230
|
+
async function register(aliasName, displayName, preferredRail, apiKey, baseUrl = DEFAULT_BASE_URL, extra = {}) {
|
|
231
|
+
return new DNSOfMoneyClient({ apiKey, baseUrl }).register(aliasName, displayName, preferredRail, extra);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Check alias availability. See DNSOfMoneyClient.checkAvailability for full docs.
|
|
235
|
+
*/
|
|
236
|
+
async function checkAvailability(aliasName, baseUrl = DEFAULT_BASE_URL) {
|
|
237
|
+
return new DNSOfMoneyClient({ baseUrl }).checkAvailability(aliasName);
|
|
238
|
+
}
|
|
239
|
+
/**
|
|
240
|
+
* Preview a send-to-alias payment. See DNSOfMoneyClient.sendPreview for full docs.
|
|
241
|
+
*/
|
|
242
|
+
async function sendPreview(alias, baseUrl = DEFAULT_BASE_URL) {
|
|
243
|
+
return new DNSOfMoneyClient({ baseUrl }).sendPreview(alias);
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Send money to a pay: alias. See DNSOfMoneyClient.send for full docs.
|
|
247
|
+
*/
|
|
248
|
+
async function send(alias, amount, apiKey, options = {}, baseUrl = DEFAULT_BASE_URL) {
|
|
249
|
+
return new DNSOfMoneyClient({ apiKey, baseUrl }).send(alias, amount, options);
|
|
250
|
+
}
|
|
251
|
+
// ── Response parsing ──────────────────────────────────────────────────────
|
|
252
|
+
function parseResolution(data) {
|
|
253
|
+
// Entity — may be nested object or top-level fields
|
|
254
|
+
let entity;
|
|
255
|
+
if (data.entity) {
|
|
256
|
+
entity = {
|
|
257
|
+
display_name: data.entity.display_name ?? "",
|
|
258
|
+
entity_type: data.entity.entity_type,
|
|
259
|
+
jurisdiction: data.entity.jurisdiction,
|
|
260
|
+
kyc_status: data.entity.kyc_status,
|
|
261
|
+
};
|
|
262
|
+
}
|
|
263
|
+
else if (data.display_name) {
|
|
264
|
+
entity = {
|
|
265
|
+
display_name: data.display_name ?? "",
|
|
266
|
+
entity_type: data.entity_type,
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
// Endpoints — handle both flat array and preferred_endpoint + fallback
|
|
270
|
+
const endpoints = [];
|
|
271
|
+
if (data.preferred_endpoint) {
|
|
272
|
+
const ep = data.preferred_endpoint;
|
|
273
|
+
endpoints.push({
|
|
274
|
+
rail: ep.rail_type ?? ep.rail ?? "",
|
|
275
|
+
currency: ep.currency ?? "USD",
|
|
276
|
+
address: ep.address,
|
|
277
|
+
priority: ep.priority ?? 1,
|
|
278
|
+
fee_estimate: ep.fee_estimate,
|
|
279
|
+
settlement_latency: ep.settlement_latency,
|
|
280
|
+
routing_metadata: ep.routing_metadata,
|
|
281
|
+
});
|
|
282
|
+
for (const fb of data.fallback_endpoints ?? []) {
|
|
283
|
+
endpoints.push({
|
|
284
|
+
rail: fb.rail_type ?? fb.rail ?? "",
|
|
285
|
+
currency: fb.currency ?? "USD",
|
|
286
|
+
address: fb.address,
|
|
287
|
+
priority: fb.priority ?? 2,
|
|
288
|
+
fee_estimate: fb.fee_estimate,
|
|
289
|
+
settlement_latency: fb.settlement_latency,
|
|
290
|
+
routing_metadata: fb.routing_metadata,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
else {
|
|
295
|
+
for (const ep of data.endpoints ?? []) {
|
|
296
|
+
endpoints.push({
|
|
297
|
+
rail: ep.rail ?? "",
|
|
298
|
+
currency: ep.currency ?? "USD",
|
|
299
|
+
address: ep.address,
|
|
300
|
+
priority: ep.priority ?? 1,
|
|
301
|
+
fee_estimate: ep.fee_estimate,
|
|
302
|
+
settlement_latency: ep.settlement_latency,
|
|
303
|
+
routing_metadata: ep.routing_metadata,
|
|
304
|
+
});
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
// Compliance
|
|
308
|
+
let compliance;
|
|
309
|
+
if (data.compliance) {
|
|
310
|
+
const c = data.compliance;
|
|
311
|
+
compliance = {
|
|
312
|
+
sanctions_checked: c.sanctions_checked ?? c.screened ?? false,
|
|
313
|
+
fatf_risk_rating: c.fatf_risk_rating,
|
|
314
|
+
requires_purpose_code: c.requires_purpose_code ?? false,
|
|
315
|
+
screened: c.screened,
|
|
316
|
+
result: c.result,
|
|
317
|
+
provider: c.provider,
|
|
318
|
+
screened_at: c.screened_at,
|
|
319
|
+
cached: c.cached,
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
// Identity (NFT + generative art)
|
|
323
|
+
let identity;
|
|
324
|
+
if (data.identity) {
|
|
325
|
+
const i = data.identity;
|
|
326
|
+
identity = {
|
|
327
|
+
nft_token_id: i.nft_token_id,
|
|
328
|
+
image_uri: i.image_uri,
|
|
329
|
+
metadata_uri: i.metadata_uri,
|
|
330
|
+
image_url: i.image_url,
|
|
331
|
+
nft_explorer_url: i.nft_explorer_url,
|
|
332
|
+
generation: i.generation,
|
|
333
|
+
identity_status: i.identity_status,
|
|
334
|
+
tier: i.tier,
|
|
335
|
+
};
|
|
336
|
+
}
|
|
337
|
+
return {
|
|
338
|
+
resolution_id: data.resolution_id ?? "",
|
|
339
|
+
alias_uri: data.alias ?? "",
|
|
340
|
+
resolved_at: data.resolved_at ?? "",
|
|
341
|
+
ttl_seconds: data.ttl_seconds ?? 300,
|
|
342
|
+
message_id: data.message_id,
|
|
343
|
+
entity_id: data.entity_id,
|
|
344
|
+
entity,
|
|
345
|
+
endpoints,
|
|
346
|
+
compliance,
|
|
347
|
+
iso20022_hint: data.iso20022_hint,
|
|
348
|
+
identity,
|
|
349
|
+
rail_score: data.rail_score,
|
|
350
|
+
resolution_status: data.status ?? data.resolution_status ?? "resolved",
|
|
351
|
+
caller_tier: data.caller_tier,
|
|
352
|
+
resolved_from: data.resolved_from ?? "origin",
|
|
353
|
+
cache_hit: data.cache_hit ?? false,
|
|
354
|
+
agent_commerce: data.agent_commerce,
|
|
355
|
+
warnings: data.warnings ?? [],
|
|
356
|
+
};
|
|
357
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/** Base error for all DNS of Money SDK errors. */
|
|
2
|
+
export declare class DNSOfMoneyError extends Error {
|
|
3
|
+
readonly statusCode?: number;
|
|
4
|
+
constructor(message: string, statusCode?: number);
|
|
5
|
+
}
|
|
6
|
+
/** Raised when a pay: alias does not exist (HTTP 404). */
|
|
7
|
+
export declare class AliasNotFoundError extends DNSOfMoneyError {
|
|
8
|
+
constructor(alias: string);
|
|
9
|
+
}
|
|
10
|
+
/** Raised when a pay: alias is already registered (HTTP 409). */
|
|
11
|
+
export declare class AliasTakenError extends DNSOfMoneyError {
|
|
12
|
+
constructor(alias: string);
|
|
13
|
+
}
|
|
14
|
+
/** Raised when the API key is missing or invalid (HTTP 401). */
|
|
15
|
+
export declare class AuthenticationError extends DNSOfMoneyError {
|
|
16
|
+
constructor();
|
|
17
|
+
}
|
|
18
|
+
/** Raised when the API rate limit is exceeded (HTTP 429). */
|
|
19
|
+
export declare class RateLimitError extends DNSOfMoneyError {
|
|
20
|
+
readonly retryAfter?: number;
|
|
21
|
+
constructor(retryAfter?: number);
|
|
22
|
+
}
|
|
23
|
+
/** Raised when the founding tier cap (500) has been reached. */
|
|
24
|
+
export declare class CapReachedError extends DNSOfMoneyError {
|
|
25
|
+
constructor();
|
|
26
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CapReachedError = exports.RateLimitError = exports.AuthenticationError = exports.AliasTakenError = exports.AliasNotFoundError = exports.DNSOfMoneyError = void 0;
|
|
4
|
+
/** Base error for all DNS of Money SDK errors. */
|
|
5
|
+
class DNSOfMoneyError extends Error {
|
|
6
|
+
constructor(message, statusCode) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.name = "DNSOfMoneyError";
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
exports.DNSOfMoneyError = DNSOfMoneyError;
|
|
13
|
+
/** Raised when a pay: alias does not exist (HTTP 404). */
|
|
14
|
+
class AliasNotFoundError extends DNSOfMoneyError {
|
|
15
|
+
constructor(alias) {
|
|
16
|
+
super(`Alias not found: ${alias}`, 404);
|
|
17
|
+
this.name = "AliasNotFoundError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
exports.AliasNotFoundError = AliasNotFoundError;
|
|
21
|
+
/** Raised when a pay: alias is already registered (HTTP 409). */
|
|
22
|
+
class AliasTakenError extends DNSOfMoneyError {
|
|
23
|
+
constructor(alias) {
|
|
24
|
+
super(`Alias already taken: ${alias}`, 409);
|
|
25
|
+
this.name = "AliasTakenError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.AliasTakenError = AliasTakenError;
|
|
29
|
+
/** Raised when the API key is missing or invalid (HTTP 401). */
|
|
30
|
+
class AuthenticationError extends DNSOfMoneyError {
|
|
31
|
+
constructor() {
|
|
32
|
+
super("Invalid or missing API key", 401);
|
|
33
|
+
this.name = "AuthenticationError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.AuthenticationError = AuthenticationError;
|
|
37
|
+
/** Raised when the API rate limit is exceeded (HTTP 429). */
|
|
38
|
+
class RateLimitError extends DNSOfMoneyError {
|
|
39
|
+
constructor(retryAfter) {
|
|
40
|
+
const msg = retryAfter
|
|
41
|
+
? `Rate limit exceeded — retry after ${retryAfter}s`
|
|
42
|
+
: "Rate limit exceeded";
|
|
43
|
+
super(msg, 429);
|
|
44
|
+
this.name = "RateLimitError";
|
|
45
|
+
this.retryAfter = retryAfter;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
exports.RateLimitError = RateLimitError;
|
|
49
|
+
/** Raised when the founding tier cap (500) has been reached. */
|
|
50
|
+
class CapReachedError extends DNSOfMoneyError {
|
|
51
|
+
constructor() {
|
|
52
|
+
super("Founding tier cap reached (500/500)", 409);
|
|
53
|
+
this.name = "CapReachedError";
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
exports.CapReachedError = CapReachedError;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { DNSOfMoneyClient, resolve, register, checkAvailability, sendPreview, send, } from "./client";
|
|
2
|
+
export type { ClientOptions } from "./client";
|
|
3
|
+
export { DNSOfMoneyError, AliasNotFoundError, AliasTakenError, AuthenticationError, RateLimitError, CapReachedError, } from "./exceptions";
|
|
4
|
+
export type { Entity, Endpoint, Compliance, Identity, AgentCard, ResolutionResponse, RegistrationResponse, SendPreview, SendResult, SendOptions, } from "./models";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.CapReachedError = exports.RateLimitError = exports.AuthenticationError = exports.AliasTakenError = exports.AliasNotFoundError = exports.DNSOfMoneyError = exports.send = exports.sendPreview = exports.checkAvailability = exports.register = exports.resolve = exports.DNSOfMoneyClient = void 0;
|
|
4
|
+
var client_1 = require("./client");
|
|
5
|
+
Object.defineProperty(exports, "DNSOfMoneyClient", { enumerable: true, get: function () { return client_1.DNSOfMoneyClient; } });
|
|
6
|
+
Object.defineProperty(exports, "resolve", { enumerable: true, get: function () { return client_1.resolve; } });
|
|
7
|
+
Object.defineProperty(exports, "register", { enumerable: true, get: function () { return client_1.register; } });
|
|
8
|
+
Object.defineProperty(exports, "checkAvailability", { enumerable: true, get: function () { return client_1.checkAvailability; } });
|
|
9
|
+
Object.defineProperty(exports, "sendPreview", { enumerable: true, get: function () { return client_1.sendPreview; } });
|
|
10
|
+
Object.defineProperty(exports, "send", { enumerable: true, get: function () { return client_1.send; } });
|
|
11
|
+
var exceptions_1 = require("./exceptions");
|
|
12
|
+
Object.defineProperty(exports, "DNSOfMoneyError", { enumerable: true, get: function () { return exceptions_1.DNSOfMoneyError; } });
|
|
13
|
+
Object.defineProperty(exports, "AliasNotFoundError", { enumerable: true, get: function () { return exceptions_1.AliasNotFoundError; } });
|
|
14
|
+
Object.defineProperty(exports, "AliasTakenError", { enumerable: true, get: function () { return exceptions_1.AliasTakenError; } });
|
|
15
|
+
Object.defineProperty(exports, "AuthenticationError", { enumerable: true, get: function () { return exceptions_1.AuthenticationError; } });
|
|
16
|
+
Object.defineProperty(exports, "RateLimitError", { enumerable: true, get: function () { return exceptions_1.RateLimitError; } });
|
|
17
|
+
Object.defineProperty(exports, "CapReachedError", { enumerable: true, get: function () { return exceptions_1.CapReachedError; } });
|
package/dist/models.d.ts
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/** The entity (person, business, agent) that owns a pay: alias. */
|
|
2
|
+
export interface Entity {
|
|
3
|
+
display_name: string;
|
|
4
|
+
entity_type?: string;
|
|
5
|
+
jurisdiction?: string;
|
|
6
|
+
kyc_status?: string;
|
|
7
|
+
}
|
|
8
|
+
/** A single payment endpoint returned by resolution. */
|
|
9
|
+
export interface Endpoint {
|
|
10
|
+
rail: string;
|
|
11
|
+
currency: string;
|
|
12
|
+
address?: string;
|
|
13
|
+
priority: number;
|
|
14
|
+
fee_estimate?: string;
|
|
15
|
+
settlement_latency?: string;
|
|
16
|
+
routing_metadata?: Record<string, unknown>;
|
|
17
|
+
}
|
|
18
|
+
/** Compliance screening result attached to a resolution. */
|
|
19
|
+
export interface Compliance {
|
|
20
|
+
sanctions_checked: boolean;
|
|
21
|
+
fatf_risk_rating?: string;
|
|
22
|
+
requires_purpose_code: boolean;
|
|
23
|
+
screened?: boolean;
|
|
24
|
+
result?: string;
|
|
25
|
+
provider?: string;
|
|
26
|
+
screened_at?: string;
|
|
27
|
+
cached?: boolean;
|
|
28
|
+
}
|
|
29
|
+
/** On-chain identity linked to a pay: alias (NFT + generative art). */
|
|
30
|
+
export interface Identity {
|
|
31
|
+
nft_token_id?: string;
|
|
32
|
+
image_uri?: string;
|
|
33
|
+
metadata_uri?: string;
|
|
34
|
+
image_url?: string;
|
|
35
|
+
nft_explorer_url?: string;
|
|
36
|
+
generation?: number;
|
|
37
|
+
identity_status?: string;
|
|
38
|
+
tier?: string;
|
|
39
|
+
}
|
|
40
|
+
/** AP2/A2A-003 agent capability manifest. */
|
|
41
|
+
export interface AgentCard {
|
|
42
|
+
name: string;
|
|
43
|
+
endpoint: string;
|
|
44
|
+
capabilities: string[];
|
|
45
|
+
authentication?: string;
|
|
46
|
+
domains: string[];
|
|
47
|
+
protocol_versions: string[];
|
|
48
|
+
}
|
|
49
|
+
/** Full resolution response from the DNS of Money API. */
|
|
50
|
+
export interface ResolutionResponse {
|
|
51
|
+
resolution_id: string;
|
|
52
|
+
alias_uri: string;
|
|
53
|
+
resolved_at: string;
|
|
54
|
+
ttl_seconds: number;
|
|
55
|
+
message_id?: string;
|
|
56
|
+
entity_id?: string;
|
|
57
|
+
entity?: Entity;
|
|
58
|
+
endpoints: Endpoint[];
|
|
59
|
+
compliance?: Compliance;
|
|
60
|
+
iso20022_hint?: Record<string, unknown>;
|
|
61
|
+
identity?: Identity;
|
|
62
|
+
rail_score?: Record<string, unknown>;
|
|
63
|
+
resolution_status: string;
|
|
64
|
+
caller_tier?: number;
|
|
65
|
+
resolved_from: string;
|
|
66
|
+
cache_hit: boolean;
|
|
67
|
+
agent_commerce?: Record<string, unknown>;
|
|
68
|
+
warnings: string[];
|
|
69
|
+
}
|
|
70
|
+
/** Response from a successful alias registration. */
|
|
71
|
+
export interface RegistrationResponse {
|
|
72
|
+
alias_name: string;
|
|
73
|
+
registration_number?: number;
|
|
74
|
+
anchor_status?: string;
|
|
75
|
+
proof?: Record<string, unknown>;
|
|
76
|
+
created_at?: string;
|
|
77
|
+
}
|
|
78
|
+
/** Preview of where a payment would go (dry-run, no execution). */
|
|
79
|
+
export interface SendPreview {
|
|
80
|
+
alias: string;
|
|
81
|
+
resolved: boolean;
|
|
82
|
+
destination_address?: string;
|
|
83
|
+
display_name?: string;
|
|
84
|
+
rail?: string;
|
|
85
|
+
currency: string;
|
|
86
|
+
fee_estimate?: string;
|
|
87
|
+
identity?: Record<string, unknown>;
|
|
88
|
+
}
|
|
89
|
+
/** Result of a send-to-alias payment execution. */
|
|
90
|
+
export interface SendResult {
|
|
91
|
+
transaction_id: string;
|
|
92
|
+
status: string;
|
|
93
|
+
alias: string;
|
|
94
|
+
amount: number;
|
|
95
|
+
currency: string;
|
|
96
|
+
rail: string;
|
|
97
|
+
tx_hash?: string;
|
|
98
|
+
settle_time_seconds?: number;
|
|
99
|
+
memo?: string;
|
|
100
|
+
created_at?: string;
|
|
101
|
+
}
|
|
102
|
+
/** Optional parameters for a send-to-alias payment. */
|
|
103
|
+
export interface SendOptions {
|
|
104
|
+
currency?: string;
|
|
105
|
+
memo?: string;
|
|
106
|
+
/** Unique key to prevent double-send. Auto-generated if not provided. */
|
|
107
|
+
idempotencyKey?: string;
|
|
108
|
+
}
|
package/dist/models.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "dnsofmoney",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "DNS of Money — pay: alias resolution + send SDK",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"types": "dist/index.d.ts",
|
|
7
|
+
"files": ["dist"],
|
|
8
|
+
"scripts": {
|
|
9
|
+
"build": "tsc",
|
|
10
|
+
"test": "echo 'Tests coming soon'"
|
|
11
|
+
},
|
|
12
|
+
"keywords": ["payments", "dns", "fintech", "xrpl", "iso20022", "fas-1"],
|
|
13
|
+
"license": "MIT",
|
|
14
|
+
"dependencies": {},
|
|
15
|
+
"devDependencies": {
|
|
16
|
+
"typescript": "^5.0.0"
|
|
17
|
+
},
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/dnsofmoney/dns-of-money"
|
|
21
|
+
},
|
|
22
|
+
"homepage": "https://dnsofmoney.com"
|
|
23
|
+
}
|