domain-quotes 0.1.0 → 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 (3) hide show
  1. package/README.md +18 -18
  2. package/dist/index.js +1 -1
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -25,37 +25,37 @@ npm i domain-quotes
25
25
  Usage
26
26
 
27
27
  ```ts
28
- import { getDefaultQuote, DomainPrices, DEFAULT_RATES } from 'domain-quotes';
28
+ import { getDefaultQuote, DomainQuotes, DEFAULT_CONFIG } from 'domain-quotes';
29
29
 
30
30
  // Quick quote (uses bundled defaults)
31
31
  const quote = await getDefaultQuote('com', 'USD', { discountCodes: ['SAVE10'] });
32
32
  // → { extension, currency, basePrice, discount, tax, totalPrice, symbol }
33
33
 
34
34
  // Advanced: custom or explicit config via the class
35
- const dp = new DomainPrices(DEFAULT_RATES); // or provide your own DomainPricesConfig
36
- const eur = await dp.getPrice('example.com', 'EUR', { discountPolicy: 'stack' });
35
+ const dq = new DomainQuotes(DEFAULT_CONFIG); // or provide your own DomainQuoteConfig
36
+ const eur = await dq.getQuote('example.com', 'EUR', { discountPolicy: 'stack' });
37
37
 
38
38
  // Add a 15% markup before discounts/taxes
39
- const withMarkup = new DomainPrices({
40
- ...DEFAULT_RATES,
39
+ const withMarkup = new DomainQuotes({
40
+ ...DEFAULT_CONFIG,
41
41
  markup: { type: 'percentage', value: 0.15 },
42
42
  });
43
- const quoteWithMarkup = await withMarkup.getPrice('example.com', 'USD', { discountCodes: ['SAVE10'] });
43
+ const quoteWithMarkup = await withMarkup.getQuote('example.com', 'USD', { discountCodes: ['SAVE10'] });
44
+
44
45
  ```
45
46
 
46
47
  API
47
48
 
48
- - `getDefaultQuote(extension: string, currency: string, options?: GetPriceOptions): Promise<PriceQuote>`
49
+ - `getDefaultQuote(extension: string, currency: string, options?: GetQuoteOptions): Promise<Quote>`
49
50
  - Computes a quote for a TLD/SLD extension (e.g. `com`, `com.ng`, `.org`) using the bundled defaults.
50
- - Alias: `getDefaultPrice(...)` for backward-compatibility.
51
51
  - `options`
52
52
  - `discountCodes?: string[]` – one or more codes; case-insensitive.
53
53
  - `now?: number | Date` – inject time for deterministic tests.
54
54
  - `discountPolicy?: 'stack' | 'max'` – default `'max'` (highest single discount only).
55
55
 
56
- - `class DomainPrices(config: DomainPricesConfig)`
57
- - `getPrice(extension: string, currency: string, options?: GetPriceOptions): Promise<PriceQuote>` – same behavior as above, but uses the provided config. Alias: `getQuote(...)`.
58
- - `DEFAULT_RATES: DomainPricesConfig` – exported snapshot config used by `getDefaultQuote`.
56
+ - `class DomainQuotes(config: DomainQuoteConfig)`
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`.
59
59
 
60
60
  - `listSupportedExtensions(): string[]`
61
61
  - All extensions with a non-zero price in the dataset.
@@ -73,21 +73,21 @@ Types
73
73
  ```ts
74
74
  type DiscountPolicy = 'stack' | 'max';
75
75
 
