@unirate/nuxt 0.1.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/LICENSE +21 -0
- package/README.md +164 -0
- package/dist/module.d.ts +23 -0
- package/dist/module.d.ts.map +1 -0
- package/dist/module.js +67 -0
- package/dist/module.js.map +1 -0
- package/dist/runtime/client.d.ts +65 -0
- package/dist/runtime/client.d.ts.map +1 -0
- package/dist/runtime/client.js +199 -0
- package/dist/runtime/client.js.map +1 -0
- package/dist/runtime/components/Currency.vue +19 -0
- package/dist/runtime/components/Rate.vue +18 -0
- package/dist/runtime/composables/useCurrency.d.ts +15 -0
- package/dist/runtime/composables/useCurrency.d.ts.map +1 -0
- package/dist/runtime/composables/useCurrency.js +34 -0
- package/dist/runtime/composables/useCurrency.js.map +1 -0
- package/dist/runtime/composables/useUniRate.d.ts +19 -0
- package/dist/runtime/composables/useUniRate.d.ts.map +1 -0
- package/dist/runtime/composables/useUniRate.js +69 -0
- package/dist/runtime/composables/useUniRate.js.map +1 -0
- package/dist/runtime/currency.d.ts +19 -0
- package/dist/runtime/currency.d.ts.map +1 -0
- package/dist/runtime/currency.js +58 -0
- package/dist/runtime/currency.js.map +1 -0
- package/dist/runtime/parse.d.ts +3 -0
- package/dist/runtime/parse.d.ts.map +1 -0
- package/dist/runtime/parse.js +15 -0
- package/dist/runtime/parse.js.map +1 -0
- package/dist/runtime/proxy.d.ts +14 -0
- package/dist/runtime/proxy.d.ts.map +1 -0
- package/dist/runtime/proxy.js +35 -0
- package/dist/runtime/proxy.js.map +1 -0
- package/dist/runtime/server/routes/proxy.d.ts +9 -0
- package/dist/runtime/server/routes/proxy.d.ts.map +1 -0
- package/dist/runtime/server/routes/proxy.js +46 -0
- package/dist/runtime/server/routes/proxy.js.map +1 -0
- package/dist/runtime/server/utils/unirate.d.ts +8 -0
- package/dist/runtime/server/utils/unirate.d.ts.map +1 -0
- package/dist/runtime/server/utils/unirate.js +25 -0
- package/dist/runtime/server/utils/unirate.js.map +1 -0
- package/dist/runtime/types.d.ts +12 -0
- package/dist/runtime/types.d.ts.map +1 -0
- package/dist/runtime/types.js +2 -0
- package/dist/runtime/types.js.map +1 -0
- package/package.json +64 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 UniRate API
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# @unirate/nuxt
|
|
2
|
+
|
|
3
|
+
[](https://github.com/UniRate-API/nuxt-unirate/actions/workflows/ci.yml)
|
|
4
|
+
[](https://www.npmjs.com/package/@unirate/nuxt)
|
|
5
|
+
|
|
6
|
+
Nuxt module for the [UniRate](https://unirateapi.com) currency-exchange API.
|
|
7
|
+
|
|
8
|
+
- 🔒 **Server proxy** — your API key stays on the server; the browser only ever talks to your own app.
|
|
9
|
+
- 🧩 **`useUniRate()`** composable — universal (SSR + client) rate/convert/historical/VAT/time-series helpers.
|
|
10
|
+
- 🌍 **`useCurrency()`** composable — detect the visitor's currency from `Accept-Language`, persisted to a cookie.
|
|
11
|
+
- 🛠️ **`useUniRateClient()`** server util — a direct, typed client for your `server/` routes.
|
|
12
|
+
- 💱 **`<Currency>`** + **`<Rate>`** components — locale-aware `Intl` formatting.
|
|
13
|
+
- 📦 **Zero runtime dependencies.** `@nuxt/kit` is a peer (it ships with Nuxt). Nuxt 3 and Nuxt 4.
|
|
14
|
+
|
|
15
|
+
## Install
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm install @unirate/nuxt
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
// nuxt.config.ts
|
|
23
|
+
export default defineNuxtConfig({
|
|
24
|
+
modules: ['@unirate/nuxt'],
|
|
25
|
+
unirate: {
|
|
26
|
+
// Prefer env: NUXT_UNIRATE_API_KEY (or UNIRATE_API_KEY). Avoid hardcoding.
|
|
27
|
+
apiKey: process.env.NUXT_UNIRATE_API_KEY,
|
|
28
|
+
},
|
|
29
|
+
})
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Get a free API key at [unirateapi.com](https://unirateapi.com). Set it via the
|
|
33
|
+
`NUXT_UNIRATE_API_KEY` environment variable so it never ends up in source control:
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
# .env
|
|
37
|
+
NUXT_UNIRATE_API_KEY=your_key_here
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
## Why a proxy?
|
|
41
|
+
|
|
42
|
+
A currency API key is a server secret. This module registers a server route
|
|
43
|
+
(default `/api/_unirate`) that injects the key and forwards only an
|
|
44
|
+
**allow-listed** set of UniRate paths. The `useUniRate()` composable calls that
|
|
45
|
+
route — so the key is never shipped in the client bundle, even during SSR
|
|
46
|
+
hydration. Set `addProxy: false` if you only use the server util.
|
|
47
|
+
|
|
48
|
+
## Usage
|
|
49
|
+
|
|
50
|
+
### Composable (pages / components)
|
|
51
|
+
|
|
52
|
+
```vue
|
|
53
|
+
<script setup lang="ts">
|
|
54
|
+
const { getRate, convert, listCurrencies } = useUniRate()
|
|
55
|
+
|
|
56
|
+
// SSR-friendly: wrap in useAsyncData so it runs once and hydrates.
|
|
57
|
+
const { data: rate } = await useAsyncData('usd-eur', () => getRate('USD', 'EUR'))
|
|
58
|
+
const { data: total } = await useAsyncData('cart', () => convert('USD', 'EUR', 49.99))
|
|
59
|
+
</script>
|
|
60
|
+
|
|
61
|
+
<template>
|
|
62
|
+
<p>1 USD = <Rate from="USD" to="EUR" :rate="rate ?? 0" /> EUR</p>
|
|
63
|
+
<p>Total: <Currency :amount="total ?? 0" currency="EUR" /></p>
|
|
64
|
+
</template>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
`useUniRate()` returns:
|
|
68
|
+
|
|
69
|
+
| Method | Returns |
|
|
70
|
+
|---|---|
|
|
71
|
+
| `getRate(from, to?)` | `number` (pair) or `Record<string, number>` (all rates from `from`) |
|
|
72
|
+
| `convert(from, to, amount)` | `number` |
|
|
73
|
+
| `listCurrencies()` | `string[]` |
|
|
74
|
+
| `getHistoricalRate(date, from, to?, amount?)` | `number` or `Record<string, number>` *(Pro)* |
|
|
75
|
+
| `getTimeSeries(start, end, base?, currencies?, amount?)` | `Record<string, Record<string, number>>` *(Pro)* |
|
|
76
|
+
| `getVatRates(country?)` | all VAT rates or one country |
|
|
77
|
+
| `getHistoricalLimits()` | available historical ranges *(Pro)* |
|
|
78
|
+
|
|
79
|
+
### Server util (`server/` routes)
|
|
80
|
+
|
|
81
|
+
When you need the typed client directly on the server (key stays server-side):
|
|
82
|
+
|
|
83
|
+
```ts
|
|
84
|
+
// server/api/price.get.ts
|
|
85
|
+
export default defineEventHandler(async () => {
|
|
86
|
+
const unirate = useUniRateClient()
|
|
87
|
+
return { eur: await unirate.convert('EUR', 100, 'USD') }
|
|
88
|
+
})
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
### Visitor currency
|
|
92
|
+
|
|
93
|
+
```vue
|
|
94
|
+
<script setup lang="ts">
|
|
95
|
+
const { currency, setCurrency } = useCurrency() // e.g. 'GBP' for an en-GB visitor
|
|
96
|
+
</script>
|
|
97
|
+
|
|
98
|
+
<template>
|
|
99
|
+
<select :value="currency" @change="setCurrency(($event.target as HTMLSelectElement).value)">
|
|
100
|
+
<option>USD</option><option>EUR</option><option>GBP</option>
|
|
101
|
+
</select>
|
|
102
|
+
</template>
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Components
|
|
106
|
+
|
|
107
|
+
```vue
|
|
108
|
+
<Currency :amount="1234.5" currency="EUR" :decimals="2" locale="de-DE" />
|
|
109
|
+
<!-- → 1.234,50 € -->
|
|
110
|
+
|
|
111
|
+
<Rate from="USD" to="JPY" :rate="157.42" :decimals="2" />
|
|
112
|
+
<!-- → 157.42 -->
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Configuration
|
|
116
|
+
|
|
117
|
+
```ts
|
|
118
|
+
unirate: {
|
|
119
|
+
apiKey: process.env.NUXT_UNIRATE_API_KEY, // or UNIRATE_API_KEY
|
|
120
|
+
baseUrl: 'https://api.unirateapi.com', // override for self-host/testing
|
|
121
|
+
timeoutMs: 30000,
|
|
122
|
+
addProxy: true, // register the server proxy route
|
|
123
|
+
proxyRoute: '/api/_unirate', // where the proxy is mounted
|
|
124
|
+
allowedPaths: undefined, // restrict the proxy's path allow-list
|
|
125
|
+
components: true, // register <Currency> + <Rate>
|
|
126
|
+
prefix: '', // e.g. 'Uni' → <UniCurrency>, <UniRate>
|
|
127
|
+
cookieName: 'unirate_currency', // used by useCurrency()
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
All values can also be supplied through Nuxt runtime config env overrides
|
|
132
|
+
(`NUXT_UNIRATE_API_KEY`, `NUXT_UNIRATE_BASE_URL`, …).
|
|
133
|
+
|
|
134
|
+
## Errors
|
|
135
|
+
|
|
136
|
+
Server-side calls (`useUniRateClient()`) throw typed errors:
|
|
137
|
+
`UniRateError` and its subclasses `AuthenticationError` (401),
|
|
138
|
+
`ProRequiredError` (403 — historical/time-series are Pro-gated on the free tier),
|
|
139
|
+
`InvalidCurrencyError` (404), `InvalidRequestError` (400), `RateLimitError` (429).
|
|
140
|
+
Proxy requests surface the upstream status code to `useUniRate()` via `$fetch`.
|
|
141
|
+
|
|
142
|
+
## Security
|
|
143
|
+
|
|
144
|
+
- Zero runtime dependencies; `@nuxt/kit` is a peer provided by Nuxt itself.
|
|
145
|
+
- The API key is read from server runtime config only — never bundled client-side.
|
|
146
|
+
- The proxy forwards an allow-listed set of paths, not arbitrary upstream URLs.
|
|
147
|
+
- Published to npm with [provenance attestation](https://docs.npmjs.com/generating-provenance-statements).
|
|
148
|
+
|
|
149
|
+
## Part of the UniRate ecosystem
|
|
150
|
+
|
|
151
|
+
Official UniRate clients & framework integrations:
|
|
152
|
+
[Python](https://github.com/UniRate-API/unirate-api-python) ·
|
|
153
|
+
[Node](https://github.com/UniRate-API/unirate-api-nodejs) ·
|
|
154
|
+
[React](https://github.com/UniRate-API/react-unirate) ·
|
|
155
|
+
[Next.js](https://github.com/UniRate-API/next-unirate) ·
|
|
156
|
+
[SvelteKit](https://github.com/UniRate-API/sveltekit-unirate) ·
|
|
157
|
+
[NestJS](https://github.com/UniRate-API/nestjs-unirate) ·
|
|
158
|
+
[Astro](https://github.com/UniRate-API/astro-unirate) ·
|
|
159
|
+
[Eleventy](https://github.com/UniRate-API/eleventy-unirate) ·
|
|
160
|
+
[MCP server](https://github.com/UniRate-API/unirate-mcp)
|
|
161
|
+
|
|
162
|
+
## License
|
|
163
|
+
|
|
164
|
+
MIT © UniRate API
|
package/dist/module.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ModuleOptions {
|
|
2
|
+
/** UniRate API key. Falls back to NUXT_UNIRATE_API_KEY / UNIRATE_API_KEY env. */
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
/** Upstream API base URL. Defaults to https://api.unirateapi.com */
|
|
5
|
+
baseUrl?: string;
|
|
6
|
+
/** Per-request timeout in milliseconds. Default 30000. */
|
|
7
|
+
timeoutMs?: number;
|
|
8
|
+
/** Register the server proxy route so the client composable can run. Default true. */
|
|
9
|
+
addProxy?: boolean;
|
|
10
|
+
/** Path the server proxy is mounted at. Default `/api/_unirate`. */
|
|
11
|
+
proxyRoute?: string;
|
|
12
|
+
/** API paths the proxy is allowed to forward. Defaults to the full UniRate surface. */
|
|
13
|
+
allowedPaths?: string[];
|
|
14
|
+
/** Register `<Currency>` + `<Rate>` components. Default true. */
|
|
15
|
+
components?: boolean;
|
|
16
|
+
/** Component name prefix, e.g. "Uni" → `<UniCurrency>`. Default "" (no prefix). */
|
|
17
|
+
prefix?: string;
|
|
18
|
+
/** Cookie name used by `useCurrency()`. Default `unirate_currency`. */
|
|
19
|
+
cookieName?: string;
|
|
20
|
+
}
|
|
21
|
+
declare const _default: unknown;
|
|
22
|
+
export default _default;
|
|
23
|
+
//# sourceMappingURL=module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.d.ts","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAUA,MAAM,WAAW,aAAa;IAC5B,iFAAiF;IACjF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oEAAoE;IACpE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,uFAAuF;IACvF,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iEAAiE;IACjE,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mFAAmF;IACnF,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,uEAAuE;IACvE,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;;AAED,wBAwEG"}
|
package/dist/module.js
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { defineNuxtModule, createResolver, addComponent, addImportsDir, addServerImportsDir, addServerHandler, } from "@nuxt/kit";
|
|
2
|
+
import { DEFAULT_ALLOWED_PATHS } from "./runtime/proxy.js";
|
|
3
|
+
export default defineNuxtModule({
|
|
4
|
+
meta: {
|
|
5
|
+
name: "@unirate/nuxt",
|
|
6
|
+
configKey: "unirate",
|
|
7
|
+
compatibility: { nuxt: ">=3.0.0" },
|
|
8
|
+
},
|
|
9
|
+
defaults: {
|
|
10
|
+
addProxy: true,
|
|
11
|
+
proxyRoute: "/api/_unirate",
|
|
12
|
+
components: true,
|
|
13
|
+
prefix: "",
|
|
14
|
+
},
|
|
15
|
+
setup(options, nuxt) {
|
|
16
|
+
const resolver = createResolver(import.meta.url);
|
|
17
|
+
const apiKey = options.apiKey ?? process.env.UNIRATE_API_KEY ?? "";
|
|
18
|
+
const baseUrl = (options.baseUrl ?? "https://api.unirateapi.com").replace(/\/+$/, "");
|
|
19
|
+
const timeoutMs = options.timeoutMs ?? 30_000;
|
|
20
|
+
const allowedPaths = options.allowedPaths ?? DEFAULT_ALLOWED_PATHS;
|
|
21
|
+
const proxyRoute = options.proxyRoute ?? "/api/_unirate";
|
|
22
|
+
if (!apiKey) {
|
|
23
|
+
console.warn("[@unirate/nuxt] No API key set. Provide `unirate.apiKey` in nuxt.config or " +
|
|
24
|
+
"the NUXT_UNIRATE_API_KEY / UNIRATE_API_KEY environment variable before making requests.");
|
|
25
|
+
}
|
|
26
|
+
// Private (server-only) config — never bundled into the client.
|
|
27
|
+
const rc = nuxt.options.runtimeConfig;
|
|
28
|
+
rc.unirate = {
|
|
29
|
+
apiKey,
|
|
30
|
+
baseUrl,
|
|
31
|
+
timeoutMs,
|
|
32
|
+
allowedPaths,
|
|
33
|
+
...rc.unirate,
|
|
34
|
+
};
|
|
35
|
+
// Public config — only the proxy route + cookie name reach the browser.
|
|
36
|
+
rc.public.unirate = {
|
|
37
|
+
proxyRoute,
|
|
38
|
+
cookieName: options.cookieName ?? "unirate_currency",
|
|
39
|
+
...rc.public.unirate,
|
|
40
|
+
};
|
|
41
|
+
// Server-side `useUniRateClient()` auto-import (key stays on the server).
|
|
42
|
+
addServerImportsDir(resolver.resolve("./runtime/server/utils"));
|
|
43
|
+
// `useUniRate()` + `useCurrency()` app composables.
|
|
44
|
+
addImportsDir(resolver.resolve("./runtime/composables"));
|
|
45
|
+
// Server proxy route so the client composable never touches the upstream key.
|
|
46
|
+
if (options.addProxy !== false) {
|
|
47
|
+
addServerHandler({
|
|
48
|
+
route: proxyRoute,
|
|
49
|
+
method: "get",
|
|
50
|
+
handler: resolver.resolve("./runtime/server/routes/proxy"),
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
// Presentational components.
|
|
54
|
+
if (options.components !== false) {
|
|
55
|
+
const prefix = options.prefix ?? "";
|
|
56
|
+
addComponent({
|
|
57
|
+
name: `${prefix}Currency`,
|
|
58
|
+
filePath: resolver.resolve("./runtime/components/Currency.vue"),
|
|
59
|
+
});
|
|
60
|
+
addComponent({
|
|
61
|
+
name: `${prefix}Rate`,
|
|
62
|
+
filePath: resolver.resolve("./runtime/components/Rate.vue"),
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
//# sourceMappingURL=module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"module.js","sourceRoot":"","sources":["../src/module.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,gBAAgB,EAChB,cAAc,EACd,YAAY,EACZ,aAAa,EACb,mBAAmB,EACnB,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAuB3D,eAAe,gBAAgB,CAAgB;IAC7C,IAAI,EAAE;QACJ,IAAI,EAAE,eAAe;QACrB,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KACnC;IACD,QAAQ,EAAE;QACR,QAAQ,EAAE,IAAI;QACd,UAAU,EAAE,eAAe;QAC3B,UAAU,EAAE,IAAI;QAChB,MAAM,EAAE,EAAE;KACX;IACD,KAAK,CAAC,OAAO,EAAE,IAAI;QACjB,MAAM,QAAQ,GAAG,cAAc,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QAEjD,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,EAAE,CAAC;QACnE,MAAM,OAAO,GAAG,CAAC,OAAO,CAAC,OAAO,IAAI,4BAA4B,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACtF,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;QAC9C,MAAM,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,qBAAqB,CAAC;QACnE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,eAAe,CAAC;QAEzD,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,OAAO,CAAC,IAAI,CACV,6EAA6E;gBAC3E,yFAAyF,CAC5F,CAAC;QACJ,CAAC;QAED,gEAAgE;QAChE,MAAM,EAAE,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC;QACtC,EAAE,CAAC,OAAO,GAAG;YACX,MAAM;YACN,OAAO;YACP,SAAS;YACT,YAAY;YACZ,GAAI,EAAE,CAAC,OAA+C;SACvD,CAAC;QACF,wEAAwE;QACxE,EAAE,CAAC,MAAM,CAAC,OAAO,GAAG;YAClB,UAAU;YACV,UAAU,EAAE,OAAO,CAAC,UAAU,IAAI,kBAAkB;YACpD,GAAI,EAAE,CAAC,MAAM,CAAC,OAA+C;SAC9D,CAAC;QAEF,0EAA0E;QAC1E,mBAAmB,CAAC,QAAQ,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAC,CAAC;QAEhE,oDAAoD;QACpD,aAAa,CAAC,QAAQ,CAAC,OAAO,CAAC,uBAAuB,CAAC,CAAC,CAAC;QAEzD,8EAA8E;QAC9E,IAAI,OAAO,CAAC,QAAQ,KAAK,KAAK,EAAE,CAAC;YAC/B,gBAAgB,CAAC;gBACf,KAAK,EAAE,UAAU;gBACjB,MAAM,EAAE,KAAK;gBACb,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,+BAA+B,CAAC;aAC3D,CAAC,CAAC;QACL,CAAC;QAED,6BAA6B;QAC7B,IAAI,OAAO,CAAC,UAAU,KAAK,KAAK,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC;YACpC,YAAY,CAAC;gBACX,IAAI,EAAE,GAAG,MAAM,UAAU;gBACzB,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,mCAAmC,CAAC;aAChE,CAAC,CAAC;YACH,YAAY,CAAC;gBACX,IAAI,EAAE,GAAG,MAAM,MAAM;gBACrB,QAAQ,EAAE,QAAQ,CAAC,OAAO,CAAC,+BAA+B,CAAC;aAC5D,CAAC,CAAC;QACL,CAAC;IACH,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export declare class UniRateError extends Error {
|
|
2
|
+
readonly status?: number;
|
|
3
|
+
readonly body?: unknown;
|
|
4
|
+
constructor(message: string, status?: number, body?: unknown);
|
|
5
|
+
}
|
|
6
|
+
export declare class AuthenticationError extends UniRateError {
|
|
7
|
+
constructor(message?: string, body?: unknown);
|
|
8
|
+
}
|
|
9
|
+
export declare class RateLimitError extends UniRateError {
|
|
10
|
+
constructor(message?: string, body?: unknown);
|
|
11
|
+
}
|
|
12
|
+
export declare class InvalidCurrencyError extends UniRateError {
|
|
13
|
+
constructor(message?: string, body?: unknown);
|
|
14
|
+
}
|
|
15
|
+
export declare class InvalidRequestError extends UniRateError {
|
|
16
|
+
constructor(message?: string, body?: unknown);
|
|
17
|
+
}
|
|
18
|
+
export declare class ProRequiredError extends UniRateError {
|
|
19
|
+
constructor(message?: string, body?: unknown);
|
|
20
|
+
}
|
|
21
|
+
export interface UniRateClientOptions {
|
|
22
|
+
apiKey: string;
|
|
23
|
+
baseUrl?: string;
|
|
24
|
+
fetch?: typeof fetch;
|
|
25
|
+
timeoutMs?: number;
|
|
26
|
+
userAgent?: string;
|
|
27
|
+
}
|
|
28
|
+
export declare const DEFAULT_BASE_URL = "https://api.unirateapi.com";
|
|
29
|
+
export interface VATEntry {
|
|
30
|
+
country_code: string;
|
|
31
|
+
country_name: string;
|
|
32
|
+
vat_rate: number;
|
|
33
|
+
}
|
|
34
|
+
export interface VATRatesAll {
|
|
35
|
+
total_countries: number;
|
|
36
|
+
date: string;
|
|
37
|
+
vat_rates: Record<string, VATEntry>;
|
|
38
|
+
}
|
|
39
|
+
export interface VATRateOne {
|
|
40
|
+
country: string;
|
|
41
|
+
vat_data: VATEntry;
|
|
42
|
+
}
|
|
43
|
+
export interface HistoricalLimitsResponse {
|
|
44
|
+
total_currencies: number;
|
|
45
|
+
data_source: string;
|
|
46
|
+
currencies: Record<string, {
|
|
47
|
+
earliest_date: string;
|
|
48
|
+
latest_date: string;
|
|
49
|
+
total_days: number;
|
|
50
|
+
description: string;
|
|
51
|
+
}>;
|
|
52
|
+
}
|
|
53
|
+
export declare class UniRateClient {
|
|
54
|
+
#private;
|
|
55
|
+
constructor(opts: UniRateClientOptions);
|
|
56
|
+
getRate(from: string, to?: string): Promise<number | Record<string, number>>;
|
|
57
|
+
convert(to: string, amount: number, from: string): Promise<number>;
|
|
58
|
+
listCurrencies(): Promise<string[]>;
|
|
59
|
+
getHistoricalRate(date: string, amount: number, from: string, to?: string): Promise<number | Record<string, number>>;
|
|
60
|
+
getVatRates(): Promise<VATRatesAll>;
|
|
61
|
+
getVatRates(country: string): Promise<VATRateOne>;
|
|
62
|
+
getTimeSeries(startDate: string, endDate: string, amount?: number, base?: string, currencies?: string[]): Promise<Record<string, Record<string, number>>>;
|
|
63
|
+
getHistoricalLimits(): Promise<HistoricalLimitsResponse>;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { toNum, toRates } from "./parse.js";
|
|
2
|
+
export class UniRateError extends Error {
|
|
3
|
+
status;
|
|
4
|
+
body;
|
|
5
|
+
constructor(message, status, body) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "UniRateError";
|
|
8
|
+
this.status = status;
|
|
9
|
+
this.body = body;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export class AuthenticationError extends UniRateError {
|
|
13
|
+
constructor(message = "Missing or invalid API key", body) {
|
|
14
|
+
super(message, 401, body);
|
|
15
|
+
this.name = "AuthenticationError";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export class RateLimitError extends UniRateError {
|
|
19
|
+
constructor(message = "Rate limit exceeded", body) {
|
|
20
|
+
super(message, 429, body);
|
|
21
|
+
this.name = "RateLimitError";
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
export class InvalidCurrencyError extends UniRateError {
|
|
25
|
+
constructor(message = "Currency not found or no data available", body) {
|
|
26
|
+
super(message, 404, body);
|
|
27
|
+
this.name = "InvalidCurrencyError";
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export class InvalidRequestError extends UniRateError {
|
|
31
|
+
constructor(message = "Invalid request parameters", body) {
|
|
32
|
+
super(message, 400, body);
|
|
33
|
+
this.name = "InvalidRequestError";
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
export class ProRequiredError extends UniRateError {
|
|
37
|
+
constructor(message = "Endpoint requires a Pro subscription", body) {
|
|
38
|
+
super(message, 403, body);
|
|
39
|
+
this.name = "ProRequiredError";
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
export const DEFAULT_BASE_URL = "https://api.unirateapi.com";
|
|
43
|
+
const DEFAULT_TIMEOUT_MS = 30_000;
|
|
44
|
+
const DEFAULT_USER_AGENT = "@unirate/nuxt/0.1.0";
|
|
45
|
+
export class UniRateClient {
|
|
46
|
+
#apiKey;
|
|
47
|
+
#baseUrl;
|
|
48
|
+
#fetch;
|
|
49
|
+
#timeoutMs;
|
|
50
|
+
#userAgent;
|
|
51
|
+
constructor(opts) {
|
|
52
|
+
if (!opts.apiKey)
|
|
53
|
+
throw new UniRateError("apiKey is required");
|
|
54
|
+
this.#apiKey = opts.apiKey;
|
|
55
|
+
this.#baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
|
|
56
|
+
this.#fetch = opts.fetch ?? globalThis.fetch;
|
|
57
|
+
this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
58
|
+
this.#userAgent = opts.userAgent ?? DEFAULT_USER_AGENT;
|
|
59
|
+
if (typeof this.#fetch !== "function") {
|
|
60
|
+
throw new UniRateError("global fetch is unavailable; pass `fetch` explicitly");
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
async #get(path, params) {
|
|
64
|
+
const url = new URL(this.#baseUrl + path);
|
|
65
|
+
url.searchParams.set("api_key", this.#apiKey);
|
|
66
|
+
for (const [k, v] of Object.entries(params)) {
|
|
67
|
+
if (v !== undefined)
|
|
68
|
+
url.searchParams.set(k, String(v));
|
|
69
|
+
}
|
|
70
|
+
const ctrl = new AbortController();
|
|
71
|
+
const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs);
|
|
72
|
+
let res;
|
|
73
|
+
try {
|
|
74
|
+
res = await this.#fetch(url.toString(), {
|
|
75
|
+
headers: {
|
|
76
|
+
Accept: "application/json",
|
|
77
|
+
"User-Agent": this.#userAgent,
|
|
78
|
+
},
|
|
79
|
+
signal: ctrl.signal,
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
catch (err) {
|
|
83
|
+
clearTimeout(timer);
|
|
84
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
85
|
+
throw new UniRateError(`Request to ${path} failed: ${msg}`);
|
|
86
|
+
}
|
|
87
|
+
clearTimeout(timer);
|
|
88
|
+
const text = await res.text();
|
|
89
|
+
let body = null;
|
|
90
|
+
if (text) {
|
|
91
|
+
try {
|
|
92
|
+
body = JSON.parse(text);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
if (!res.ok) {
|
|
96
|
+
throw new UniRateError(`HTTP ${res.status} from ${path}`, res.status, text);
|
|
97
|
+
}
|
|
98
|
+
throw new UniRateError(`Non-JSON response from ${path}`, res.status, text);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
if (!res.ok) {
|
|
102
|
+
const detail = body && typeof body === "object" && "error" in body && typeof body.error === "string"
|
|
103
|
+
? body.error
|
|
104
|
+
: undefined;
|
|
105
|
+
switch (res.status) {
|
|
106
|
+
case 400:
|
|
107
|
+
throw new InvalidRequestError(detail ?? "Invalid request parameters", body);
|
|
108
|
+
case 401:
|
|
109
|
+
throw new AuthenticationError(detail ?? "Missing or invalid API key", body);
|
|
110
|
+
case 403:
|
|
111
|
+
throw new ProRequiredError(detail ?? "Endpoint requires a Pro subscription", body);
|
|
112
|
+
case 404:
|
|
113
|
+
throw new InvalidCurrencyError(detail ?? "Currency not found or no data available", body);
|
|
114
|
+
case 429:
|
|
115
|
+
throw new RateLimitError(detail ?? "Rate limit exceeded", body);
|
|
116
|
+
default:
|
|
117
|
+
throw new UniRateError(detail ?? `HTTP ${res.status} from ${path}`, res.status, body);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
return body;
|
|
121
|
+
}
|
|
122
|
+
async getRate(from, to) {
|
|
123
|
+
const params = { from: from.toUpperCase() };
|
|
124
|
+
if (to)
|
|
125
|
+
params.to = to.toUpperCase();
|
|
126
|
+
const raw = await this.#get("/api/rates", params);
|
|
127
|
+
if (to) {
|
|
128
|
+
if (raw.rate === undefined)
|
|
129
|
+
throw new UniRateError("Malformed /api/rates response", undefined, raw);
|
|
130
|
+
return toNum(raw.rate);
|
|
131
|
+
}
|
|
132
|
+
if (!raw.rates)
|
|
133
|
+
throw new UniRateError("Malformed /api/rates response", undefined, raw);
|
|
134
|
+
return toRates(raw.rates);
|
|
135
|
+
}
|
|
136
|
+
async convert(to, amount, from) {
|
|
137
|
+
const raw = await this.#get("/api/convert", {
|
|
138
|
+
from: from.toUpperCase(),
|
|
139
|
+
to: to.toUpperCase(),
|
|
140
|
+
amount,
|
|
141
|
+
});
|
|
142
|
+
if (raw.result === undefined) {
|
|
143
|
+
throw new UniRateError("Malformed /api/convert response", undefined, raw);
|
|
144
|
+
}
|
|
145
|
+
return toNum(raw.result);
|
|
146
|
+
}
|
|
147
|
+
async listCurrencies() {
|
|
148
|
+
const raw = await this.#get("/api/currencies", {});
|
|
149
|
+
if (!Array.isArray(raw.currencies)) {
|
|
150
|
+
throw new UniRateError("Malformed /api/currencies response", undefined, raw);
|
|
151
|
+
}
|
|
152
|
+
return raw.currencies;
|
|
153
|
+
}
|
|
154
|
+
async getHistoricalRate(date, amount, from, to) {
|
|
155
|
+
const params = {
|
|
156
|
+
date,
|
|
157
|
+
amount,
|
|
158
|
+
from: from.toUpperCase(),
|
|
159
|
+
};
|
|
160
|
+
if (to)
|
|
161
|
+
params.to = to.toUpperCase();
|
|
162
|
+
const raw = await this.#get("/api/historical/rates", params);
|
|
163
|
+
if (to) {
|
|
164
|
+
const v = amount === 1 ? raw.rate : raw.result;
|
|
165
|
+
if (v === undefined) {
|
|
166
|
+
throw new UniRateError("Malformed /api/historical/rates response", undefined, raw);
|
|
167
|
+
}
|
|
168
|
+
return toNum(v);
|
|
169
|
+
}
|
|
170
|
+
const map = amount === 1 ? raw.rates : raw.results;
|
|
171
|
+
if (!map) {
|
|
172
|
+
throw new UniRateError("Malformed /api/historical/rates response", undefined, raw);
|
|
173
|
+
}
|
|
174
|
+
return toRates(map);
|
|
175
|
+
}
|
|
176
|
+
async getVatRates(country) {
|
|
177
|
+
const params = {};
|
|
178
|
+
if (country)
|
|
179
|
+
params.country = country.toUpperCase();
|
|
180
|
+
return this.#get("/api/vat/rates", params);
|
|
181
|
+
}
|
|
182
|
+
async getTimeSeries(startDate, endDate, amount = 1, base = "USD", currencies) {
|
|
183
|
+
const params = {
|
|
184
|
+
start_date: startDate,
|
|
185
|
+
end_date: endDate,
|
|
186
|
+
amount,
|
|
187
|
+
base: base.toUpperCase(),
|
|
188
|
+
};
|
|
189
|
+
if (currencies?.length) {
|
|
190
|
+
params.currencies = currencies.map((c) => c.toUpperCase()).join(",");
|
|
191
|
+
}
|
|
192
|
+
const raw = await this.#get("/api/historical/timeseries", params);
|
|
193
|
+
return raw.data;
|
|
194
|
+
}
|
|
195
|
+
async getHistoricalLimits() {
|
|
196
|
+
return this.#get("/api/historical/limits", {});
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/runtime/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
amount: { type: Number, required: true },
|
|
4
|
+
currency: { type: String, required: true },
|
|
5
|
+
decimals: { type: Number, default: 2 },
|
|
6
|
+
locale: { type: String, default: undefined },
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
const formatted = computed(() =>
|
|
10
|
+
new Intl.NumberFormat(props.locale, {
|
|
11
|
+
style: 'currency',
|
|
12
|
+
currency: props.currency,
|
|
13
|
+
minimumFractionDigits: props.decimals,
|
|
14
|
+
maximumFractionDigits: props.decimals,
|
|
15
|
+
}).format(props.amount),
|
|
16
|
+
)
|
|
17
|
+
</script>
|
|
18
|
+
|
|
19
|
+
<template>{{ formatted }}</template>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
const props = defineProps({
|
|
3
|
+
from: { type: String, required: true },
|
|
4
|
+
to: { type: String, required: true },
|
|
5
|
+
rate: { type: Number, required: true },
|
|
6
|
+
decimals: { type: Number, default: 4 },
|
|
7
|
+
locale: { type: String, default: undefined },
|
|
8
|
+
})
|
|
9
|
+
|
|
10
|
+
const formatted = computed(() =>
|
|
11
|
+
new Intl.NumberFormat(props.locale, {
|
|
12
|
+
minimumFractionDigits: props.decimals,
|
|
13
|
+
maximumFractionDigits: props.decimals,
|
|
14
|
+
}).format(props.rate),
|
|
15
|
+
)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>{{ formatted }}</template>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Ref } from "vue";
|
|
2
|
+
export interface UseCurrencyReturn {
|
|
3
|
+
/** Reactive ISO-4217 currency code for the visitor. */
|
|
4
|
+
currency: Ref<string>;
|
|
5
|
+
/** Persist a new currency choice to the cookie + shared state. */
|
|
6
|
+
setCurrency: (code: string) => void;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Detect the visitor's currency once (cookie → Accept-Language → default),
|
|
10
|
+
* share it across the app via `useState`, and persist the choice to a cookie.
|
|
11
|
+
* SSR-safe: header reading happens on the server, the value hydrates to the
|
|
12
|
+
* client.
|
|
13
|
+
*/
|
|
14
|
+
export declare function useCurrency(defaultCurrency?: string): UseCurrencyReturn;
|
|
15
|
+
//# sourceMappingURL=useCurrency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCurrency.d.ts","sourceRoot":"","sources":["../../../src/runtime/composables/useCurrency.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAI/B,MAAM,WAAW,iBAAiB;IAChC,uDAAuD;IACvD,QAAQ,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACtB,kEAAkE;IAClE,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC;AAED;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,eAAe,SAAQ,GAAG,iBAAiB,CA6BtE"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { useRuntimeConfig, useState, useCookie, useRequestHeaders } from "#imports";
|
|
2
|
+
import { detectCurrency, UNIRATE_CURRENCY_COOKIE } from "../currency.js";
|
|
3
|
+
/**
|
|
4
|
+
* Detect the visitor's currency once (cookie → Accept-Language → default),
|
|
5
|
+
* share it across the app via `useState`, and persist the choice to a cookie.
|
|
6
|
+
* SSR-safe: header reading happens on the server, the value hydrates to the
|
|
7
|
+
* client.
|
|
8
|
+
*/
|
|
9
|
+
export function useCurrency(defaultCurrency = "USD") {
|
|
10
|
+
const pub = (useRuntimeConfig().public.unirate ?? {});
|
|
11
|
+
const cookieName = pub.cookieName ?? UNIRATE_CURRENCY_COOKIE;
|
|
12
|
+
const cookie = useCookie(cookieName, {
|
|
13
|
+
path: "/",
|
|
14
|
+
sameSite: "lax",
|
|
15
|
+
maxAge: 365 * 24 * 60 * 60,
|
|
16
|
+
});
|
|
17
|
+
const currency = useState("unirate:currency", () => {
|
|
18
|
+
const headers = import.meta.server ? useRequestHeaders(["accept-language"]) : {};
|
|
19
|
+
return detectCurrency({
|
|
20
|
+
cookieValue: cookie.value,
|
|
21
|
+
acceptLanguage: headers["accept-language"] ?? null,
|
|
22
|
+
defaultCurrency,
|
|
23
|
+
});
|
|
24
|
+
});
|
|
25
|
+
if (!cookie.value)
|
|
26
|
+
cookie.value = currency.value;
|
|
27
|
+
function setCurrency(code) {
|
|
28
|
+
const next = code.toUpperCase();
|
|
29
|
+
currency.value = next;
|
|
30
|
+
cookie.value = next;
|
|
31
|
+
}
|
|
32
|
+
return { currency, setCurrency };
|
|
33
|
+
}
|
|
34
|
+
//# sourceMappingURL=useCurrency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useCurrency.js","sourceRoot":"","sources":["../../../src/runtime/composables/useCurrency.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,SAAS,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAEpF,OAAO,EAAE,cAAc,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAUzE;;;;;GAKG;AACH,MAAM,UAAU,WAAW,CAAC,eAAe,GAAG,KAAK;IACjD,MAAM,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,CAEnD,CAAC;IACF,MAAM,UAAU,GAAG,GAAG,CAAC,UAAU,IAAI,uBAAuB,CAAC;IAC7D,MAAM,MAAM,GAAG,SAAS,CAAgB,UAAU,EAAE;QAClD,IAAI,EAAE,GAAG;QACT,QAAQ,EAAE,KAAK;QACf,MAAM,EAAE,GAAG,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;KAC3B,CAAC,CAAC;IAEH,MAAM,QAAQ,GAAG,QAAQ,CAAS,kBAAkB,EAAE,GAAG,EAAE;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,iBAAiB,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QACjF,OAAO,cAAc,CAAC;YACpB,WAAW,EAAE,MAAM,CAAC,KAAK;YACzB,cAAc,EAAE,OAAO,CAAC,iBAAiB,CAAC,IAAI,IAAI;YAClD,eAAe;SAChB,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,MAAM,CAAC,KAAK;QAAE,MAAM,CAAC,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC;IAEjD,SAAS,WAAW,CAAC,IAAY;QAC/B,MAAM,IAAI,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;QAChC,QAAQ,CAAC,KAAK,GAAG,IAAI,CAAC;QACtB,MAAM,CAAC,KAAK,GAAG,IAAI,CAAC;IACtB,CAAC;IAED,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;AACnC,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { HistoricalLimitsResponse, VATRateOne, VATRatesAll } from "../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Universal (SSR + client) UniRate composable. Every call is routed through the
|
|
4
|
+
* server proxy registered by the module, so the API key never reaches the
|
|
5
|
+
* browser. Mirrors the server client's method surface.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useUniRate(): {
|
|
8
|
+
getRate: (from: string, to?: string) => Promise<number | Record<string, number>>;
|
|
9
|
+
convert: (from: string, to: string, amount: number) => Promise<number>;
|
|
10
|
+
listCurrencies: () => Promise<string[]>;
|
|
11
|
+
getHistoricalRate: (date: string, from: string, to?: string, amount?: number) => Promise<number | Record<string, number>>;
|
|
12
|
+
getVatRates: {
|
|
13
|
+
(): Promise<VATRatesAll>;
|
|
14
|
+
(country: string): Promise<VATRateOne>;
|
|
15
|
+
};
|
|
16
|
+
getTimeSeries: (startDate: string, endDate: string, base?: string, currencies?: string[], amount?: number) => Promise<Record<string, Record<string, number>>>;
|
|
17
|
+
getHistoricalLimits: () => Promise<HistoricalLimitsResponse>;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=useUniRate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUniRate.d.ts","sourceRoot":"","sources":["../../../src/runtime/composables/useUniRate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EACV,wBAAwB,EACxB,UAAU,EACV,WAAW,EACZ,MAAM,cAAc,CAAC;AAGtB;;;;GAIG;AACH,wBAAgB,UAAU;oBAgBhB,MAAM,OACP,MAAM,KACV,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;oBASd,MAAM,MAAM,MAAM,UAAU,MAAM,KAAG,OAAO,CAAC,MAAM,CAAC;0BAShD,OAAO,CAAC,MAAM,EAAE,CAAC;8BAM1C,MAAM,QACN,MAAM,OACP,MAAM,sBAEV,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;;YAWnB,OAAO,CAAC,WAAW,CAAC;kBACd,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;;+BAM7C,MAAM,WACR,MAAM,8BAEF,MAAM,EAAE,sBAEpB,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;+BAclB,OAAO,CAAC,wBAAwB,CAAC;EAalE"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
import { toNum, toRates } from "../parse.js";
|
|
3
|
+
/**
|
|
4
|
+
* Universal (SSR + client) UniRate composable. Every call is routed through the
|
|
5
|
+
* server proxy registered by the module, so the API key never reaches the
|
|
6
|
+
* browser. Mirrors the server client's method surface.
|
|
7
|
+
*/
|
|
8
|
+
export function useUniRate() {
|
|
9
|
+
const pub = (useRuntimeConfig().public.unirate ?? {});
|
|
10
|
+
const proxyRoute = pub.proxyRoute ?? "/api/_unirate";
|
|
11
|
+
async function get(path, params = {}) {
|
|
12
|
+
const query = { path };
|
|
13
|
+
for (const [k, v] of Object.entries(params)) {
|
|
14
|
+
if (v !== undefined)
|
|
15
|
+
query[k] = v;
|
|
16
|
+
}
|
|
17
|
+
return $fetch(proxyRoute, { query });
|
|
18
|
+
}
|
|
19
|
+
async function getRate(from, to) {
|
|
20
|
+
const raw = await get("/api/rates", { from: from.toUpperCase(), to: to?.toUpperCase() });
|
|
21
|
+
if (to)
|
|
22
|
+
return toNum(raw.rate);
|
|
23
|
+
return toRates(raw.rates ?? {});
|
|
24
|
+
}
|
|
25
|
+
async function convert(from, to, amount) {
|
|
26
|
+
const raw = await get("/api/convert", {
|
|
27
|
+
from: from.toUpperCase(),
|
|
28
|
+
to: to.toUpperCase(),
|
|
29
|
+
amount,
|
|
30
|
+
});
|
|
31
|
+
return toNum(raw.result);
|
|
32
|
+
}
|
|
33
|
+
async function listCurrencies() {
|
|
34
|
+
const raw = await get("/api/currencies");
|
|
35
|
+
return raw.currencies ?? [];
|
|
36
|
+
}
|
|
37
|
+
async function getHistoricalRate(date, from, to, amount = 1) {
|
|
38
|
+
const raw = await get("/api/historical/rates", { date, amount, from: from.toUpperCase(), to: to?.toUpperCase() });
|
|
39
|
+
if (to)
|
|
40
|
+
return toNum(amount === 1 ? raw.rate : raw.result);
|
|
41
|
+
return toRates((amount === 1 ? raw.rates : raw.results) ?? {});
|
|
42
|
+
}
|
|
43
|
+
function getVatRates(country) {
|
|
44
|
+
return get("/api/vat/rates", { country: country?.toUpperCase() });
|
|
45
|
+
}
|
|
46
|
+
async function getTimeSeries(startDate, endDate, base = "USD", currencies, amount = 1) {
|
|
47
|
+
const raw = await get("/api/historical/timeseries", {
|
|
48
|
+
start_date: startDate,
|
|
49
|
+
end_date: endDate,
|
|
50
|
+
amount,
|
|
51
|
+
base: base.toUpperCase(),
|
|
52
|
+
currencies: currencies?.length ? currencies.map((c) => c.toUpperCase()).join(",") : undefined,
|
|
53
|
+
});
|
|
54
|
+
return raw.data;
|
|
55
|
+
}
|
|
56
|
+
function getHistoricalLimits() {
|
|
57
|
+
return get("/api/historical/limits");
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
getRate,
|
|
61
|
+
convert,
|
|
62
|
+
listCurrencies,
|
|
63
|
+
getHistoricalRate,
|
|
64
|
+
getVatRates,
|
|
65
|
+
getTimeSeries,
|
|
66
|
+
getHistoricalLimits,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=useUniRate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useUniRate.js","sourceRoot":"","sources":["../../../src/runtime/composables/useUniRate.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale → currency heuristics for `useCurrency()`. Pure and dependency-free so
|
|
3
|
+
* the detection logic can be unit-tested in isolation.
|
|
4
|
+
*/
|
|
5
|
+
export declare const LOCALE_CURRENCY: Record<string, string>;
|
|
6
|
+
export declare const LANG_CURRENCY: Record<string, string>;
|
|
7
|
+
export declare const UNIRATE_CURRENCY_COOKIE = "unirate_currency";
|
|
8
|
+
export interface DetectCurrencyOptions {
|
|
9
|
+
acceptLanguage?: string | null;
|
|
10
|
+
cookieValue?: string | null;
|
|
11
|
+
defaultCurrency?: string;
|
|
12
|
+
localeCurrencyMap?: Record<string, string>;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Resolve a currency code from (in precedence order) an existing cookie, the
|
|
16
|
+
* `Accept-Language` header's region/language tags, then a default.
|
|
17
|
+
*/
|
|
18
|
+
export declare function detectCurrency(opts?: DetectCurrencyOptions): string;
|
|
19
|
+
//# sourceMappingURL=currency.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency.d.ts","sourceRoot":"","sources":["../../src/runtime/currency.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmBlD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAOhD,CAAC;AAEF,eAAO,MAAM,uBAAuB,qBAAqB,CAAC;AAE1D,MAAM,WAAW,qBAAqB;IACpC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,iBAAiB,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC5C;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,IAAI,GAAE,qBAA0B,GAAG,MAAM,CAiBvE"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Locale → currency heuristics for `useCurrency()`. Pure and dependency-free so
|
|
3
|
+
* the detection logic can be unit-tested in isolation.
|
|
4
|
+
*/
|
|
5
|
+
export const LOCALE_CURRENCY = {
|
|
6
|
+
US: "USD", GB: "GBP", AU: "AUD", CA: "CAD", NZ: "NZD",
|
|
7
|
+
JP: "JPY", CN: "CNY", HK: "HKD", SG: "SGD", TW: "TWD",
|
|
8
|
+
KR: "KRW", IN: "INR", PH: "PHP", TH: "THB", MY: "MYR",
|
|
9
|
+
ID: "IDR", VN: "VND",
|
|
10
|
+
CH: "CHF", NO: "NOK", SE: "SEK", DK: "DKK", PL: "PLN",
|
|
11
|
+
CZ: "CZK", HU: "HUF", RO: "RON", BG: "BGN", HR: "EUR",
|
|
12
|
+
AT: "EUR", BE: "EUR", CY: "EUR", EE: "EUR", FI: "EUR",
|
|
13
|
+
FR: "EUR", DE: "EUR", GR: "EUR", IE: "EUR", IT: "EUR",
|
|
14
|
+
LV: "EUR", LT: "EUR", LU: "EUR", MT: "EUR", NL: "EUR",
|
|
15
|
+
PT: "EUR", SK: "EUR", SI: "EUR", ES: "EUR",
|
|
16
|
+
BR: "BRL", MX: "MXN", AR: "ARS", CL: "CLP", CO: "COP",
|
|
17
|
+
PE: "PEN", UY: "UYU",
|
|
18
|
+
ZA: "ZAR", NG: "NGN", KE: "KES", GH: "GHS", EG: "EGP",
|
|
19
|
+
MA: "MAD", TN: "TND",
|
|
20
|
+
AE: "AED", SA: "SAR", QA: "QAR", KW: "KWD", BH: "BHD",
|
|
21
|
+
OM: "OMR", JO: "JOD", IL: "ILS", TR: "TRY",
|
|
22
|
+
RU: "RUB", UA: "UAH", KZ: "KZT",
|
|
23
|
+
PK: "PKR", BD: "BDT", LK: "LKR",
|
|
24
|
+
};
|
|
25
|
+
export const LANG_CURRENCY = {
|
|
26
|
+
en: "USD", ja: "JPY", zh: "CNY", ko: "KRW", de: "EUR",
|
|
27
|
+
fr: "EUR", es: "EUR", it: "EUR", pt: "BRL", nl: "EUR",
|
|
28
|
+
sv: "SEK", no: "NOK", da: "DKK", fi: "EUR", pl: "PLN",
|
|
29
|
+
cs: "CZK", hu: "HUF", ro: "RON", bg: "BGN", hr: "EUR",
|
|
30
|
+
tr: "TRY", ar: "SAR", he: "ILS", hi: "INR", th: "THB",
|
|
31
|
+
vi: "VND", ms: "MYR", id: "IDR", ru: "RUB", uk: "UAH",
|
|
32
|
+
};
|
|
33
|
+
export const UNIRATE_CURRENCY_COOKIE = "unirate_currency";
|
|
34
|
+
/**
|
|
35
|
+
* Resolve a currency code from (in precedence order) an existing cookie, the
|
|
36
|
+
* `Accept-Language` header's region/language tags, then a default.
|
|
37
|
+
*/
|
|
38
|
+
export function detectCurrency(opts = {}) {
|
|
39
|
+
if (opts.cookieValue)
|
|
40
|
+
return opts.cookieValue.toUpperCase();
|
|
41
|
+
const accept = opts.acceptLanguage;
|
|
42
|
+
if (accept) {
|
|
43
|
+
const map = opts.localeCurrencyMap ?? LOCALE_CURRENCY;
|
|
44
|
+
for (const part of accept.split(",")) {
|
|
45
|
+
const tag = part.split(";")[0].trim();
|
|
46
|
+
if (!tag)
|
|
47
|
+
continue;
|
|
48
|
+
const region = tag.split("-")[1]?.toUpperCase();
|
|
49
|
+
if (region && map[region])
|
|
50
|
+
return map[region];
|
|
51
|
+
const lang = tag.split("-")[0].toLowerCase();
|
|
52
|
+
if (LANG_CURRENCY[lang])
|
|
53
|
+
return LANG_CURRENCY[lang];
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return (opts.defaultCurrency ?? "USD").toUpperCase();
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=currency.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"currency.js","sourceRoot":"","sources":["../../src/runtime/currency.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../../src/runtime/parse.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,KAAK,GAAI,GAAG,OAAO,KAAG,MAMlC,CAAC;AAEF,eAAO,MAAM,OAAO,GAAI,KAAK,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAI3E,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { UniRateError } from "./client.js";
|
|
2
|
+
export const toNum = (v) => {
|
|
3
|
+
const n = typeof v === "string" ? Number.parseFloat(v) : v;
|
|
4
|
+
if (!Number.isFinite(n)) {
|
|
5
|
+
throw new UniRateError(`Non-numeric value: ${String(v)}`);
|
|
6
|
+
}
|
|
7
|
+
return n;
|
|
8
|
+
};
|
|
9
|
+
export const toRates = (raw) => {
|
|
10
|
+
const out = {};
|
|
11
|
+
for (const [k, v] of Object.entries(raw))
|
|
12
|
+
out[k] = toNum(v);
|
|
13
|
+
return out;
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../../src/runtime/parse.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAE3C,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,CAAU,EAAU,EAAE;IAC1C,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,CAAE,CAAY,CAAC;IACvE,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,YAAY,CAAC,sBAAsB,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IAC5D,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,GAA4B,EAA0B,EAAE;IAC9E,MAAM,GAAG,GAA2B,EAAE,CAAC;IACvC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC;QAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAC5D,OAAO,GAAG,CAAC;AACb,CAAC,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers shared by the server proxy route. Kept dependency-free so they
|
|
3
|
+
* can be unit-tested without an h3 / Nitro runtime.
|
|
4
|
+
*/
|
|
5
|
+
export declare const DEFAULT_ALLOWED_PATHS: string[];
|
|
6
|
+
/** Normalise a caller-supplied `path` query value to a leading-slash API path. */
|
|
7
|
+
export declare function normalizePath(path: string): string;
|
|
8
|
+
export declare function isPathAllowed(path: string, allowed: Iterable<string>): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Build the upstream UniRate URL for a proxied request: injects the server-side
|
|
11
|
+
* api_key and forwards every query param except the routing `path` key.
|
|
12
|
+
*/
|
|
13
|
+
export declare function buildUpstreamUrl(baseUrl: string, apiPath: string, query: Record<string, unknown>, apiKey: string): string;
|
|
14
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../src/runtime/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,eAAO,MAAM,qBAAqB,UAQjC,CAAC;AAEF,kFAAkF;AAClF,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAElD;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,OAAO,CAE9E;AAED;;;GAGG;AACH,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,MAAM,EAAE,MAAM,GACb,MAAM,CAQR"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure helpers shared by the server proxy route. Kept dependency-free so they
|
|
3
|
+
* can be unit-tested without an h3 / Nitro runtime.
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_ALLOWED_PATHS = [
|
|
6
|
+
"/api/rates",
|
|
7
|
+
"/api/convert",
|
|
8
|
+
"/api/currencies",
|
|
9
|
+
"/api/vat/rates",
|
|
10
|
+
"/api/historical/rates",
|
|
11
|
+
"/api/historical/timeseries",
|
|
12
|
+
"/api/historical/limits",
|
|
13
|
+
];
|
|
14
|
+
/** Normalise a caller-supplied `path` query value to a leading-slash API path. */
|
|
15
|
+
export function normalizePath(path) {
|
|
16
|
+
return path.startsWith("/") ? path : `/${path}`;
|
|
17
|
+
}
|
|
18
|
+
export function isPathAllowed(path, allowed) {
|
|
19
|
+
return new Set(allowed).has(normalizePath(path));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Build the upstream UniRate URL for a proxied request: injects the server-side
|
|
23
|
+
* api_key and forwards every query param except the routing `path` key.
|
|
24
|
+
*/
|
|
25
|
+
export function buildUpstreamUrl(baseUrl, apiPath, query, apiKey) {
|
|
26
|
+
const target = new URL(baseUrl.replace(/\/+$/, "") + normalizePath(apiPath));
|
|
27
|
+
target.searchParams.set("api_key", apiKey);
|
|
28
|
+
for (const [k, v] of Object.entries(query)) {
|
|
29
|
+
if (k === "path" || v === undefined || v === null)
|
|
30
|
+
continue;
|
|
31
|
+
target.searchParams.set(k, String(v));
|
|
32
|
+
}
|
|
33
|
+
return target.toString();
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../src/runtime/proxy.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,YAAY;IACZ,cAAc;IACd,iBAAiB;IACjB,gBAAgB;IAChB,uBAAuB;IACvB,4BAA4B;IAC5B,wBAAwB;CACzB,CAAC;AAEF,kFAAkF;AAClF,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;AAClD,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,IAAY,EAAE,OAAyB;IACnE,OAAO,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,GAAG,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC,CAAC;AACnD,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAC9B,OAAe,EACf,OAAe,EACf,KAA8B,EAC9B,MAAc;IAEd,MAAM,MAAM,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,GAAG,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC;IAC7E,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;IAC3C,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,IAAI;YAAE,SAAS;QAC5D,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,MAAM,CAAC,QAAQ,EAAE,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Server proxy: forwards an allow-listed UniRate path to the upstream API while
|
|
3
|
+
* keeping the api_key server-side. Mounted by the module at the configured
|
|
4
|
+
* `proxyRoute` (default `/api/_unirate`). The client `useUniRate()` composable
|
|
5
|
+
* talks to this endpoint, never to the upstream directly.
|
|
6
|
+
*/
|
|
7
|
+
declare const _default: (event: import("h3").H3Event) => Promise<string>;
|
|
8
|
+
export default _default;
|
|
9
|
+
//# sourceMappingURL=proxy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.d.ts","sourceRoot":"","sources":["../../../../src/runtime/server/routes/proxy.ts"],"names":[],"mappings":"AAKA;;;;;GAKG;;AACH,wBA0CG"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { defineEventHandler, getQuery, setResponseHeader, createError } from "h3";
|
|
2
|
+
import { useRuntimeConfig } from "#imports";
|
|
3
|
+
import { buildUpstreamUrl, isPathAllowed } from "../../proxy.js";
|
|
4
|
+
/**
|
|
5
|
+
* Server proxy: forwards an allow-listed UniRate path to the upstream API while
|
|
6
|
+
* keeping the api_key server-side. Mounted by the module at the configured
|
|
7
|
+
* `proxyRoute` (default `/api/_unirate`). The client `useUniRate()` composable
|
|
8
|
+
* talks to this endpoint, never to the upstream directly.
|
|
9
|
+
*/
|
|
10
|
+
export default defineEventHandler(async (event) => {
|
|
11
|
+
const cfg = (useRuntimeConfig().unirate ?? {});
|
|
12
|
+
if (!cfg.apiKey) {
|
|
13
|
+
throw createError({ statusCode: 500, statusMessage: "UniRate API key not configured" });
|
|
14
|
+
}
|
|
15
|
+
const query = getQuery(event);
|
|
16
|
+
const path = typeof query.path === "string" ? query.path : undefined;
|
|
17
|
+
if (!path) {
|
|
18
|
+
throw createError({ statusCode: 400, statusMessage: "Missing 'path' query parameter" });
|
|
19
|
+
}
|
|
20
|
+
const allowed = cfg.allowedPaths ?? [];
|
|
21
|
+
if (!isPathAllowed(path, allowed)) {
|
|
22
|
+
throw createError({ statusCode: 403, statusMessage: `Path not allowed: ${path}` });
|
|
23
|
+
}
|
|
24
|
+
const target = buildUpstreamUrl(cfg.baseUrl ?? "https://api.unirateapi.com", path, query, cfg.apiKey);
|
|
25
|
+
const ctrl = new AbortController();
|
|
26
|
+
const timer = setTimeout(() => ctrl.abort(), cfg.timeoutMs ?? 30_000);
|
|
27
|
+
try {
|
|
28
|
+
const upstream = await fetch(target, {
|
|
29
|
+
headers: { Accept: "application/json", "User-Agent": "@unirate/nuxt/0.1.0" },
|
|
30
|
+
signal: ctrl.signal,
|
|
31
|
+
});
|
|
32
|
+
const text = await upstream.text();
|
|
33
|
+
setResponseHeader(event, "Content-Type", upstream.headers.get("Content-Type") ?? "application/json");
|
|
34
|
+
setResponseHeader(event, "Cache-Control", "public, s-maxage=60, stale-while-revalidate=300");
|
|
35
|
+
event.node.res.statusCode = upstream.status;
|
|
36
|
+
return text;
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
40
|
+
throw createError({ statusCode: 502, statusMessage: `Upstream request failed: ${message}` });
|
|
41
|
+
}
|
|
42
|
+
finally {
|
|
43
|
+
clearTimeout(timer);
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
//# sourceMappingURL=proxy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"proxy.js","sourceRoot":"","sources":["../../../../src/runtime/server/routes/proxy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,QAAQ,EAAE,iBAAiB,EAAE,WAAW,EAAE,MAAM,IAAI,CAAC;AAClF,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,gBAAgB,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAGjE;;;;;GAKG;AACH,eAAe,kBAAkB,CAAC,KAAK,EAAE,KAAK,EAAE,EAAE;IAChD,MAAM,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC,OAAO,IAAI,EAAE,CAAkC,CAAC;IAChF,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,EAAE,gCAAgC,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAA4B,CAAC;IACzD,MAAM,IAAI,GAAG,OAAO,KAAK,CAAC,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC;IACrE,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,EAAE,gCAAgC,EAAE,CAAC,CAAC;IAC1F,CAAC;IAED,MAAM,OAAO,GAAG,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC;IACvC,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE,OAAO,CAAC,EAAE,CAAC;QAClC,MAAM,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,EAAE,qBAAqB,IAAI,EAAE,EAAE,CAAC,CAAC;IACrF,CAAC;IAED,MAAM,MAAM,GAAG,gBAAgB,CAC7B,GAAG,CAAC,OAAO,IAAI,4BAA4B,EAC3C,IAAI,EACJ,KAAK,EACL,GAAG,CAAC,MAAM,CACX,CAAC;IAEF,MAAM,IAAI,GAAG,IAAI,eAAe,EAAE,CAAC;IACnC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,GAAG,CAAC,SAAS,IAAI,MAAM,CAAC,CAAC;IACtE,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,MAAM,EAAE;YACnC,OAAO,EAAE,EAAE,MAAM,EAAE,kBAAkB,EAAE,YAAY,EAAE,qBAAqB,EAAE;YAC5E,MAAM,EAAE,IAAI,CAAC,MAAM;SACpB,CAAC,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;QACnC,iBAAiB,CAAC,KAAK,EAAE,cAAc,EAAE,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,kBAAkB,CAAC,CAAC;QACrG,iBAAiB,CAAC,KAAK,EAAE,eAAe,EAAE,iDAAiD,CAAC,CAAC;QAC7F,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC;QAC5C,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QACjE,MAAM,WAAW,CAAC,EAAE,UAAU,EAAE,GAAG,EAAE,aAAa,EAAE,4BAA4B,OAAO,EAAE,EAAE,CAAC,CAAC;IAC/F,CAAC;YAAS,CAAC;QACT,YAAY,CAAC,KAAK,CAAC,CAAC;IACtB,CAAC;AACH,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { UniRateClient } from "../../client.js";
|
|
2
|
+
/**
|
|
3
|
+
* Server-side UniRate client, auto-imported in `server/`. Reads the API key
|
|
4
|
+
* from the private runtime config so the key never reaches the browser bundle.
|
|
5
|
+
* Returns a process-wide singleton.
|
|
6
|
+
*/
|
|
7
|
+
export declare function useUniRateClient(): UniRateClient;
|
|
8
|
+
//# sourceMappingURL=unirate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unirate.d.ts","sourceRoot":"","sources":["../../../../src/runtime/server/utils/unirate.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAKhD;;;;GAIG;AACH,wBAAgB,gBAAgB,IAAI,aAAa,CAkBhD"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { useRuntimeConfig } from "#imports";
|
|
2
|
+
import { UniRateClient } from "../../client.js";
|
|
3
|
+
let cached;
|
|
4
|
+
/**
|
|
5
|
+
* Server-side UniRate client, auto-imported in `server/`. Reads the API key
|
|
6
|
+
* from the private runtime config so the key never reaches the browser bundle.
|
|
7
|
+
* Returns a process-wide singleton.
|
|
8
|
+
*/
|
|
9
|
+
export function useUniRateClient() {
|
|
10
|
+
if (cached)
|
|
11
|
+
return cached;
|
|
12
|
+
const cfg = (useRuntimeConfig().unirate ?? {});
|
|
13
|
+
if (!cfg.apiKey) {
|
|
14
|
+
throw new Error("UniRate API key not configured. Set `unirate.apiKey` in nuxt.config, or the " +
|
|
15
|
+
"NUXT_UNIRATE_API_KEY / UNIRATE_API_KEY environment variable.");
|
|
16
|
+
}
|
|
17
|
+
cached = new UniRateClient({
|
|
18
|
+
apiKey: cfg.apiKey,
|
|
19
|
+
baseUrl: cfg.baseUrl,
|
|
20
|
+
timeoutMs: cfg.timeoutMs,
|
|
21
|
+
userAgent: "@unirate/nuxt/0.1.0",
|
|
22
|
+
});
|
|
23
|
+
return cached;
|
|
24
|
+
}
|
|
25
|
+
//# sourceMappingURL=unirate.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unirate.js","sourceRoot":"","sources":["../../../../src/runtime/server/utils/unirate.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAGhD,IAAI,MAAiC,CAAC;AAEtC;;;;GAIG;AACH,MAAM,UAAU,gBAAgB;IAC9B,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,GAAG,GAAG,CAAC,gBAAgB,EAAE,CAAC,OAAO,IAAI,EAAE,CAAkC,CAAC;IAChF,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CACb,8EAA8E;YAC5E,8DAA8D,CACjE,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,IAAI,aAAa,CAAC;QACzB,MAAM,EAAE,GAAG,CAAC,MAAM;QAClB,OAAO,EAAE,GAAG,CAAC,OAAO;QACpB,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,SAAS,EAAE,qBAAqB;KACjC,CAAC,CAAC;IACH,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/** Server-only runtime config (never exposed to the client bundle). */
|
|
2
|
+
export interface UniRatePrivateConfig {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
timeoutMs: number;
|
|
6
|
+
allowedPaths: string[];
|
|
7
|
+
}
|
|
8
|
+
/** Public runtime config — only the proxy route path reaches the client. */
|
|
9
|
+
export interface UniRatePublicConfig {
|
|
10
|
+
proxyRoute: string;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":"AAAA,uEAAuE;AACvE,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED,4EAA4E;AAC5E,MAAM,WAAW,mBAAmB;IAClC,UAAU,EAAE,MAAM,CAAC;CACpB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/runtime/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@unirate/nuxt",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Nuxt module for the UniRate currency-exchange API. Server proxy that keeps your API key server-side, useUniRate() + useCurrency() composables, useUniRateClient() server util, and <Currency/> + <Rate/> components. Zero runtime deps.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"author": "UniRate (https://unirateapi.com)",
|
|
8
|
+
"homepage": "https://github.com/UniRate-API/nuxt-unirate#readme",
|
|
9
|
+
"bugs": "https://github.com/UniRate-API/nuxt-unirate/issues",
|
|
10
|
+
"repository": {
|
|
11
|
+
"type": "git",
|
|
12
|
+
"url": "git+https://github.com/UniRate-API/nuxt-unirate.git"
|
|
13
|
+
},
|
|
14
|
+
"keywords": [
|
|
15
|
+
"nuxt",
|
|
16
|
+
"nuxt-module",
|
|
17
|
+
"nuxt3",
|
|
18
|
+
"vue",
|
|
19
|
+
"unirate",
|
|
20
|
+
"currency",
|
|
21
|
+
"currency-converter",
|
|
22
|
+
"exchange-rates",
|
|
23
|
+
"forex",
|
|
24
|
+
"fx",
|
|
25
|
+
"money",
|
|
26
|
+
"fintech"
|
|
27
|
+
],
|
|
28
|
+
"files": [
|
|
29
|
+
"dist",
|
|
30
|
+
"README.md",
|
|
31
|
+
"LICENSE"
|
|
32
|
+
],
|
|
33
|
+
"main": "./dist/module.js",
|
|
34
|
+
"types": "./dist/module.d.ts",
|
|
35
|
+
"exports": {
|
|
36
|
+
".": {
|
|
37
|
+
"types": "./dist/module.d.ts",
|
|
38
|
+
"import": "./dist/module.js"
|
|
39
|
+
},
|
|
40
|
+
"./package.json": "./package.json"
|
|
41
|
+
},
|
|
42
|
+
"scripts": {
|
|
43
|
+
"build": "tsc -p tsconfig.build.json && node scripts/copy-vue.mjs",
|
|
44
|
+
"test": "vitest run",
|
|
45
|
+
"test:watch": "vitest",
|
|
46
|
+
"typecheck": "tsc --noEmit",
|
|
47
|
+
"prepublishOnly": "npm run build"
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@nuxt/kit": "^3.13.0 || ^4.0.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@types/node": "^20.11.0",
|
|
54
|
+
"typescript": "^5.4.0",
|
|
55
|
+
"vitest": "^4.1.7"
|
|
56
|
+
},
|
|
57
|
+
"engines": {
|
|
58
|
+
"node": ">=20.12.0"
|
|
59
|
+
},
|
|
60
|
+
"publishConfig": {
|
|
61
|
+
"access": "public",
|
|
62
|
+
"provenance": true
|
|
63
|
+
}
|
|
64
|
+
}
|