domain-quotes 0.2.2 → 0.3.2
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 +235 -65
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -11,91 +11,250 @@ Domain Quote is a lightweight TypeScript/JavaScript library to compute domain re
|
|
|
11
11
|
Includes:
|
|
12
12
|
- Extension support based on unified registrar price list (OpenProvider/NIRA)
|
|
13
13
|
- Currency conversion via remote exchange rates
|
|
14
|
-
- VAT calculation
|
|
15
|
-
-
|
|
14
|
+
- VAT calculation with configurable rate
|
|
15
|
+
- Flexible discount system with date ranges, extension/transaction filtering, and custom eligibility callbacks
|
|
16
16
|
- Configurable markup to increase base prices before taxes/discounts
|
|
17
|
+
- Extension normalization (`.com` and `com` are treated identically)
|
|
17
18
|
- Clean ESM API with TypeScript types
|
|
18
19
|
|
|
19
|
-
Install
|
|
20
|
+
## Install
|
|
20
21
|
|
|
21
22
|
```bash
|
|
22
23
|
npm i domain-quotes
|
|
23
24
|
```
|
|
24
25
|
|
|
25
|
-
Usage
|
|
26
|
+
## Usage
|
|
26
27
|
|
|
27
28
|
```ts
|
|
28
29
|
import { getDefaultQuote, DomainQuotes, DEFAULT_CONFIG } from 'domain-quotes';
|
|
29
30
|
|
|
30
|
-
// Quick quote (uses bundled defaults)
|
|
31
|
-
const quote = await getDefaultQuote('com', 'USD'
|
|
32
|
-
// → { extension, currency, basePrice, discount, tax, totalPrice, symbol }
|
|
31
|
+
// Quick quote (uses bundled defaults, no discounts configured by default)
|
|
32
|
+
const quote = await getDefaultQuote('com', 'USD');
|
|
33
|
+
// → { extension, currency, basePrice, discount, tax, totalPrice, symbol, domainTransaction }
|
|
33
34
|
|
|
34
|
-
//
|
|
35
|
-
const
|
|
36
|
-
|
|
35
|
+
// Extensions are normalized - leading dots are stripped
|
|
36
|
+
const quote2 = await getDefaultQuote('.com', 'USD'); // same as 'com'
|
|
37
|
+
|
|
38
|
+
// Custom config with discounts
|
|
39
|
+
const dq = new DomainQuotes({
|
|
40
|
+
...DEFAULT_CONFIG,
|
|
41
|
+
discounts: {
|
|
42
|
+
SAVE10: {
|
|
43
|
+
rate: 0.1, // 10% discount
|
|
44
|
+
extensions: ['com', 'net', 'org'],
|
|
45
|
+
startAt: '2024-01-01T00:00:00Z',
|
|
46
|
+
endAt: '2024-12-31T23:59:59Z',
|
|
47
|
+
},
|
|
48
|
+
},
|
|
49
|
+
});
|
|
50
|
+
const discounted = await dq.getQuote('com', 'USD', { discountCodes: ['SAVE10'] });
|
|
37
51
|
|
|
38
52
|
// Add a 15% markup before discounts/taxes
|
|
39
53
|
const withMarkup = new DomainQuotes({
|
|
40
54
|
...DEFAULT_CONFIG,
|
|
41
55
|
markup: { type: 'percentage', value: 0.15 },
|
|
42
56
|
});
|
|
43
|
-
const quoteWithMarkup = await withMarkup.getQuote('
|
|
57
|
+
const quoteWithMarkup = await withMarkup.getQuote('com', 'USD');
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## Discounts
|
|
61
|
+
|
|
62
|
+
Discounts are configured via the `discounts` field in `DomainQuoteConfig`. Each discount can be filtered by:
|
|
63
|
+
|
|
64
|
+
- **Date range**: `startAt` and `endAt` (ISO timestamps)
|
|
65
|
+
- **Extensions**: List of eligible extensions (normalized, so `.com` and `com` are equivalent)
|
|
66
|
+
- **Transaction types**: Optional list of transaction types (`create`, `renew`, `restore`, `transfer`)
|
|
67
|
+
- **Custom eligibility**: Optional callback for complex eligibility logic
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
const dq = new DomainQuotes({
|
|
71
|
+
...DEFAULT_CONFIG,
|
|
72
|
+
discounts: {
|
|
73
|
+
// Basic discount
|
|
74
|
+
WELCOME: {
|
|
75
|
+
rate: 0.1,
|
|
76
|
+
extensions: ['com', 'net'],
|
|
77
|
+
startAt: '2024-01-01T00:00:00Z',
|
|
78
|
+
endAt: '2024-12-31T23:59:59Z',
|
|
79
|
+
},
|
|
80
|
+
|
|
81
|
+
// Discount limited to specific transaction types
|
|
82
|
+
NEWUSER: {
|
|
83
|
+
rate: 0.2,
|
|
84
|
+
extensions: ['com', 'net', 'org'],
|
|
85
|
+
startAt: '2024-01-01T00:00:00Z',
|
|
86
|
+
endAt: '2024-12-31T23:59:59Z',
|
|
87
|
+
transactions: ['create'], // Only applies to new registrations
|
|
88
|
+
},
|
|
89
|
+
|
|
90
|
+
// Discount with custom eligibility callback
|
|
91
|
+
BIGSPENDER: {
|
|
92
|
+
rate: 0.25,
|
|
93
|
+
extensions: ['com', 'net', 'org'],
|
|
94
|
+
startAt: '2024-01-01T00:00:00Z',
|
|
95
|
+
endAt: '2024-12-31T23:59:59Z',
|
|
96
|
+
isEligible: (ctx) => ctx.basePrice >= 50, // Only if base price >= $50
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// Async eligibility (e.g., check external service)
|
|
100
|
+
VIP: {
|
|
101
|
+
rate: 0.3,
|
|
102
|
+
extensions: ['com'],
|
|
103
|
+
startAt: '2024-01-01T00:00:00Z',
|
|
104
|
+
endAt: '2024-12-31T23:59:59Z',
|
|
105
|
+
isEligible: async (ctx) => {
|
|
106
|
+
// Check if user is VIP via external service
|
|
107
|
+
const isVip = await checkVipStatus(ctx.discountCode);
|
|
108
|
+
return isVip;
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Apply discounts
|
|
115
|
+
const quote = await dq.getQuote('com', 'USD', {
|
|
116
|
+
discountCodes: ['WELCOME', 'NEWUSER'],
|
|
117
|
+
discountPolicy: 'max', // default: use highest discount
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// Stack multiple discounts
|
|
121
|
+
const stacked = await dq.getQuote('com', 'USD', {
|
|
122
|
+
discountCodes: ['WELCOME', 'NEWUSER'],
|
|
123
|
+
discountPolicy: 'stack', // sum all applicable discounts
|
|
124
|
+
});
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Eligibility Callback Context
|
|
128
|
+
|
|
129
|
+
The `isEligible` callback receives a context object with:
|
|
44
130
|
|
|
131
|
+
```ts
|
|
132
|
+
interface DiscountEligibilityContext {
|
|
133
|
+
extension: string; // Normalized extension (e.g., 'com')
|
|
134
|
+
currency: string; // Currency code (e.g., 'USD')
|
|
135
|
+
transaction: TransactionType; // Transaction type
|
|
136
|
+
basePrice: number; // Base price before discount
|
|
137
|
+
discountCode: string; // The discount code being evaluated
|
|
138
|
+
}
|
|
45
139
|
```
|
|
46
140
|
|
|
47
|
-
|
|
141
|
+
The callback is only invoked after all other criteria (date range, extension, transaction type) are satisfied. If the callback throws an error, the discount is skipped.
|
|
142
|
+
|
|
143
|
+
## API
|
|
144
|
+
|
|
145
|
+
### Functions
|
|
146
|
+
|
|
147
|
+
- **`getDefaultQuote(extension, currency, options?): Promise<Quote>`**
|
|
148
|
+
|
|
149
|
+
Computes a quote using bundled defaults (no discounts configured by default).
|
|
150
|
+
|
|
151
|
+
```ts
|
|
152
|
+
const quote = await getDefaultQuote('com', 'USD');
|
|
153
|
+
const withOptions = await getDefaultQuote('.ng', 'NGN', {
|
|
154
|
+
discountCodes: ['SAVE10'],
|
|
155
|
+
transaction: 'renew',
|
|
156
|
+
});
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
- **`normalizeExtension(extension: string): string`**
|
|
160
|
+
|
|
161
|
+
Normalizes an extension by trimming whitespace, lowercasing, and removing leading dots.
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
normalizeExtension('.COM') // → 'com'
|
|
165
|
+
normalizeExtension('..ng') // → 'ng'
|
|
166
|
+
normalizeExtension(' org ') // → 'org'
|
|
167
|
+
```
|
|
48
168
|
|
|
49
|
-
-
|
|
50
|
-
- Computes a quote for a TLD/SLD extension (e.g. `com`, `com.ng`, `.org`) using the bundled defaults.
|
|
51
|
-
- `options`
|
|
52
|
-
- `discountCodes?: string[]` – one or more codes; case-insensitive.
|
|
53
|
-
- `now?: number | Date` – inject time for deterministic tests.
|
|
54
|
-
- `discountPolicy?: 'stack' | 'max'` – default `'max'` (highest single discount only).
|
|
169
|
+
- **`listSupportedExtensions(): string[]`**
|
|
55
170
|
|
|
56
|
-
|
|
57
|
-
- `getQuote(extension: string, currency: string, options?: GetQuoteOptions): Promise<Quote>` – same behavior as above, but uses the provided config.
|
|
58
|
-
- `DEFAULT_CONFIG: DomainQuoteConfig` – exported snapshot config used by `getDefaultQuote`.
|
|
171
|
+
Returns all extensions with pricing data.
|
|
59
172
|
|
|
60
|
-
-
|
|
61
|
-
- All extensions with a non-zero price in the dataset.
|
|
173
|
+
- **`isSupportedExtension(extension: string): boolean`**
|
|
62
174
|
|
|
63
|
-
|
|
64
|
-
- Accepts an extension or a full domain (resolved by longest-known suffix match against bundled price data).
|
|
175
|
+
Checks if an extension is supported (normalizes input).
|
|
65
176
|
|
|
66
|
-
-
|
|
67
|
-
- Currently returns `['USD','GBP','EUR','NGN']`. These map to VAT via country ISO codes.
|
|
177
|
+
- **`listSupportedCurrencies(): string[]`**
|
|
68
178
|
|
|
69
|
-
|
|
179
|
+
Returns supported currencies (default: `['USD', 'NGN']`).
|
|
70
180
|
|
|
71
|
-
|
|
181
|
+
- **`isSupportedCurrency(code: string): boolean`**
|
|
182
|
+
|
|
183
|
+
Checks if a currency is supported (case-insensitive).
|
|
184
|
+
|
|
185
|
+
### Class
|
|
186
|
+
|
|
187
|
+
- **`new DomainQuotes(config: DomainQuoteConfig)`**
|
|
188
|
+
|
|
189
|
+
Creates a quote calculator with custom configuration.
|
|
190
|
+
|
|
191
|
+
```ts
|
|
192
|
+
const dq = new DomainQuotes({
|
|
193
|
+
...DEFAULT_CONFIG,
|
|
194
|
+
vatRate: 0.2,
|
|
195
|
+
supportedCurrencies: ['USD', 'NGN', 'EUR', 'GBP'],
|
|
196
|
+
discounts: { /* ... */ },
|
|
197
|
+
});
|
|
198
|
+
|
|
199
|
+
const quote = await dq.getQuote('com', 'EUR', options);
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### Constants
|
|
203
|
+
|
|
204
|
+
- **`DEFAULT_CONFIG: DomainQuoteConfig`**
|
|
205
|
+
|
|
206
|
+
The default configuration with remote pricing data, 7.5% VAT, and no discounts.
|
|
207
|
+
|
|
208
|
+
- **`DEFAULT_VAT_RATE`** = `0.075` (7.5%)
|
|
209
|
+
|
|
210
|
+
## Types
|
|
72
211
|
|
|
73
212
|
```ts
|
|
213
|
+
type TransactionType = 'create' | 'renew' | 'restore' | 'transfer';
|
|
74
214
|
type DiscountPolicy = 'stack' | 'max';
|
|
215
|
+
type MarkupType = 'percentage' | 'fixedUsd';
|
|
75
216
|
|
|
76
217
|
interface GetQuoteOptions {
|
|
77
|
-
discountCodes?: string[];
|
|
78
|
-
now?: number | Date;
|
|
79
|
-
discountPolicy?: DiscountPolicy;
|
|
80
|
-
transaction?:
|
|
218
|
+
discountCodes?: string[]; // Discount codes to apply (case-insensitive)
|
|
219
|
+
now?: number | Date; // Override current time for testing
|
|
220
|
+
discountPolicy?: DiscountPolicy; // 'max' (default) or 'stack'
|
|
221
|
+
transaction?: TransactionType; // default: 'create'
|
|
81
222
|
}
|
|
82
223
|
|
|
83
|
-
|
|
224
|
+
interface Quote {
|
|
225
|
+
extension: string; // Normalized extension
|
|
226
|
+
currency: string; // Currency code
|
|
227
|
+
basePrice: number; // Price before discount
|
|
228
|
+
discount: number; // Total discount amount
|
|
229
|
+
tax: number; // Tax amount
|
|
230
|
+
totalPrice: number; // Final price (basePrice - discount + tax)
|
|
231
|
+
symbol: string; // Currency symbol
|
|
232
|
+
domainTransaction: TransactionType; // Transaction type
|
|
233
|
+
}
|
|
84
234
|
|
|
85
235
|
interface Markup {
|
|
86
|
-
type: MarkupType;
|
|
87
|
-
value: number;
|
|
236
|
+
type: MarkupType; // 'percentage' or 'fixedUsd'
|
|
237
|
+
value: number; // 0.2 = +20%, or fixed USD amount
|
|
88
238
|
}
|
|
89
239
|
|
|
90
|
-
interface
|
|
240
|
+
interface DiscountEligibilityContext {
|
|
91
241
|
extension: string;
|
|
92
242
|
currency: string;
|
|
243
|
+
transaction: TransactionType;
|
|
93
244
|
basePrice: number;
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
245
|
+
discountCode: string;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
type DiscountEligibilityCallback =
|
|
249
|
+
(context: DiscountEligibilityContext) => boolean | Promise<boolean>;
|
|
250
|
+
|
|
251
|
+
interface DiscountConfig {
|
|
252
|
+
rate: number; // e.g., 0.1 for 10%
|
|
253
|
+
extensions: string[]; // Eligible extensions (normalized)
|
|
254
|
+
startAt: string; // ISO timestamp
|
|
255
|
+
endAt: string; // ISO timestamp
|
|
256
|
+
transactions?: TransactionType[]; // Limit to specific transaction types
|
|
257
|
+
isEligible?: DiscountEligibilityCallback; // Custom eligibility logic
|
|
99
258
|
}
|
|
100
259
|
|
|
101
260
|
interface ExchangeRateData {
|
|
@@ -107,38 +266,49 @@ interface ExchangeRateData {
|
|
|
107
266
|
inverseRate: number;
|
|
108
267
|
}
|
|
109
268
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
extensions: string[]; // eligible extensions
|
|
113
|
-
startAt: string; // ISO timestamp
|
|
114
|
-
endAt: string; // ISO timestamp
|
|
115
|
-
}
|
|
269
|
+
type PriceEntry = number | Record<string, number>;
|
|
270
|
+
type PriceTable = Record<string, PriceEntry>;
|
|
116
271
|
|
|
117
272
|
interface DomainQuoteConfig {
|
|
118
|
-
createPrices:
|
|
119
|
-
// Optional
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
273
|
+
createPrices: PriceTable; // Base prices for create
|
|
274
|
+
renewPrices?: PriceTable; // Optional prices for renew
|
|
275
|
+
restorePrices?: PriceTable; // Optional prices for restore
|
|
276
|
+
transferPrices?: PriceTable; // Optional prices for transfer
|
|
277
|
+
exchangeRates: ExchangeRateData[]; // Currency conversion data
|
|
278
|
+
vatRate: number; // VAT rate (e.g., 0.075 for 7.5%)
|
|
279
|
+
discounts: Record<string, DiscountConfig>; // Discount configurations
|
|
280
|
+
markup?: Markup; // Optional markup
|
|
281
|
+
supportedCurrencies?: string[]; // Allowed currencies (default: ['USD', 'NGN'])
|
|
127
282
|
}
|
|
128
283
|
```
|
|
129
284
|
|
|
130
|
-
Errors
|
|
285
|
+
## Errors
|
|
286
|
+
|
|
287
|
+
- **`UnsupportedExtensionError`** - `code: 'ERR_UNSUPPORTED_EXTENSION'`
|
|
288
|
+
- **`UnsupportedCurrencyError`** - `code: 'ERR_UNSUPPORTED_CURRENCY'`
|
|
131
289
|
|
|
132
|
-
|
|
133
|
-
|
|
290
|
+
```ts
|
|
291
|
+
import { UnsupportedExtensionError, UnsupportedCurrencyError } from 'domain-quotes';
|
|
292
|
+
|
|
293
|
+
try {
|
|
294
|
+
await getDefaultQuote('invalid-tld', 'USD');
|
|
295
|
+
} catch (err) {
|
|
296
|
+
if (err instanceof UnsupportedExtensionError) {
|
|
297
|
+
console.log(err.code); // 'ERR_UNSUPPORTED_EXTENSION'
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
```
|
|
134
301
|
|
|
135
|
-
Notes
|
|
302
|
+
## Notes
|
|
136
303
|
|
|
137
|
-
- Rounding
|
|
138
|
-
- A single VAT rate is applied to the subtotal
|
|
139
|
-
-
|
|
304
|
+
- **Rounding**: All monetary values are rounded to 2 decimal places at each step.
|
|
305
|
+
- **VAT**: A single VAT rate is applied to the subtotal (base price - discount). Default is 7.5%.
|
|
306
|
+
- **Extension normalization**: Leading dots are stripped and extensions are lowercased. `.COM`, `..com`, and `com` are all equivalent.
|
|
307
|
+
- **Discount order**: The `isEligible` callback is only called after date range, extension, and transaction type checks pass.
|
|
308
|
+
- **Remote data**: Price and exchange-rate data are fetched at import time from:
|
|
140
309
|
- Prices: `https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/unified-create-prices.csv`
|
|
141
310
|
- Exchange rates: `https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/exchange-rates.json`
|
|
311
|
+
|
|
142
312
|
These are cached in-memory for the life of the process.
|
|
143
313
|
|
|
144
314
|
## Testing
|
|
@@ -147,4 +317,4 @@ Notes
|
|
|
147
317
|
npm test
|
|
148
318
|
```
|
|
149
319
|
|
|
150
|
-
The test suite uses Node
|
|
320
|
+
The test suite uses Node's built-in `node:test` runner and builds the library first.
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iBAAiB,EAEjB,eAAe,EAIf,KAAK,EAEN,MAAM,SAAS,CAAC;AACjB,YAAY,EACV,cAAc,EACd,2BAA2B,EAC3B,0BAA0B,EAC1B,cAAc,EACd,iBAAiB,EACjB,gBAAgB,EAChB,eAAe,EACf,MAAM,EACN,UAAU,EACV,UAAU,EACV,UAAU,EACV,KAAK,EACL,eAAe,EAChB,MAAM,SAAS,CAAC;AAEjB,eAAO,MAAM,gBAAgB,QAAQ,CAAC;AAEtC,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAGlD;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAKzD;AAED,wBAAgB,uBAAuB,IAAI,MAAM,EAAE,CAGlD;AAuBD,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAK/D;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,CAK5D;AAoGD,cAAM,gBAAiB,SAAQ,KAAK;IAClC,IAAI,EAAE,MAAM,CAAC;gBACA,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM;CAK3C;AAED,qBAAa,yBAA0B,SAAQ,gBAAgB;gBAChD,GAAG,EAAE,MAAM;CAIzB;AAED,qBAAa,wBAAyB,SAAQ,gBAAgB;gBAC/C,QAAQ,EAAE,MAAM;CAI9B;AA+BD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAoB;gBAE9B,MAAM,EAAE,iBAAiB;IAItC,OAAO,CAAC,YAAY;IAOd,QAAQ,CACZ,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,KAAK,CAAC;CAmHlB;AAGD,eAAO,MAAM,cAAc,EAAE,iBAQ5B,CAAC;AAEF,wBAAsB,eAAe,CACnC,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,GAAE,eAAoB,GAC5B,OAAO,CAAC,KAAK,CAAC,CAGhB"}
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var fe=.075;function L(){return(O.supportedCurrencies??["USD","NGN"]).slice()}function de(e){if(!e)return!1;let t=e.toUpperCase();return L().includes(t)}function le(){let e=_();return Object.keys(e).sort()}function N(e){if(e==null)return;if(typeof e=="number")return!Number.isFinite(e)||e<=0?void 0:{USD:e};let t={};for(let[n,r]of Object.entries(e)){let a=n?.toUpperCase();if(!a||!Number.isFinite(r)||r<=0)continue;let u=t[a];t[a]=u===void 0?r:Math.min(u,r)}return Object.keys(t).length>0?t:void 0}function j(e){return!!N(e)}function pe(e){let t=_(),n=S(e),r=t[n];return j(r)}function S(e){return e&&e.trim().toLowerCase().replace(/^\.+/,"")}function q(e){return e instanceof Date?e.getTime():typeof e=="number"?e:Date.now()}var X="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/unified-create-prices.csv",H="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/unified-renew-prices.csv",J="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/unified-transfer-prices.csv",W="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/exchange-rates.json";async function D(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch ${e}: ${t.status} ${t.statusText}`);return t.text()}async function B(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch ${e}: ${t.status} ${t.statusText}`);return t.json()}function y(e){let t=e.split(/\r?\n/).map(a=>a.trim()).filter(Boolean);if(t.length===0)return{};let n=t.shift(),r={};for(let a of t){let u=a.split(",");if(u.length<4)continue;let b=u[0]?.trim().toLowerCase(),i=u[2]?.trim().toUpperCase(),h=u[3]?.trim(),l=Number(h);if(!b||!i||!Number.isFinite(l)||l<=0)continue;let c=r[b],f;c===void 0?f={}:typeof c=="number"?f={USD:c}:f=c;let p=f[i];f[i]=p===void 0?l:Math.min(p,l),r[b]=f}return r}async function Y(){try{let[e,t,n,r]=await Promise.all([D(X).then(y),D(H).then(y),D(J).then(y),B(W)]);return[e,t,n,r]}catch(e){let t=e instanceof Error?e:new Error(typeof e=="string"?e:"Unknown error");throw t.message=`domain-quotes: failed to load remote pricing data: ${t.message}`,t}}var[K,Z,ee,te]=await Y();function _(){return K}function ne(){return Z}function re(){return ee}function ie(){return te}var T=class extends Error{constructor(t,n){super(n),this.name="DomainQuoteError",this.code=t}},R=class extends T{constructor(t){super("ERR_UNSUPPORTED_EXTENSION",`Unsupported extension: ${t}`),this.name="UnsupportedExtensionError"}},w=class extends T{constructor(t){super("ERR_UNSUPPORTED_CURRENCY",`Unsupported currency: ${t}`),this.name="UnsupportedCurrencyError"}};function se(){return{countryCode:"US",currencyName:"United States Dollar",currencySymbol:"$",currencyCode:"USD",exchangeRate:1,inverseRate:1}}function m(e){return Number(e.toFixed(2))}function oe(e,t){if(!t)return e;let n=typeof t.value=="number"?t.value:0;if(!Number.isFinite(n)||n<=0)return e;switch(t.type){case"percentage":return e+e*n;case"fixedUsd":return e+n;default:return e}}var U=class{constructor(t){this.config=t}findRateInfo(t){if(t==="USD")return se();let n=this.config.exchangeRates.find(r=>r.currencyCode===t);if(!n)throw new w(t);return n}async getQuote(t,n,r={}){let a=this.config.createPrices,u=typeof this.config.vatRate=="number"?this.config.vatRate:.075,b=this.config.discounts,i=S(t),h=r.transaction||"create",l=N(a[i]);if(!l)throw new R(i);let c={...l},f=(()=>{switch(h){case"renew":return this.config.renewPrices;case"restore":return this.config.restorePrices;case"transfer":return this.config.transferPrices;default:return}})();if(f){let o=N(f[i]);o&&(c={...c,...o})}if(Object.keys(c).length===0)throw new R(i);let p=(n||"").toUpperCase();if(!(this.config.supportedCurrencies??["USD","NGN"]).includes(p))throw new w(n);let C=this.findRateInfo(p),M=C.currencySymbol,d=c.USD;d===void 0&&(d=l.USD);let P=c[p];if(d===void 0&&P!==void 0&&(d=P/C.exchangeRate),d===void 0||d<=0)throw new R(i);let A=oe(d,this.config.markup),g;if(P!==void 0&&d>0){let o=P/d;g=m(A*o)}else g=m(A*C.exchangeRate);let G=u,$=Array.from(new Set((r.discountCodes||[]).map(o=>o.toUpperCase()))),v=q(r.now),x=[];for(let o of $){let s=b[o];if(!s)continue;let Q=Date.parse(s.startAt),k=Date.parse(s.endAt);if(!(Number.isNaN(Q)||Number.isNaN(k)||v<Q||v>k||!s.extensions.map(S).includes(i))&&!(s.transactions&&s.transactions.length>0&&!s.transactions.includes(h))){if(s.isEligible)try{let z={extension:i,currency:p,transaction:h,basePrice:g,discountCode:o};if(!await Promise.resolve(s.isEligible(z)))continue}catch{continue}x.push(m(g*s.rate))}}let E=0;x.length>0&&(r.discountPolicy==="stack"?E=m(x.reduce((o,s)=>o+s,0)):E=Math.max(...x)),E>g&&(E=g);let I=m(g-E),F=m(I*G),V=m(I+F);return{extension:i,currency:p,basePrice:g,discount:E,tax:F,totalPrice:V,symbol:M,domainTransaction:h}}},O={createPrices:_(),renewPrices:ne(),transferPrices:re(),exchangeRates:ie(),vatRate:.075,discounts:{},supportedCurrencies:["USD","NGN"]};async function ge(e,t,n={}){return new U(O).getQuote(e,t,n)}export{O as DEFAULT_CONFIG,fe as DEFAULT_VAT_RATE,U as DomainQuotes,w as UnsupportedCurrencyError,R as UnsupportedExtensionError,ge as getDefaultQuote,de as isSupportedCurrency,pe as isSupportedExtension,L as listSupportedCurrencies,le as listSupportedExtensions,S as normalizeExtension};
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,eAAe,CAAC;CACpC;AAED,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,UAAU,CAAC;AAEnD,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,KAAK;IACpB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,iBAAiB,EAAE,eAAe,CAAC;CACpC;AAED,MAAM,MAAM,UAAU,GAAG,YAAY,GAAG,UAAU,CAAC;AAEnD,MAAM,WAAW,MAAM;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,gBAAgB;IAC/B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,uDAAuD;AACvD,MAAM,WAAW,0BAA0B;IACzC,mDAAmD;IACnD,SAAS,EAAE,MAAM,CAAC;IAClB,6CAA6C;IAC7C,QAAQ,EAAE,MAAM,CAAC;IACjB,2BAA2B;IAC3B,WAAW,EAAE,eAAe,CAAC;IAC7B,qCAAqC;IACrC,SAAS,EAAE,MAAM,CAAC;IAClB,wCAAwC;IACxC,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,4GAA4G;AAC5G,MAAM,MAAM,2BAA2B,GAAG,CAAC,OAAO,EAAE,0BAA0B,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;AAE9G,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,iHAAiH;IACjH,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,2GAA2G;IAC3G,UAAU,CAAC,EAAE,2BAA2B,CAAC;CAC1C;AAED,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,CAAC;AAC7C,MAAM,MAAM,eAAe,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,UAAU,CAAC;AAE1E,MAAM,WAAW,eAAe;IAC9B,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;IACzB,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,WAAW,CAAC,EAAE,eAAe,CAAC;CAC/B;AAED,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AACzD,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAEpD,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,UAAU,CAAC;IAEzB,WAAW,CAAC,EAAE,UAAU,CAAC;IACzB,aAAa,CAAC,EAAE,UAAU,CAAC;IAC3B,cAAc,CAAC,EAAE,UAAU,CAAC;IAC5B,aAAa,EAAE,gBAAgB,EAAE,CAAC;IAElC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC;IAC1C,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,mBAAmB,CAAC,EAAE,MAAM,EAAE,CAAC;CAChC"}
|