76
- interface GetPriceOptions {
76
+ interface GetQuoteOptions {
77
77
  discountCodes?: string[];
78
78
  now?: number | Date;
79
79
  discountPolicy?: DiscountPolicy;
80
80
  transaction?: 'create' | 'renew' | 'restore' | 'transfer'; // default 'create'
81
81
  }
82
82
 
83
- type MarkupType = 'percentage' | 'fixed_usd';
83
+ type MarkupType = 'percentage' | 'fixedUsd';
84
84
 
85
- interface PriceMarkup {
86
- type: MarkupType; // percentage -> 0.2 === +20%, fixed_usd -> +$ value before conversion
85
+ interface Markup {
86
+ type: MarkupType; // percentage -> 0.2 === +20%, fixedUsd -> +$ value before conversion
87
87
  value: number;
88
88
  }
89
89
 
90
- interface PriceQuote {
90
+ interface Quote {
91
91
  extension: string;
92
92
  currency: string;
93
93
  basePrice: number;
@@ -114,7 +114,7 @@ interface DiscountConfig {
114
114
  endAt: string; // ISO timestamp
115
115
  }
116
116
 
117
- interface DomainPricesConfig {
117
+ interface DomainQuoteConfig {
118
118
  createPrices: Record<string, number>; // base USD prices for create
119
119
  // Optional price tables per transaction type (all USD). Falls back to `createPrices` when absent.
120
120
  renewPrices?: Record<string, number>;
@@ -123,7 +123,7 @@ interface DomainPricesConfig {
123
123
  exchangeRates: ExchangeRateData[]; // currency conversion data
124
124
  vatRate: number; // single VAT rate applied to subtotal
125
125
  discounts: Record<string, DiscountConfig>; // discount code → config
126
- markup?: PriceMarkup; // optional markup applied before conversion
126
+ markup?: Markup; // optional markup applied before conversion
127
127
  }
128
128
  ```
129
129
 
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- var S={SAVE1:{rate:.01,extensions:["com","net"],startAt:"2023-01-01T00:00:00Z",endAt:"2025-12-31T23:59:59Z"},NEWUSER15:{rate:.15,extensions:["com","net","org"],startAt:"2023-01-01T00:00:00Z",endAt:"2024-12-31T23:59:59Z"},FALL20:{rate:.2,extensions:["org","info"],startAt:"2024-09-01T00:00:00Z",endAt:"2024-12-01T00:00:00Z"}};var U=.075;function I(){return(_.supportedCurrencies??["USD","NGN"]).slice()}function et(e){if(!e)return!1;let t=e.toUpperCase();return I().includes(t)}function nt(){let e=y();return Object.keys(e).sort()}function rt(e){let t=y(),n=A(e),r=t[n];return typeof r=="number"&&r>0}function A(e){return e&&e.trim().toLowerCase().replace(/^\.+/,"")}function $(e){return e instanceof Date?e.getTime():typeof e=="number"?e:Date.now()}var L="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/unified-create-prices.csv",M="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/exchange-rates.json";async function Z(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 j(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch ${e}: ${t.status} ${t.statusText}`);return t.json()}function V(e){let t=e.split(/\r?\n/).map(i=>i.trim()).filter(Boolean);if(t.length===0)return{};let n=t.shift(),r={};for(let i of t){let g=i.split(",");if(g.length<3)continue;let u=g[0]?.trim().toLowerCase(),s=g[2]?.trim(),o=Number(s);!u||!Number.isFinite(o)||o<=0||(!(u in r)||o<r[u])&&(r[u]=o)}return r}var[z,J]=await Promise.all([Z(L).then(V),j(M)]);function y(){return z}function X(){return J}function H(){return S}var h=class extends Error{constructor(t,n){super(n),this.name="DomainPricesError",this.code=t}},R=class extends h{constructor(t){super("ERR_UNSUPPORTED_EXTENSION",`Unsupported extension: ${t}`),this.name="UnsupportedExtensionError"}},P=class extends h{constructor(t){super("ERR_UNSUPPORTED_CURRENCY",`Unsupported currency: ${t}`),this.name="UnsupportedCurrencyError"}};function q(){return{countryCode:"US",currencyName:"United States Dollar",currencySymbol:"$",currencyCode:"USD",exchangeRate:1,inverseRate:1}}function p(e){return Number(e.toFixed(2))}function B(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 E=class{constructor(t){this.config=t}findRateInfo(t){if(t==="USD")return q();let n=this.config.exchangeRates.find(r=>r.currencyCode===t);if(!n)throw new P(t);return n}async getPrice(t,n,r={}){let i=this.config.createPrices,g=typeof this.config.vatRate=="number"?this.config.vatRate:U,u=this.config.discounts,s=A(t),o=r.transaction||"create",c;switch(o){case"renew":c=this.config.renewPrices?.[s]??i[s];break;case"restore":c=this.config.restorePrices?.[s]??i[s];break;case"transfer":c=this.config.transferPrices?.[s]??i[s];break;case"create":default:c=i[s];break}if(c===void 0||c===0)throw new R(s);let x=(n||"").toUpperCase();if(!(this.config.supportedCurrencies??["USD","NGN"]).includes(x))throw new P(n);let D=this.findRateInfo(x),k=D.currencySymbol,v=B(c,this.config.markup),d=p(v*D.exchangeRate),G=g,O=Array.from(new Set((r.discountCodes||[]).map(m=>m.toUpperCase()))),C=$(r.now),l=[];for(let m of O){let a=u[m];if(!a)continue;let w=Date.parse(a.startAt),N=Date.parse(a.endAt);Number.isNaN(w)||Number.isNaN(N)||C<w||C>N||a.extensions.includes(s)&&l.push(p(d*a.rate))}let f=0;l.length>0&&(r.discountPolicy==="stack"?f=p(l.reduce((m,a)=>m+a,0)):f=Math.max(...l)),f>d&&(f=d);let b=p(d-f),T=p(b*G),Q=p(b+T);return{extension:s,currency:x,basePrice:d,discount:f,tax:T,totalPrice:Q,symbol:k,transaction:o}}async getQuote(t,n,r={}){return this.getPrice(t,n,r)}},_={createPrices:y(),exchangeRates:X(),vatRate:U,discounts:H(),supportedCurrencies:["USD","NGN"]};async function W(e,t,n={}){return new E(_).getPrice(e,t,n)}async function st(e,t,n={}){return W(e,t,n)}export{_ as DEFAULT_CONFIG,U as DEFAULT_VAT_RATE,E as DomainPrices,E as DomainQuote,P as UnsupportedCurrencyError,R as UnsupportedExtensionError,W as getDefaultPrice,st as getDefaultQuote,et as isSupportedCurrency,rt as isSupportedExtension,I as listSupportedCurrencies,nt as listSupportedExtensions};
1
+ var P={SAVE1:{rate:.01,extensions:["com","net"],startAt:"2023-01-01T00:00:00Z",endAt:"2025-12-31T23:59:59Z"},NEWUSER15:{rate:.15,extensions:["com","net","org"],startAt:"2023-01-01T00:00:00Z",endAt:"2024-12-31T23:59:59Z"},FALL20:{rate:.2,extensions:["org","info"],startAt:"2024-09-01T00:00:00Z",endAt:"2024-12-01T00:00:00Z"}};var U=.075;function O(){return(Q.supportedCurrencies??["USD","NGN"]).slice()}function tt(e){if(!e)return!1;let t=e.toUpperCase();return O().includes(t)}function et(){let e=y();return Object.keys(e).sort()}function nt(e){let t=y(),n=A(e),r=t[n];return typeof r=="number"&&r>0}function A(e){return e&&e.trim().toLowerCase().replace(/^\.+/,"")}function $(e){return e instanceof Date?e.getTime():typeof e=="number"?e:Date.now()}var L="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/unified-create-prices.csv",M="https://raw.githubusercontent.com/namewiz/registrar-pricelist/refs/heads/main/data/exchange-rates.json";async function Z(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 j(e){let t=await fetch(e);if(!t.ok)throw new Error(`Failed to fetch ${e}: ${t.status} ${t.statusText}`);return t.json()}function V(e){let t=e.split(/\r?\n/).map(o=>o.trim()).filter(Boolean);if(t.length===0)return{};let n=t.shift(),r={};for(let o of t){let g=o.split(",");if(g.length<3)continue;let u=g[0]?.trim().toLowerCase(),s=g[2]?.trim(),i=Number(s);!u||!Number.isFinite(i)||i<=0||(!(u in r)||i<r[u])&&(r[u]=i)}return r}var[q,z]=await Promise.all([Z(L).then(V),j(M)]);function y(){return q}function J(){return z}function X(){return P}var h=class extends Error{constructor(t,n){super(n),this.name="DomainQuoteError",this.code=t}},E=class extends h{constructor(t){super("ERR_UNSUPPORTED_EXTENSION",`Unsupported extension: ${t}`),this.name="UnsupportedExtensionError"}},x=class extends h{constructor(t){super("ERR_UNSUPPORTED_CURRENCY",`Unsupported currency: ${t}`),this.name="UnsupportedCurrencyError"}};function H(){return{countryCode:"US",currencyName:"United States Dollar",currencySymbol:"$",currencyCode:"USD",exchangeRate:1,inverseRate:1}}function p(e){return Number(e.toFixed(2))}function B(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 C=class{constructor(t){this.config=t}findRateInfo(t){if(t==="USD")return H();let n=this.config.exchangeRates.find(r=>r.currencyCode===t);if(!n)throw new x(t);return n}async getQuote(t,n,r={}){let o=this.config.createPrices,g=typeof this.config.vatRate=="number"?this.config.vatRate:U,u=this.config.discounts,s=A(t),i=r.transaction||"create",c;switch(i){case"renew":c=this.config.renewPrices?.[s]??o[s];break;case"restore":c=this.config.restorePrices?.[s]??o[s];break;case"transfer":c=this.config.transferPrices?.[s]??o[s];break;case"create":default:c=o[s];break}if(c===void 0||c===0)throw new E(s);let R=(n||"").toUpperCase();if(!(this.config.supportedCurrencies??["USD","NGN"]).includes(R))throw new x(n);let D=this.findRateInfo(R),_=D.currencySymbol,k=B(c,this.config.markup),d=p(k*D.exchangeRate),v=g,F=Array.from(new Set((r.discountCodes||[]).map(m=>m.toUpperCase()))),b=$(r.now),l=[];for(let m of F){let a=u[m];if(!a)continue;let N=Date.parse(a.startAt),S=Date.parse(a.endAt);Number.isNaN(N)||Number.isNaN(S)||b<N||b>S||a.extensions.includes(s)&&l.push(p(d*a.rate))}let f=0;l.length>0&&(r.discountPolicy==="stack"?f=p(l.reduce((m,a)=>m+a,0)):f=Math.max(...l)),f>d&&(f=d);let T=p(d-f),w=p(T*v),G=p(T+w);return{extension:s,currency:R,basePrice:d,discount:f,tax:w,totalPrice:G,symbol:_,transaction:i}}},Q={createPrices:y(),exchangeRates:J(),vatRate:U,discounts:X(),supportedCurrencies:["USD","NGN"]};async function rt(e,t,n={}){return new C(Q).getQuote(e,t,n)}export{Q as DEFAULT_CONFIG,U as DEFAULT_VAT_RATE,C as DomainQuotes,x as UnsupportedCurrencyError,E as UnsupportedExtensionError,rt as getDefaultQuote,tt as isSupportedCurrency,nt as isSupportedExtension,O as listSupportedCurrencies,et as listSupportedExtensions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domain-quotes",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "Fast multi-currency domain quote checker library across registrars.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",