trpc-unirate 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 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,126 @@
1
+ # trpc-unirate
2
+
3
+ [![npm](https://img.shields.io/npm/v/trpc-unirate.svg)](https://www.npmjs.com/package/trpc-unirate)
4
+ [![ci](https://github.com/UniRate-API/trpc-unirate/actions/workflows/ci.yml/badge.svg)](https://github.com/UniRate-API/trpc-unirate/actions/workflows/ci.yml)
5
+ [![license: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
6
+
7
+ Drop-in [tRPC](https://trpc.io) v11 router for the [UniRate](https://unirateapi.com) currency-exchange API. One import, one factory call, seven Zod-validated procedures — `convert`, `rate`, `rates`, `historical`, `timeSeries`, `currencies`, `vat`.
8
+
9
+ UniRate offers **free real-time exchange rates** for 170+ currencies plus VAT data; historical rates and time-series are Pro-tier endpoints.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install trpc-unirate @trpc/server zod
15
+ ```
16
+
17
+ `@trpc/server` and `zod` are peer dependencies — bring your existing versions. Native `fetch` is required (Node ≥ 18.17).
18
+
19
+ ## Quick start
20
+
21
+ ```ts
22
+ import { initTRPC } from "@trpc/server";
23
+ import { createUniRateRouter } from "trpc-unirate";
24
+
25
+ const t = initTRPC.create();
26
+
27
+ export const appRouter = t.router({
28
+ unirate: createUniRateRouter({ apiKey: process.env.UNIRATE_API_KEY! }),
29
+ });
30
+
31
+ export type AppRouter = typeof appRouter;
32
+ ```
33
+
34
+ On the client:
35
+
36
+ ```ts
37
+ const eur = await trpc.unirate.convert.query({ from: "USD", to: "EUR", amount: 100 });
38
+ // ^? number
39
+
40
+ const rates = await trpc.unirate.rates.query({ base: "USD" });
41
+ // ^? Record<string, number>
42
+ ```
43
+
44
+ ## Procedures
45
+
46
+ All procedures are queries (`useQuery` on the React client).
47
+
48
+ | Procedure | Input (Zod-validated) | Output |
49
+ |--------------|--------------------------------------------------------------------------------------|----------------------------------------------|
50
+ | `convert` | `{ from, to, amount? = 1 }` | `number` |
51
+ | `rate` | `{ from? = "USD", to? }` | `number` (when `to` set) \| `Record<string, number>` |
52
+ | `rates` | `{ base? = "USD" }` | `Record<string, number>` |
53
+ | `historical` | `{ date: "YYYY-MM-DD", from? = "USD", to?, amount? = 1 }` (Pro) | `number` \| `Record<string, number>` |
54
+ | `timeSeries` | `{ startDate, endDate, base? = "USD", amount? = 1, currencies?: string[] }` (Pro) | `Record<date, Record<currency, number>>` |
55
+ | `currencies` | _none_ | `string[]` (e.g. `["USD","EUR",...]`) |
56
+ | `vat` | `{ country? }` | `{ total_countries, ... }` or `{ country, vat_data }` |
57
+
58
+ Currency codes are normalized to uppercase before being sent to the API; Zod enforces 3-letter codes (2-letter for `country`).
59
+
60
+ ## Error mapping
61
+
62
+ UniRate API errors are mapped to standard `TRPCError` codes, so your client-side `onError` handlers see familiar shapes:
63
+
64
+ | HTTP | UniRate error class | `TRPCError.code` |
65
+ |------|------------------------|--------------------------|
66
+ | 400 | `InvalidRequestError` | `BAD_REQUEST` |
67
+ | 401 | `AuthenticationError` | `UNAUTHORIZED` |
68
+ | 403 | `ProRequiredError` | `FORBIDDEN` |
69
+ | 404 | `InvalidCurrencyError` | `NOT_FOUND` |
70
+ | 429 | `RateLimitError` | `TOO_MANY_REQUESTS` |
71
+ | other / network | `UniRateError` | `INTERNAL_SERVER_ERROR` |
72
+
73
+ The underlying error is preserved on `cause`.
74
+
75
+ ## Options
76
+
77
+ ```ts
78
+ createUniRateRouter({
79
+ apiKey: process.env.UNIRATE_API_KEY!,
80
+ // Optional:
81
+ baseUrl: "https://api.unirateapi.com", // override for self-hosting / tests
82
+ timeoutMs: 30_000, // per-request timeout
83
+ fetch: globalThis.fetch, // inject a custom fetch (proxies, MSW, etc.)
84
+ userAgent: "myapp/1.0", // overrides "unirate-trpc/x.y.z"
85
+ });
86
+ ```
87
+
88
+ For tests, you can pass a pre-built client instead of an API key:
89
+
90
+ ```ts
91
+ import { UniRateClient, createUniRateRouter } from "trpc-unirate";
92
+
93
+ const client = new UniRateClient({ apiKey: "test", fetch: mockFetch });
94
+ const router = createUniRateRouter({ client });
95
+ const caller = router.createCaller({});
96
+
97
+ expect(await caller.convert({ from: "USD", to: "EUR", amount: 100 })).toBe(92.5);
98
+ ```
99
+
100
+ ## Why a separate router?
101
+
102
+ `createUniRateRouter()` returns a fully-built tRPC v11 router. Nest it under any key in your own router via the object form (`t.router({ unirate: ... })`). The router uses its own `initTRPC.create()` internally, which means:
103
+
104
+ - ✅ No coupling to your context, transformer, or middleware.
105
+ - ✅ Zero changes to your existing tRPC setup.
106
+ - ✅ Procedures still appear in your generated client types.
107
+
108
+ If you need shared context (auth, request-scoped caching, etc.) on the UniRate procedures, build them directly with your own `t.procedure` using the exported `UniRateClient` — the schemas live in `uniRateInputSchemas` for re-use.
109
+
110
+ ## Standalone server example
111
+
112
+ A minimal runnable example lives in [`examples/server.ts`](examples/server.ts). Start it with:
113
+
114
+ ```bash
115
+ UNIRATE_API_KEY=your-key npx tsx examples/server.ts
116
+ ```
117
+
118
+ ## Related
119
+
120
+ - [`unirate-api`](https://www.npmjs.com/package/unirate-api) — the official Node.js client (used internally as reference; this package re-implements the HTTP surface with zero runtime deps).
121
+ - [`@unirate/mcp`](https://www.npmjs.com/package/@unirate/mcp) — Model Context Protocol server for UniRate (use UniRate from Claude Desktop, Cline, etc.).
122
+ - [`@unirate/astro`](https://www.npmjs.com/package/@unirate/astro), [`@unirate/eleventy`](https://www.npmjs.com/package/@unirate/eleventy) — build-time SSG integrations.
123
+
124
+ ## License
125
+
126
+ MIT
@@ -0,0 +1,63 @@
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 interface VATEntry {
29
+ country_code: string;
30
+ country_name: string;
31
+ vat_rate: number;
32
+ }
33
+ export interface VATRatesAll {
34
+ total_countries: number;
35
+ date: string;
36
+ vat_rates: Record<string, VATEntry>;
37
+ }
38
+ export interface VATRateOne {
39
+ country: string;
40
+ vat_data: VATEntry;
41
+ }
42
+ export interface HistoricalLimitsResponse {
43
+ total_currencies: number;
44
+ data_source: string;
45
+ currencies: Record<string, {
46
+ earliest_date: string;
47
+ latest_date: string;
48
+ total_days: number;
49
+ description: string;
50
+ }>;
51
+ }
52
+ export declare class UniRateClient {
53
+ #private;
54
+ constructor(opts: UniRateClientOptions);
55
+ getRate(from: string, to?: string): Promise<number | Record<string, number>>;
56
+ convert(to: string, amount: number, from: string): Promise<number>;
57
+ listCurrencies(): Promise<string[]>;
58
+ getHistoricalRate(date: string, amount: number, from: string, to?: string): Promise<number | Record<string, number>>;
59
+ getTimeSeries(startDate: string, endDate: string, amount: number, base: string, currencies?: string[]): Promise<Record<string, Record<string, number>>>;
60
+ getHistoricalLimits(): Promise<HistoricalLimitsResponse>;
61
+ getVATRates(country?: string): Promise<VATRatesAll | VATRateOne>;
62
+ }
63
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
package/dist/client.js ADDED
@@ -0,0 +1,226 @@
1
+ // Tiny zero-dependency fetch wrapper around the UniRate REST API.
2
+ //
3
+ // Stays dependency-free so the package adds no runtime weight beyond
4
+ // its peer dependencies (@trpc/server, zod). Native fetch is required
5
+ // (Node 18.17+, the package's declared engines floor).
6
+ //
7
+ // `Accept: application/json` is set on every request because UniRate's
8
+ // /api/currencies endpoint returns an HTML 404 without it — see the
9
+ // workspace CLAUDE.md "Key gotchas" #2.
10
+ export class UniRateError extends Error {
11
+ status;
12
+ body;
13
+ constructor(message, status, body) {
14
+ super(message);
15
+ this.name = "UniRateError";
16
+ this.status = status;
17
+ this.body = body;
18
+ }
19
+ }
20
+ export class AuthenticationError extends UniRateError {
21
+ constructor(message = "Missing or invalid API key", body) {
22
+ super(message, 401, body);
23
+ this.name = "AuthenticationError";
24
+ }
25
+ }
26
+ export class RateLimitError extends UniRateError {
27
+ constructor(message = "Rate limit exceeded", body) {
28
+ super(message, 429, body);
29
+ this.name = "RateLimitError";
30
+ }
31
+ }
32
+ export class InvalidCurrencyError extends UniRateError {
33
+ constructor(message = "Currency not found or no data available", body) {
34
+ super(message, 404, body);
35
+ this.name = "InvalidCurrencyError";
36
+ }
37
+ }
38
+ export class InvalidRequestError extends UniRateError {
39
+ constructor(message = "Invalid request parameters", body) {
40
+ super(message, 400, body);
41
+ this.name = "InvalidRequestError";
42
+ }
43
+ }
44
+ export class ProRequiredError extends UniRateError {
45
+ constructor(message = "Endpoint requires a Pro subscription", body) {
46
+ super(message, 403, body);
47
+ this.name = "ProRequiredError";
48
+ }
49
+ }
50
+ const DEFAULT_BASE_URL = "https://api.unirateapi.com";
51
+ const DEFAULT_TIMEOUT_MS = 30_000;
52
+ const DEFAULT_USER_AGENT = "unirate-trpc/0.1.0";
53
+ const toNum = (v) => {
54
+ const n = typeof v === "string" ? Number.parseFloat(v) : v;
55
+ if (!Number.isFinite(n)) {
56
+ throw new UniRateError(`Non-numeric value: ${String(v)}`);
57
+ }
58
+ return n;
59
+ };
60
+ const toRates = (raw) => {
61
+ const out = {};
62
+ for (const [k, v] of Object.entries(raw))
63
+ out[k] = toNum(v);
64
+ return out;
65
+ };
66
+ export class UniRateClient {
67
+ #apiKey;
68
+ #baseUrl;
69
+ #fetch;
70
+ #timeoutMs;
71
+ #userAgent;
72
+ constructor(opts) {
73
+ if (!opts.apiKey)
74
+ throw new UniRateError("apiKey is required");
75
+ this.#apiKey = opts.apiKey;
76
+ this.#baseUrl = (opts.baseUrl ?? DEFAULT_BASE_URL).replace(/\/+$/, "");
77
+ this.#fetch = opts.fetch ?? globalThis.fetch;
78
+ this.#timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
79
+ this.#userAgent = opts.userAgent ?? DEFAULT_USER_AGENT;
80
+ if (typeof this.#fetch !== "function") {
81
+ throw new UniRateError("global fetch is unavailable; pass `fetch` explicitly");
82
+ }
83
+ }
84
+ async #get(path, params) {
85
+ const url = new URL(this.#baseUrl + path);
86
+ url.searchParams.set("api_key", this.#apiKey);
87
+ for (const [k, v] of Object.entries(params)) {
88
+ if (v !== undefined)
89
+ url.searchParams.set(k, String(v));
90
+ }
91
+ const ctrl = new AbortController();
92
+ const timer = setTimeout(() => ctrl.abort(), this.#timeoutMs);
93
+ let res;
94
+ try {
95
+ res = await this.#fetch(url.toString(), {
96
+ headers: {
97
+ Accept: "application/json",
98
+ "User-Agent": this.#userAgent,
99
+ },
100
+ signal: ctrl.signal,
101
+ });
102
+ }
103
+ catch (err) {
104
+ clearTimeout(timer);
105
+ const msg = err instanceof Error ? err.message : String(err);
106
+ throw new UniRateError(`Request to ${path} failed: ${msg}`);
107
+ }
108
+ clearTimeout(timer);
109
+ const text = await res.text();
110
+ let body = null;
111
+ if (text) {
112
+ try {
113
+ body = JSON.parse(text);
114
+ }
115
+ catch {
116
+ if (!res.ok) {
117
+ throw new UniRateError(`HTTP ${res.status} from ${path}`, res.status, text);
118
+ }
119
+ throw new UniRateError(`Non-JSON response from ${path}`, res.status, text);
120
+ }
121
+ }
122
+ if (!res.ok) {
123
+ const detail = body && typeof body === "object" && "error" in body && typeof body.error === "string"
124
+ ? body.error
125
+ : undefined;
126
+ switch (res.status) {
127
+ case 400:
128
+ throw new InvalidRequestError(detail ?? "Invalid request parameters", body);
129
+ case 401:
130
+ throw new AuthenticationError(detail ?? "Missing or invalid API key", body);
131
+ case 403:
132
+ throw new ProRequiredError(detail ?? "Endpoint requires a Pro subscription", body);
133
+ case 404:
134
+ throw new InvalidCurrencyError(detail ?? "Currency not found or no data available", body);
135
+ case 429:
136
+ throw new RateLimitError(detail ?? "Rate limit exceeded", body);
137
+ default:
138
+ throw new UniRateError(detail ?? `HTTP ${res.status} from ${path}`, res.status, body);
139
+ }
140
+ }
141
+ return body;
142
+ }
143
+ async getRate(from, to) {
144
+ const params = { from: from.toUpperCase() };
145
+ if (to)
146
+ params.to = to.toUpperCase();
147
+ const raw = await this.#get("/api/rates", params);
148
+ if (to) {
149
+ if (raw.rate === undefined)
150
+ throw new UniRateError("Malformed /api/rates response", undefined, raw);
151
+ return toNum(raw.rate);
152
+ }
153
+ if (!raw.rates)
154
+ throw new UniRateError("Malformed /api/rates response", undefined, raw);
155
+ return toRates(raw.rates);
156
+ }
157
+ async convert(to, amount, from) {
158
+ const raw = await this.#get("/api/convert", {
159
+ from: from.toUpperCase(),
160
+ to: to.toUpperCase(),
161
+ amount,
162
+ });
163
+ if (raw.result === undefined) {
164
+ throw new UniRateError("Malformed /api/convert response", undefined, raw);
165
+ }
166
+ return toNum(raw.result);
167
+ }
168
+ async listCurrencies() {
169
+ const raw = await this.#get("/api/currencies", {});
170
+ if (!Array.isArray(raw.currencies)) {
171
+ throw new UniRateError("Malformed /api/currencies response", undefined, raw);
172
+ }
173
+ return raw.currencies;
174
+ }
175
+ async getHistoricalRate(date, amount, from, to) {
176
+ const params = {
177
+ date,
178
+ amount,
179
+ from: from.toUpperCase(),
180
+ };
181
+ if (to)
182
+ params.to = to.toUpperCase();
183
+ const raw = await this.#get("/api/historical/rates", params);
184
+ if (to) {
185
+ const v = amount === 1 ? raw.rate : raw.result;
186
+ if (v === undefined) {
187
+ throw new UniRateError("Malformed /api/historical/rates response", undefined, raw);
188
+ }
189
+ return toNum(v);
190
+ }
191
+ const map = amount === 1 ? raw.rates : raw.results;
192
+ if (!map) {
193
+ throw new UniRateError("Malformed /api/historical/rates response", undefined, raw);
194
+ }
195
+ return toRates(map);
196
+ }
197
+ async getTimeSeries(startDate, endDate, amount, base, currencies) {
198
+ const params = {
199
+ start_date: startDate,
200
+ end_date: endDate,
201
+ amount,
202
+ base: base.toUpperCase(),
203
+ };
204
+ if (currencies && currencies.length > 0) {
205
+ params.currencies = currencies.map((c) => c.toUpperCase()).join(",");
206
+ }
207
+ const raw = await this.#get("/api/historical/timeseries", params);
208
+ if (!raw.data) {
209
+ throw new UniRateError("Malformed /api/historical/timeseries response", undefined, raw);
210
+ }
211
+ const out = {};
212
+ for (const [day, rates] of Object.entries(raw.data))
213
+ out[day] = toRates(rates);
214
+ return out;
215
+ }
216
+ async getHistoricalLimits() {
217
+ return this.#get("/api/historical/limits", {});
218
+ }
219
+ async getVATRates(country) {
220
+ const params = {};
221
+ if (country)
222
+ params.country = country.toUpperCase();
223
+ return this.#get("/api/vat/rates", params);
224
+ }
225
+ }
226
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export { createUniRateRouter, uniRateInputSchemas, type CreateUniRateRouterOptions, type UniRateRouter, } from "./router.js";
2
+ export { UniRateClient, UniRateError, AuthenticationError, InvalidCurrencyError, InvalidRequestError, ProRequiredError, RateLimitError, type UniRateClientOptions, type VATEntry, type VATRatesAll, type VATRateOne, type HistoricalLimitsResponse, } from "./client.js";
3
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,EACnB,KAAK,0BAA0B,EAC/B,KAAK,aAAa,GACnB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,KAAK,oBAAoB,EACzB,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,wBAAwB,GAC9B,MAAM,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,3 @@
1
+ export { createUniRateRouter, uniRateInputSchemas, } from "./router.js";
2
+ export { UniRateClient, UniRateError, AuthenticationError, InvalidCurrencyError, InvalidRequestError, ProRequiredError, RateLimitError, } from "./client.js";
3
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,mBAAmB,EACnB,mBAAmB,GAGpB,MAAM,aAAa,CAAC;AAErB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,GAMf,MAAM,aAAa,CAAC"}
@@ -0,0 +1,119 @@
1
+ import { z } from "zod";
2
+ import { UniRateClient, type UniRateClientOptions } from "./client.js";
3
+ export interface CreateUniRateRouterOptions extends Partial<UniRateClientOptions> {
4
+ /** Required unless `client` is supplied. */
5
+ apiKey?: string;
6
+ /** Inject a pre-built client (for tests, or to share with the rest of your app). */
7
+ client?: UniRateClient;
8
+ }
9
+ export declare const uniRateInputSchemas: {
10
+ convert: z.ZodObject<{
11
+ from: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
12
+ to: z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>;
13
+ amount: z.ZodDefault<z.ZodNumber>;
14
+ }, z.core.$strip>;
15
+ rate: z.ZodObject<{
16
+ from: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
17
+ to: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
18
+ }, z.core.$strip>;
19
+ rates: z.ZodObject<{
20
+ base: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
21
+ }, z.core.$strip>;
22
+ historical: z.ZodObject<{
23
+ date: z.ZodString;
24
+ from: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
25
+ to: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
26
+ amount: z.ZodDefault<z.ZodNumber>;
27
+ }, z.core.$strip>;
28
+ timeSeries: z.ZodObject<{
29
+ startDate: z.ZodString;
30
+ endDate: z.ZodString;
31
+ base: z.ZodDefault<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
32
+ amount: z.ZodDefault<z.ZodNumber>;
33
+ currencies: z.ZodOptional<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>>;
34
+ }, z.core.$strip>;
35
+ vat: z.ZodObject<{
36
+ country: z.ZodOptional<z.ZodPipe<z.ZodString, z.ZodTransform<string, string>>>;
37
+ }, z.core.$strip>;
38
+ };
39
+ /**
40
+ * Build a tRPC v11 router exposing the UniRate API.
41
+ *
42
+ * Creates its own `initTRPC.create()` instance and returns a fully-built
43
+ * router with seven query procedures: `convert`, `rate`, `rates`,
44
+ * `historical`, `timeSeries`, `currencies`, `vat`. Nest the result under
45
+ * any key in your own router via the object form:
46
+ *
47
+ * t.router({ unirate: createUniRateRouter({ apiKey }) })
48
+ *
49
+ * Errors from the UniRate API are mapped to typed `TRPCError` codes
50
+ * (`UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BAD_REQUEST`,
51
+ * `TOO_MANY_REQUESTS`, `INTERNAL_SERVER_ERROR`) so client-side
52
+ * `useQuery({ onError })` handlers see standard tRPC error shapes.
53
+ */
54
+ export declare const createUniRateRouter: (opts: CreateUniRateRouterOptions) => import("@trpc/server").TRPCBuiltRouter<{
55
+ ctx: object;
56
+ meta: object;
57
+ errorShape: import("@trpc/server").TRPCDefaultErrorShape;
58
+ transformer: false;
59
+ }, import("@trpc/server").TRPCDecorateCreateRouterOptions<{
60
+ convert: import("@trpc/server").TRPCQueryProcedure<{
61
+ input: {
62
+ from: string;
63
+ to: string;
64
+ amount?: number | undefined;
65
+ };
66
+ output: number;
67
+ meta: object;
68
+ }>;
69
+ rate: import("@trpc/server").TRPCQueryProcedure<{
70
+ input: {
71
+ from?: string | undefined;
72
+ to?: string | undefined;
73
+ };
74
+ output: number | Record<string, number>;
75
+ meta: object;
76
+ }>;
77
+ rates: import("@trpc/server").TRPCQueryProcedure<{
78
+ input: {
79
+ base?: string | undefined;
80
+ };
81
+ output: Record<string, number>;
82
+ meta: object;
83
+ }>;
84
+ historical: import("@trpc/server").TRPCQueryProcedure<{
85
+ input: {
86
+ date: string;
87
+ from?: string | undefined;
88
+ to?: string | undefined;
89
+ amount?: number | undefined;
90
+ };
91
+ output: number | Record<string, number>;
92
+ meta: object;
93
+ }>;
94
+ timeSeries: import("@trpc/server").TRPCQueryProcedure<{
95
+ input: {
96
+ startDate: string;
97
+ endDate: string;
98
+ base?: string | undefined;
99
+ amount?: number | undefined;
100
+ currencies?: string[] | undefined;
101
+ };
102
+ output: Record<string, Record<string, number>>;
103
+ meta: object;
104
+ }>;
105
+ currencies: import("@trpc/server").TRPCQueryProcedure<{
106
+ input: void;
107
+ output: string[];
108
+ meta: object;
109
+ }>;
110
+ vat: import("@trpc/server").TRPCQueryProcedure<{
111
+ input: {
112
+ country?: string | undefined;
113
+ };
114
+ output: import("./client.js").VATRatesAll | import("./client.js").VATRateOne;
115
+ meta: object;
116
+ }>;
117
+ }>>;
118
+ export type UniRateRouter = ReturnType<typeof createUniRateRouter>;
119
+ //# sourceMappingURL=router.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAgBA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAML,aAAa,EAEb,KAAK,oBAAoB,EAC1B,MAAM,aAAa,CAAC;AAErB,MAAM,WAAW,0BAA2B,SAAQ,OAAO,CAAC,oBAAoB,CAAC;IAC/E,4CAA4C;IAC5C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oFAAoF;IACpF,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAqDD,eAAO,MAAM,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAAS,CAAC;AAyC1C;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,mBAAmB,GAAI,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCnE,CAAC;AAEF,MAAM,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,mBAAmB,CAAC,CAAC"}
package/dist/router.js ADDED
@@ -0,0 +1,135 @@
1
+ // Drop-in tRPC router factory that wraps the UniRate REST API.
2
+ //
3
+ // Usage in a consumer app:
4
+ //
5
+ // import { initTRPC } from "@trpc/server";
6
+ // import { createUniRateRouter } from "@unirate/trpc";
7
+ //
8
+ // const t = initTRPC.create();
9
+ // export const appRouter = t.router({
10
+ // unirate: createUniRateRouter({ apiKey: process.env.UNIRATE_API_KEY! }),
11
+ // });
12
+ //
13
+ // The returned object is a fully-built tRPC v11 router. It can be nested
14
+ // under any key in your own router via the object form above.
15
+ import { TRPCError, initTRPC } from "@trpc/server";
16
+ import { z } from "zod";
17
+ import { AuthenticationError, InvalidCurrencyError, InvalidRequestError, ProRequiredError, RateLimitError, UniRateClient, UniRateError, } from "./client.js";
18
+ const currency = z
19
+ .string()
20
+ .trim()
21
+ .length(3, "currency code must be 3 letters")
22
+ .transform((s) => s.toUpperCase());
23
+ const isoDate = z
24
+ .string()
25
+ .regex(/^\d{4}-\d{2}-\d{2}$/, "expected YYYY-MM-DD");
26
+ const positiveAmount = z
27
+ .number()
28
+ .finite("amount must be finite")
29
+ .positive("amount must be positive");
30
+ const inputs = {
31
+ convert: z.object({
32
+ from: currency,
33
+ to: currency,
34
+ amount: positiveAmount.default(1),
35
+ }),
36
+ rate: z.object({
37
+ from: currency.default("USD"),
38
+ to: currency.optional(),
39
+ }),
40
+ rates: z.object({
41
+ base: currency.default("USD"),
42
+ }),
43
+ historical: z.object({
44
+ date: isoDate,
45
+ from: currency.default("USD"),
46
+ to: currency.optional(),
47
+ amount: positiveAmount.default(1),
48
+ }),
49
+ timeSeries: z.object({
50
+ startDate: isoDate,
51
+ endDate: isoDate,
52
+ base: currency.default("USD"),
53
+ amount: positiveAmount.default(1),
54
+ currencies: z.array(currency).max(50).optional(),
55
+ }),
56
+ vat: z.object({
57
+ country: z
58
+ .string()
59
+ .trim()
60
+ .length(2, "country code must be 2 letters")
61
+ .transform((s) => s.toUpperCase())
62
+ .optional(),
63
+ }),
64
+ };
65
+ export const uniRateInputSchemas = inputs;
66
+ const wrap = async (fn) => {
67
+ try {
68
+ return await fn();
69
+ }
70
+ catch (err) {
71
+ if (err instanceof TRPCError)
72
+ throw err;
73
+ if (err instanceof AuthenticationError) {
74
+ throw new TRPCError({ code: "UNAUTHORIZED", message: err.message, cause: err });
75
+ }
76
+ if (err instanceof ProRequiredError) {
77
+ throw new TRPCError({ code: "FORBIDDEN", message: err.message, cause: err });
78
+ }
79
+ if (err instanceof InvalidCurrencyError) {
80
+ throw new TRPCError({ code: "NOT_FOUND", message: err.message, cause: err });
81
+ }
82
+ if (err instanceof InvalidRequestError) {
83
+ throw new TRPCError({ code: "BAD_REQUEST", message: err.message, cause: err });
84
+ }
85
+ if (err instanceof RateLimitError) {
86
+ throw new TRPCError({ code: "TOO_MANY_REQUESTS", message: err.message, cause: err });
87
+ }
88
+ if (err instanceof UniRateError) {
89
+ throw new TRPCError({
90
+ code: "INTERNAL_SERVER_ERROR",
91
+ message: err.message,
92
+ cause: err,
93
+ });
94
+ }
95
+ throw err;
96
+ }
97
+ };
98
+ const resolveClient = (opts) => {
99
+ if (opts.client)
100
+ return opts.client;
101
+ if (!opts.apiKey) {
102
+ throw new UniRateError("createUniRateRouter requires `apiKey` or `client`");
103
+ }
104
+ return new UniRateClient({ ...opts, apiKey: opts.apiKey });
105
+ };
106
+ /**
107
+ * Build a tRPC v11 router exposing the UniRate API.
108
+ *
109
+ * Creates its own `initTRPC.create()` instance and returns a fully-built
110
+ * router with seven query procedures: `convert`, `rate`, `rates`,
111
+ * `historical`, `timeSeries`, `currencies`, `vat`. Nest the result under
112
+ * any key in your own router via the object form:
113
+ *
114
+ * t.router({ unirate: createUniRateRouter({ apiKey }) })
115
+ *
116
+ * Errors from the UniRate API are mapped to typed `TRPCError` codes
117
+ * (`UNAUTHORIZED`, `FORBIDDEN`, `NOT_FOUND`, `BAD_REQUEST`,
118
+ * `TOO_MANY_REQUESTS`, `INTERNAL_SERVER_ERROR`) so client-side
119
+ * `useQuery({ onError })` handlers see standard tRPC error shapes.
120
+ */
121
+ export const createUniRateRouter = (opts) => {
122
+ const client = resolveClient(opts);
123
+ const t = initTRPC.create();
124
+ const proc = t.procedure;
125
+ return t.router({
126
+ convert: proc.input(inputs.convert).query(({ input }) => wrap(() => client.convert(input.to, input.amount, input.from))),
127
+ rate: proc.input(inputs.rate).query(({ input }) => wrap(() => client.getRate(input.from, input.to))),
128
+ rates: proc.input(inputs.rates).query(({ input }) => wrap(() => client.getRate(input.base))),
129
+ historical: proc.input(inputs.historical).query(({ input }) => wrap(() => client.getHistoricalRate(input.date, input.amount, input.from, input.to))),
130
+ timeSeries: proc.input(inputs.timeSeries).query(({ input }) => wrap(() => client.getTimeSeries(input.startDate, input.endDate, input.amount, input.base, input.currencies))),
131
+ currencies: proc.query(() => wrap(() => client.listCurrencies())),
132
+ vat: proc.input(inputs.vat).query(({ input }) => wrap(() => client.getVATRates(input.country))),
133
+ });
134
+ };
135
+ //# sourceMappingURL=router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../src/router.ts"],"names":[],"mappings":"AAAA,+DAA+D;AAC/D,EAAE;AACF,2BAA2B;AAC3B,EAAE;AACF,6CAA6C;AAC7C,yDAAyD;AACzD,EAAE;AACF,iCAAiC;AACjC,wCAAwC;AACxC,8EAA8E;AAC9E,QAAQ;AACR,EAAE;AACF,yEAAyE;AACzE,8DAA8D;AAE9D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACnD,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EACL,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACnB,gBAAgB,EAChB,cAAc,EACd,aAAa,EACb,YAAY,GAEb,MAAM,aAAa,CAAC;AASrB,MAAM,QAAQ,GAAG,CAAC;KACf,MAAM,EAAE;KACR,IAAI,EAAE;KACN,MAAM,CAAC,CAAC,EAAE,iCAAiC,CAAC;KAC5C,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC;AAErC,MAAM,OAAO,GAAG,CAAC;KACd,MAAM,EAAE;KACR,KAAK,CAAC,qBAAqB,EAAE,qBAAqB,CAAC,CAAC;AAEvD,MAAM,cAAc,GAAG,CAAC;KACrB,MAAM,EAAE;KACR,MAAM,CAAC,uBAAuB,CAAC;KAC/B,QAAQ,CAAC,yBAAyB,CAAC,CAAC;AAEvC,MAAM,MAAM,GAAG;IACb,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;QAChB,IAAI,EAAE,QAAQ;QACd,EAAE,EAAE,QAAQ;QACZ,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;KAClC,CAAC;IACF,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC;QACb,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE;KACxB,CAAC;IACF,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;KAC9B,CAAC;IACF,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,IAAI,EAAE,OAAO;QACb,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7B,EAAE,EAAE,QAAQ,CAAC,QAAQ,EAAE;QACvB,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;KAClC,CAAC;IACF,UAAU,EAAE,CAAC,CAAC,MAAM,CAAC;QACnB,SAAS,EAAE,OAAO;QAClB,OAAO,EAAE,OAAO;QAChB,IAAI,EAAE,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC;QAC7B,MAAM,EAAE,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC;QACjC,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;KACjD,CAAC;IACF,GAAG,EAAE,CAAC,CAAC,MAAM,CAAC;QACZ,OAAO,EAAE,CAAC;aACP,MAAM,EAAE;aACR,IAAI,EAAE;aACN,MAAM,CAAC,CAAC,EAAE,gCAAgC,CAAC;aAC3C,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC;aACjC,QAAQ,EAAE;KACd,CAAC;CACH,CAAC;AAEF,MAAM,CAAC,MAAM,mBAAmB,GAAG,MAAM,CAAC;AAE1C,MAAM,IAAI,GAAG,KAAK,EAAK,EAAoB,EAAc,EAAE;IACzD,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,EAAE,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,SAAS;YAAE,MAAM,GAAG,CAAC;QACxC,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;YACvC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAClF,CAAC;QACD,IAAI,GAAG,YAAY,gBAAgB,EAAE,CAAC;YACpC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,GAAG,YAAY,oBAAoB,EAAE,CAAC;YACxC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,GAAG,YAAY,mBAAmB,EAAE,CAAC;YACvC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,aAAa,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACjF,CAAC;QACD,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;YAClC,MAAM,IAAI,SAAS,CAAC,EAAE,IAAI,EAAE,mBAAmB,EAAE,OAAO,EAAE,GAAG,CAAC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;QACvF,CAAC;QACD,IAAI,GAAG,YAAY,YAAY,EAAE,CAAC;YAChC,MAAM,IAAI,SAAS,CAAC;gBAClB,IAAI,EAAE,uBAAuB;gBAC7B,OAAO,EAAE,GAAG,CAAC,OAAO;gBACpB,KAAK,EAAE,GAAG;aACX,CAAC,CAAC;QACL,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CAAC,IAAgC,EAAiB,EAAE;IACxE,IAAI,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC,MAAM,CAAC;IACpC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,IAAI,YAAY,CAAC,mDAAmD,CAAC,CAAC;IAC9E,CAAC;IACD,OAAO,IAAI,aAAa,CAAC,EAAE,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC7D,CAAC,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAgC,EAAE,EAAE;IACtE,MAAM,MAAM,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACnC,MAAM,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC;IAC5B,MAAM,IAAI,GAAG,CAAC,CAAC,SAAS,CAAC;IACzB,OAAO,CAAC,CAAC,MAAM,CAAC;QACd,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CACtD,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAC/D;QACD,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAChD,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CACjD;QACD,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAClD,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAoC,CAAC,CAC1E;QACD,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAC5D,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,iBAAiB,CAAC,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC,CACrF;QACD,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAC5D,IAAI,CAAC,GAAG,EAAE,CACR,MAAM,CAAC,aAAa,CAClB,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,OAAO,EACb,KAAK,CAAC,MAAM,EACZ,KAAK,CAAC,IAAI,EACV,KAAK,CAAC,UAAU,CACjB,CACF,CACF;QACD,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC,CAAC;QACjE,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,CAC9C,IAAI,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAC9C;KACF,CAAC,CAAC;AACL,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,68 @@
1
+ {
2
+ "name": "trpc-unirate",
3
+ "version": "0.1.0",
4
+ "description": "Pre-built tRPC router for the UniRate currency-exchange API. Drop-in createUniRateRouter() with Zod-validated procedures for convert, rates, historical, time-series, currencies, and VAT.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "UniRate (https://unirateapi.com)",
8
+ "homepage": "https://github.com/UniRate-API/trpc-unirate#readme",
9
+ "bugs": "https://github.com/UniRate-API/trpc-unirate/issues",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/UniRate-API/trpc-unirate.git"
13
+ },
14
+ "keywords": [
15
+ "trpc",
16
+ "trpc-router",
17
+ "unirate",
18
+ "currency",
19
+ "exchange-rates",
20
+ "forex",
21
+ "money",
22
+ "fx",
23
+ "zod",
24
+ "fintech"
25
+ ],
26
+ "files": [
27
+ "dist",
28
+ "README.md",
29
+ "LICENSE"
30
+ ],
31
+ "main": "./dist/index.js",
32
+ "exports": {
33
+ ".": {
34
+ "types": "./dist/index.d.ts",
35
+ "import": "./dist/index.js"
36
+ },
37
+ "./client": {
38
+ "types": "./dist/client.d.ts",
39
+ "import": "./dist/client.js"
40
+ },
41
+ "./package.json": "./package.json"
42
+ },
43
+ "scripts": {
44
+ "build": "tsc -p tsconfig.build.json",
45
+ "test": "vitest run",
46
+ "test:watch": "vitest",
47
+ "typecheck": "tsc --noEmit",
48
+ "prepublishOnly": "npm run build"
49
+ },
50
+ "peerDependencies": {
51
+ "@trpc/server": "^11.0.0",
52
+ "zod": "^3.22.0 || ^4.0.0"
53
+ },
54
+ "devDependencies": {
55
+ "@trpc/server": "^11.0.0",
56
+ "@types/node": "^20.11.0",
57
+ "typescript": "^5.4.0",
58
+ "vitest": "^2.1.0",
59
+ "zod": "^4.0.0"
60
+ },
61
+ "engines": {
62
+ "node": ">=18.17.0"
63
+ },
64
+ "publishConfig": {
65
+ "access": "public",
66
+ "provenance": true
67
+ }
68
+ }