@usethrottle/invoices 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/index.cjs
CHANGED
|
@@ -68,7 +68,7 @@ var InvoicesClient = class {
|
|
|
68
68
|
const init = { method, headers: { "content-type": "application/json", ...this.apiKey ? { "x-api-key": this.apiKey } : {} }, signal: ctrl.signal };
|
|
69
69
|
const res = this.fetcher ? await this.fetcher(path, init) : await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
70
70
|
const json = await res.json().catch(() => ({}));
|
|
71
|
-
if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? "unknown_error", message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details });
|
|
71
|
+
if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? "unknown_error", message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details, responseHeaders: res.headers });
|
|
72
72
|
return json;
|
|
73
73
|
} finally {
|
|
74
74
|
clearTimeout(timer);
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.tsx","../src/errors.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["export { InvoicesClient, createInvoicesClient } from './client';\nexport { ThrottleInvoicesError, ThrottleError, isThrottleError } from './errors';\nexport { InvoiceProvider, useInvoiceClient, useInvoiceInvalidation } from './provider';\nexport { useInvoices, useInvoice, useDownloadInvoice } from './hooks';\nexport type * from './types';\n","import { ThrottleError } from '@usethrottle/errors';\nexport class ThrottleInvoicesError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args); this.name = 'ThrottleInvoicesError';\n }\n}\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import { ThrottleInvoicesError } from './errors';\nimport type { Invoice, InvoicesClientContract, InvoicesClientOptions, ListInvoicesParams, PaginatedInvoices, ThrottleEnvelope } from './types';\n\nexport class InvoicesClient implements InvoicesClientContract {\n private readonly apiKey?: string; private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch; private readonly fetcher?: InvoicesClientOptions['fetcher']; private readonly timeoutMs: number;\n constructor(opts: InvoicesClientOptions = {}) {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) throw new Error('InvoicesClient: fetch is required');\n if (!opts.apiKey && !opts.fetcher) throw new Error('InvoicesClient: apiKey or fetcher is required');\n this.apiKey = opts.apiKey; this.baseUrl = (opts.baseUrl ?? 'https://api.usethrottle.dev').replace(/\\/+$/, '');\n this.fetchImpl = fetchImpl; this.fetcher = opts.fetcher; this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n private async requestEnvelope<T>(method: string, path: string): Promise<ThrottleEnvelope<T>> {\n const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n try {\n const init: RequestInit = { method, headers: { 'content-type': 'application/json', ...(this.apiKey ? { 'x-api-key': this.apiKey } : {}) }, signal: ctrl.signal };\n const res = this.fetcher ? await this.fetcher(path, init) : await this.fetchImpl(`${this.baseUrl}${path}`, init);\n const json = (await res.json().catch(() => ({}))) as ThrottleEnvelope<T>;\n if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? 'unknown_error', message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details });\n return json;\n } finally { clearTimeout(timer); }\n }\n async list(params: ListInvoicesParams = {}): Promise<PaginatedInvoices> {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== null && v !== '') q.set(k, String(v));\n const suffix = q.toString() ? `?${q}` : '';\n const env = await this.requestEnvelope<Invoice[]>('GET', `/api/v1/invoices${suffix}`);\n return { data: env.data ?? [], pagination: env.meta?.pagination ? { cursor: env.meta.pagination.cursor ?? null, hasMore: Boolean(env.meta.pagination.hasMore) } : undefined };\n }\n async get(id: string): Promise<Invoice> {\n const env = await this.requestEnvelope<Invoice>('GET', `/api/v1/invoices/${encodeURIComponent(id)}`);\n return env.data as Invoice;\n }\n async getDownloadUrl(id: string): Promise<string> {\n const env = await this.requestEnvelope<{ url: string }>('GET', `/api/v1/invoices/${encodeURIComponent(id)}/download?format=json`);\n return (env.data as { url: string }).url;\n }\n}\nexport function createInvoicesClient(opts: InvoicesClientOptions): InvoicesClient { return new InvoicesClient(opts); }\n","import { createContext, useCallback, useContext, useMemo, useReducer, type ReactNode } from 'react';\nimport { InvoicesClient } from './client';\nimport type {\n InvoiceFetcher,\n InvoicesProviderProps,\n InvoicesClientContract,\n} from './types';\n\ninterface InvoiceContextValue {\n client: InvoicesClientContract;\n cacheVersion: number;\n invalidate: () => void;\n}\n\nconst InvoiceContext = createContext<InvoiceContextValue | null>(null);\n\nexport function InvoiceProvider({\n children,\n client,\n fetcher,\n baseUrl,\n timeoutMs,\n}: InvoicesProviderProps) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const resolvedClient = useMemo(() => {\n if (client) return client;\n return new InvoicesClient({\n fetcher: fetcher ?? createInvoiceFetcher('/api/throttle'),\n baseUrl,\n timeoutMs,\n });\n }, [baseUrl, client, fetcher, timeoutMs]);\n\n const value = useMemo(\n () => ({ client: resolvedClient, cacheVersion, invalidate }),\n [cacheVersion, resolvedClient],\n );\n\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n\nexport function useInvoiceClient(): InvoicesClientContract {\n return useInvoiceContext().client;\n}\n\nexport function useInvoiceInvalidation(): () => void {\n return useInvoiceContext().invalidate;\n}\n\nexport function useInvoiceCacheVersion(): number {\n return useInvoiceContext().cacheVersion;\n}\n\nexport function createInvoiceFetcher(basePath: string): InvoiceFetcher {\n const cleanBase = basePath.replace(/\\/+$/, '');\n return (path, init) => {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return fetch(`${cleanBase}${cleanPath}`, init);\n };\n}\n\nexport function useInvoiceContext(): InvoiceContextValue {\n const ctx = useContext(InvoiceContext);\n if (!ctx) {\n throw new Error(\n '@usethrottle/invoices hooks must be used inside <InvoiceProvider />',\n );\n }\n return ctx;\n}\n\nexport function InvoiceProviderWithClient({\n children,\n client,\n}: {\n children: ReactNode;\n client: InvoicesClientContract;\n}) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const value = useMemo(() => ({ client, cacheVersion, invalidate }), [cacheVersion, client]);\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n useInvoiceCacheVersion,\n useInvoiceClient,\n} from './provider';\nimport type {\n Invoice,\n ListInvoicesParams,\n PaginatedInvoices,\n QueryOptions,\n QueryState,\n} from './types';\n\nexport function useInvoices(\n params: ListInvoicesParams = {},\n options: QueryOptions<PaginatedInvoices> = {},\n): QueryState<PaginatedInvoices> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n const p = useStableValue(params);\n return useAsyncQuery(() => client.list(p), [client, p, v], options);\n}\n\nexport function useInvoice(\n id: string | null | undefined,\n options: QueryOptions<Invoice> = {},\n): QueryState<Invoice> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n return useAsyncQuery(\n () => (id ? client.get(id) : Promise.resolve(null)),\n [client, id, v],\n { ...options, enabled: options.enabled ?? Boolean(id) },\n );\n}\n\nexport function useDownloadInvoice() {\n const client = useInvoiceClient();\n return async (id: string) => {\n const url = await client.getDownloadUrl(id);\n if (typeof window !== 'undefined') window.open(url, '_blank');\n return url;\n };\n}\n\nfunction useAsyncQuery<T>(\n load: () => Promise<T | null>,\n deps: readonly unknown[],\n options: QueryOptions<T>,\n): QueryState<T> {\n const enabled = options.enabled ?? true;\n const [data, setData] = useState<T | null>(options.initialData ?? null);\n const [error, setError] = useState<unknown>(null);\n const [isLoading, setIsLoading] = useState(enabled && options.initialData === undefined);\n const [isFetching, setIsFetching] = useState(false);\n const loadRef = useRef(load);\n loadRef.current = load;\n\n const refetch = useCallback(async () => {\n if (!enabled) return data;\n setIsFetching(true);\n setError(null);\n try {\n const next = await loadRef.current();\n setData(next);\n return next;\n } catch (err) {\n setError(err);\n throw err;\n } finally {\n setIsFetching(false);\n setIsLoading(false);\n }\n }, [data, enabled]);\n\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let cancelled = false;\n setIsFetching(true);\n setError(null);\n load()\n .then((next) => {\n if (!cancelled) setData(next);\n })\n .catch((err) => {\n if (!cancelled) setError(err);\n })\n .finally(() => {\n if (!cancelled) {\n setIsLoading(false);\n setIsFetching(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, ...deps]);\n\n return { data, error, isLoading, isFetching, refetch };\n}\n\nfunction useStableValue<T>(value: T): T {\n const key = JSON.stringify(value);\n return useMemo(() => value, [key]);\n}\n"],"mappings":"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","names":["import_errors","value","import_react"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.tsx","../src/errors.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["export { InvoicesClient, createInvoicesClient } from './client';\nexport { ThrottleInvoicesError, ThrottleError, isThrottleError } from './errors';\nexport { InvoiceProvider, useInvoiceClient, useInvoiceInvalidation } from './provider';\nexport { useInvoices, useInvoice, useDownloadInvoice } from './hooks';\nexport type * from './types';\n","import { ThrottleError, type ThrottleErrorArgs } from '@usethrottle/errors';\nexport class ThrottleInvoicesError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown; responseHeaders?: ThrottleErrorArgs['responseHeaders'] }) {\n super(args); this.name = 'ThrottleInvoicesError';\n }\n}\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import { ThrottleInvoicesError } from './errors';\nimport type { Invoice, InvoicesClientContract, InvoicesClientOptions, ListInvoicesParams, PaginatedInvoices, ThrottleEnvelope } from './types';\n\nexport class InvoicesClient implements InvoicesClientContract {\n private readonly apiKey?: string; private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch; private readonly fetcher?: InvoicesClientOptions['fetcher']; private readonly timeoutMs: number;\n constructor(opts: InvoicesClientOptions = {}) {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) throw new Error('InvoicesClient: fetch is required');\n if (!opts.apiKey && !opts.fetcher) throw new Error('InvoicesClient: apiKey or fetcher is required');\n this.apiKey = opts.apiKey; this.baseUrl = (opts.baseUrl ?? 'https://api.usethrottle.dev').replace(/\\/+$/, '');\n this.fetchImpl = fetchImpl; this.fetcher = opts.fetcher; this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n private async requestEnvelope<T>(method: string, path: string): Promise<ThrottleEnvelope<T>> {\n const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n try {\n const init: RequestInit = { method, headers: { 'content-type': 'application/json', ...(this.apiKey ? { 'x-api-key': this.apiKey } : {}) }, signal: ctrl.signal };\n const res = this.fetcher ? await this.fetcher(path, init) : await this.fetchImpl(`${this.baseUrl}${path}`, init);\n const json = (await res.json().catch(() => ({}))) as ThrottleEnvelope<T>;\n if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? 'unknown_error', message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details, responseHeaders: res.headers });\n return json;\n } finally { clearTimeout(timer); }\n }\n async list(params: ListInvoicesParams = {}): Promise<PaginatedInvoices> {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== null && v !== '') q.set(k, String(v));\n const suffix = q.toString() ? `?${q}` : '';\n const env = await this.requestEnvelope<Invoice[]>('GET', `/api/v1/invoices${suffix}`);\n return { data: env.data ?? [], pagination: env.meta?.pagination ? { cursor: env.meta.pagination.cursor ?? null, hasMore: Boolean(env.meta.pagination.hasMore) } : undefined };\n }\n async get(id: string): Promise<Invoice> {\n const env = await this.requestEnvelope<Invoice>('GET', `/api/v1/invoices/${encodeURIComponent(id)}`);\n return env.data as Invoice;\n }\n async getDownloadUrl(id: string): Promise<string> {\n const env = await this.requestEnvelope<{ url: string }>('GET', `/api/v1/invoices/${encodeURIComponent(id)}/download?format=json`);\n return (env.data as { url: string }).url;\n }\n}\nexport function createInvoicesClient(opts: InvoicesClientOptions): InvoicesClient { return new InvoicesClient(opts); }\n","import { createContext, useCallback, useContext, useMemo, useReducer, type ReactNode } from 'react';\nimport { InvoicesClient } from './client';\nimport type {\n InvoiceFetcher,\n InvoicesProviderProps,\n InvoicesClientContract,\n} from './types';\n\ninterface InvoiceContextValue {\n client: InvoicesClientContract;\n cacheVersion: number;\n invalidate: () => void;\n}\n\nconst InvoiceContext = createContext<InvoiceContextValue | null>(null);\n\nexport function InvoiceProvider({\n children,\n client,\n fetcher,\n baseUrl,\n timeoutMs,\n}: InvoicesProviderProps) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const resolvedClient = useMemo(() => {\n if (client) return client;\n return new InvoicesClient({\n fetcher: fetcher ?? createInvoiceFetcher('/api/throttle'),\n baseUrl,\n timeoutMs,\n });\n }, [baseUrl, client, fetcher, timeoutMs]);\n\n const value = useMemo(\n () => ({ client: resolvedClient, cacheVersion, invalidate }),\n [cacheVersion, resolvedClient],\n );\n\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n\nexport function useInvoiceClient(): InvoicesClientContract {\n return useInvoiceContext().client;\n}\n\nexport function useInvoiceInvalidation(): () => void {\n return useInvoiceContext().invalidate;\n}\n\nexport function useInvoiceCacheVersion(): number {\n return useInvoiceContext().cacheVersion;\n}\n\nexport function createInvoiceFetcher(basePath: string): InvoiceFetcher {\n const cleanBase = basePath.replace(/\\/+$/, '');\n return (path, init) => {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return fetch(`${cleanBase}${cleanPath}`, init);\n };\n}\n\nexport function useInvoiceContext(): InvoiceContextValue {\n const ctx = useContext(InvoiceContext);\n if (!ctx) {\n throw new Error(\n '@usethrottle/invoices hooks must be used inside <InvoiceProvider />',\n );\n }\n return ctx;\n}\n\nexport function InvoiceProviderWithClient({\n children,\n client,\n}: {\n children: ReactNode;\n client: InvoicesClientContract;\n}) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const value = useMemo(() => ({ client, cacheVersion, invalidate }), [cacheVersion, client]);\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n useInvoiceCacheVersion,\n useInvoiceClient,\n} from './provider';\nimport type {\n Invoice,\n ListInvoicesParams,\n PaginatedInvoices,\n QueryOptions,\n QueryState,\n} from './types';\n\nexport function useInvoices(\n params: ListInvoicesParams = {},\n options: QueryOptions<PaginatedInvoices> = {},\n): QueryState<PaginatedInvoices> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n const p = useStableValue(params);\n return useAsyncQuery(() => client.list(p), [client, p, v], options);\n}\n\nexport function useInvoice(\n id: string | null | undefined,\n options: QueryOptions<Invoice> = {},\n): QueryState<Invoice> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n return useAsyncQuery(\n () => (id ? client.get(id) : Promise.resolve(null)),\n [client, id, v],\n { ...options, enabled: options.enabled ?? Boolean(id) },\n );\n}\n\nexport function useDownloadInvoice() {\n const client = useInvoiceClient();\n return async (id: string) => {\n const url = await client.getDownloadUrl(id);\n if (typeof window !== 'undefined') window.open(url, '_blank');\n return url;\n };\n}\n\nfunction useAsyncQuery<T>(\n load: () => Promise<T | null>,\n deps: readonly unknown[],\n options: QueryOptions<T>,\n): QueryState<T> {\n const enabled = options.enabled ?? true;\n const [data, setData] = useState<T | null>(options.initialData ?? null);\n const [error, setError] = useState<unknown>(null);\n const [isLoading, setIsLoading] = useState(enabled && options.initialData === undefined);\n const [isFetching, setIsFetching] = useState(false);\n const loadRef = useRef(load);\n loadRef.current = load;\n\n const refetch = useCallback(async () => {\n if (!enabled) return data;\n setIsFetching(true);\n setError(null);\n try {\n const next = await loadRef.current();\n setData(next);\n return next;\n } catch (err) {\n setError(err);\n throw err;\n } finally {\n setIsFetching(false);\n setIsLoading(false);\n }\n }, [data, enabled]);\n\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let cancelled = false;\n setIsFetching(true);\n setError(null);\n load()\n .then((next) => {\n if (!cancelled) setData(next);\n })\n .catch((err) => {\n if (!cancelled) setError(err);\n })\n .finally(() => {\n if (!cancelled) {\n setIsLoading(false);\n setIsFetching(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, ...deps]);\n\n return { data, error, isLoading, isFetching, refetch };\n}\n\nfunction useStableValue<T>(value: T): T {\n const key = JSON.stringify(value);\n return useMemo(() => value, [key]);\n}\n"],"mappings":"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","names":["import_errors","value","import_react"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { ThrottleError } from '@usethrottle/errors';
|
|
2
|
+
import { ThrottleError, ThrottleErrorArgs } from '@usethrottle/errors';
|
|
3
3
|
export { ThrottleError, isThrottleError } from '@usethrottle/errors';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -104,6 +104,7 @@ declare class ThrottleInvoicesError extends ThrottleError {
|
|
|
104
104
|
message: string;
|
|
105
105
|
statusCode: number;
|
|
106
106
|
details?: unknown;
|
|
107
|
+
responseHeaders?: ThrottleErrorArgs['responseHeaders'];
|
|
107
108
|
});
|
|
108
109
|
}
|
|
109
110
|
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
|
-
import { ThrottleError } from '@usethrottle/errors';
|
|
2
|
+
import { ThrottleError, ThrottleErrorArgs } from '@usethrottle/errors';
|
|
3
3
|
export { ThrottleError, isThrottleError } from '@usethrottle/errors';
|
|
4
4
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -104,6 +104,7 @@ declare class ThrottleInvoicesError extends ThrottleError {
|
|
|
104
104
|
message: string;
|
|
105
105
|
statusCode: number;
|
|
106
106
|
details?: unknown;
|
|
107
|
+
responseHeaders?: ThrottleErrorArgs['responseHeaders'];
|
|
107
108
|
});
|
|
108
109
|
}
|
|
109
110
|
|
package/dist/index.js
CHANGED
|
@@ -32,7 +32,7 @@ var InvoicesClient = class {
|
|
|
32
32
|
const init = { method, headers: { "content-type": "application/json", ...this.apiKey ? { "x-api-key": this.apiKey } : {} }, signal: ctrl.signal };
|
|
33
33
|
const res = this.fetcher ? await this.fetcher(path, init) : await this.fetchImpl(`${this.baseUrl}${path}`, init);
|
|
34
34
|
const json = await res.json().catch(() => ({}));
|
|
35
|
-
if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? "unknown_error", message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details });
|
|
35
|
+
if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? "unknown_error", message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details, responseHeaders: res.headers });
|
|
36
36
|
return json;
|
|
37
37
|
} finally {
|
|
38
38
|
clearTimeout(timer);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import { ThrottleError } from '@usethrottle/errors';\nexport class ThrottleInvoicesError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown }) {\n super(args); this.name = 'ThrottleInvoicesError';\n }\n}\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import { ThrottleInvoicesError } from './errors';\nimport type { Invoice, InvoicesClientContract, InvoicesClientOptions, ListInvoicesParams, PaginatedInvoices, ThrottleEnvelope } from './types';\n\nexport class InvoicesClient implements InvoicesClientContract {\n private readonly apiKey?: string; private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch; private readonly fetcher?: InvoicesClientOptions['fetcher']; private readonly timeoutMs: number;\n constructor(opts: InvoicesClientOptions = {}) {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) throw new Error('InvoicesClient: fetch is required');\n if (!opts.apiKey && !opts.fetcher) throw new Error('InvoicesClient: apiKey or fetcher is required');\n this.apiKey = opts.apiKey; this.baseUrl = (opts.baseUrl ?? 'https://api.usethrottle.dev').replace(/\\/+$/, '');\n this.fetchImpl = fetchImpl; this.fetcher = opts.fetcher; this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n private async requestEnvelope<T>(method: string, path: string): Promise<ThrottleEnvelope<T>> {\n const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n try {\n const init: RequestInit = { method, headers: { 'content-type': 'application/json', ...(this.apiKey ? { 'x-api-key': this.apiKey } : {}) }, signal: ctrl.signal };\n const res = this.fetcher ? await this.fetcher(path, init) : await this.fetchImpl(`${this.baseUrl}${path}`, init);\n const json = (await res.json().catch(() => ({}))) as ThrottleEnvelope<T>;\n if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? 'unknown_error', message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details });\n return json;\n } finally { clearTimeout(timer); }\n }\n async list(params: ListInvoicesParams = {}): Promise<PaginatedInvoices> {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== null && v !== '') q.set(k, String(v));\n const suffix = q.toString() ? `?${q}` : '';\n const env = await this.requestEnvelope<Invoice[]>('GET', `/api/v1/invoices${suffix}`);\n return { data: env.data ?? [], pagination: env.meta?.pagination ? { cursor: env.meta.pagination.cursor ?? null, hasMore: Boolean(env.meta.pagination.hasMore) } : undefined };\n }\n async get(id: string): Promise<Invoice> {\n const env = await this.requestEnvelope<Invoice>('GET', `/api/v1/invoices/${encodeURIComponent(id)}`);\n return env.data as Invoice;\n }\n async getDownloadUrl(id: string): Promise<string> {\n const env = await this.requestEnvelope<{ url: string }>('GET', `/api/v1/invoices/${encodeURIComponent(id)}/download?format=json`);\n return (env.data as { url: string }).url;\n }\n}\nexport function createInvoicesClient(opts: InvoicesClientOptions): InvoicesClient { return new InvoicesClient(opts); }\n","import { createContext, useCallback, useContext, useMemo, useReducer, type ReactNode } from 'react';\nimport { InvoicesClient } from './client';\nimport type {\n InvoiceFetcher,\n InvoicesProviderProps,\n InvoicesClientContract,\n} from './types';\n\ninterface InvoiceContextValue {\n client: InvoicesClientContract;\n cacheVersion: number;\n invalidate: () => void;\n}\n\nconst InvoiceContext = createContext<InvoiceContextValue | null>(null);\n\nexport function InvoiceProvider({\n children,\n client,\n fetcher,\n baseUrl,\n timeoutMs,\n}: InvoicesProviderProps) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const resolvedClient = useMemo(() => {\n if (client) return client;\n return new InvoicesClient({\n fetcher: fetcher ?? createInvoiceFetcher('/api/throttle'),\n baseUrl,\n timeoutMs,\n });\n }, [baseUrl, client, fetcher, timeoutMs]);\n\n const value = useMemo(\n () => ({ client: resolvedClient, cacheVersion, invalidate }),\n [cacheVersion, resolvedClient],\n );\n\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n\nexport function useInvoiceClient(): InvoicesClientContract {\n return useInvoiceContext().client;\n}\n\nexport function useInvoiceInvalidation(): () => void {\n return useInvoiceContext().invalidate;\n}\n\nexport function useInvoiceCacheVersion(): number {\n return useInvoiceContext().cacheVersion;\n}\n\nexport function createInvoiceFetcher(basePath: string): InvoiceFetcher {\n const cleanBase = basePath.replace(/\\/+$/, '');\n return (path, init) => {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return fetch(`${cleanBase}${cleanPath}`, init);\n };\n}\n\nexport function useInvoiceContext(): InvoiceContextValue {\n const ctx = useContext(InvoiceContext);\n if (!ctx) {\n throw new Error(\n '@usethrottle/invoices hooks must be used inside <InvoiceProvider />',\n );\n }\n return ctx;\n}\n\nexport function InvoiceProviderWithClient({\n children,\n client,\n}: {\n children: ReactNode;\n client: InvoicesClientContract;\n}) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const value = useMemo(() => ({ client, cacheVersion, invalidate }), [cacheVersion, client]);\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n useInvoiceCacheVersion,\n useInvoiceClient,\n} from './provider';\nimport type {\n Invoice,\n ListInvoicesParams,\n PaginatedInvoices,\n QueryOptions,\n QueryState,\n} from './types';\n\nexport function useInvoices(\n params: ListInvoicesParams = {},\n options: QueryOptions<PaginatedInvoices> = {},\n): QueryState<PaginatedInvoices> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n const p = useStableValue(params);\n return useAsyncQuery(() => client.list(p), [client, p, v], options);\n}\n\nexport function useInvoice(\n id: string | null | undefined,\n options: QueryOptions<Invoice> = {},\n): QueryState<Invoice> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n return useAsyncQuery(\n () => (id ? client.get(id) : Promise.resolve(null)),\n [client, id, v],\n { ...options, enabled: options.enabled ?? Boolean(id) },\n );\n}\n\nexport function useDownloadInvoice() {\n const client = useInvoiceClient();\n return async (id: string) => {\n const url = await client.getDownloadUrl(id);\n if (typeof window !== 'undefined') window.open(url, '_blank');\n return url;\n };\n}\n\nfunction useAsyncQuery<T>(\n load: () => Promise<T | null>,\n deps: readonly unknown[],\n options: QueryOptions<T>,\n): QueryState<T> {\n const enabled = options.enabled ?? true;\n const [data, setData] = useState<T | null>(options.initialData ?? null);\n const [error, setError] = useState<unknown>(null);\n const [isLoading, setIsLoading] = useState(enabled && options.initialData === undefined);\n const [isFetching, setIsFetching] = useState(false);\n const loadRef = useRef(load);\n loadRef.current = load;\n\n const refetch = useCallback(async () => {\n if (!enabled) return data;\n setIsFetching(true);\n setError(null);\n try {\n const next = await loadRef.current();\n setData(next);\n return next;\n } catch (err) {\n setError(err);\n throw err;\n } finally {\n setIsFetching(false);\n setIsLoading(false);\n }\n }, [data, enabled]);\n\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let cancelled = false;\n setIsFetching(true);\n setError(null);\n load()\n .then((next) => {\n if (!cancelled) setData(next);\n })\n .catch((err) => {\n if (!cancelled) setError(err);\n })\n .finally(() => {\n if (!cancelled) {\n setIsLoading(false);\n setIsFetching(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, ...deps]);\n\n return { data, error, isLoading, isFetching, refetch };\n}\n\nfunction useStableValue<T>(value: T): T {\n const key = JSON.stringify(value);\n return useMemo(() => value, [key]);\n}\n"],"mappings":"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","names":["ThrottleError","value","useCallback","useMemo","useCallback","useMemo"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/provider.tsx","../src/hooks.ts"],"sourcesContent":["import { ThrottleError, type ThrottleErrorArgs } from '@usethrottle/errors';\nexport class ThrottleInvoicesError extends ThrottleError {\n constructor(args: { code: string; message: string; statusCode: number; details?: unknown; responseHeaders?: ThrottleErrorArgs['responseHeaders'] }) {\n super(args); this.name = 'ThrottleInvoicesError';\n }\n}\nexport { ThrottleError, isThrottleError } from '@usethrottle/errors';\n","import { ThrottleInvoicesError } from './errors';\nimport type { Invoice, InvoicesClientContract, InvoicesClientOptions, ListInvoicesParams, PaginatedInvoices, ThrottleEnvelope } from './types';\n\nexport class InvoicesClient implements InvoicesClientContract {\n private readonly apiKey?: string; private readonly baseUrl: string;\n private readonly fetchImpl: typeof globalThis.fetch; private readonly fetcher?: InvoicesClientOptions['fetcher']; private readonly timeoutMs: number;\n constructor(opts: InvoicesClientOptions = {}) {\n const fetchImpl = opts.fetch ?? globalThis.fetch;\n if (!fetchImpl) throw new Error('InvoicesClient: fetch is required');\n if (!opts.apiKey && !opts.fetcher) throw new Error('InvoicesClient: apiKey or fetcher is required');\n this.apiKey = opts.apiKey; this.baseUrl = (opts.baseUrl ?? 'https://api.usethrottle.dev').replace(/\\/+$/, '');\n this.fetchImpl = fetchImpl; this.fetcher = opts.fetcher; this.timeoutMs = opts.timeoutMs ?? 30_000;\n }\n private async requestEnvelope<T>(method: string, path: string): Promise<ThrottleEnvelope<T>> {\n const ctrl = new AbortController(); const timer = setTimeout(() => ctrl.abort(), this.timeoutMs);\n try {\n const init: RequestInit = { method, headers: { 'content-type': 'application/json', ...(this.apiKey ? { 'x-api-key': this.apiKey } : {}) }, signal: ctrl.signal };\n const res = this.fetcher ? await this.fetcher(path, init) : await this.fetchImpl(`${this.baseUrl}${path}`, init);\n const json = (await res.json().catch(() => ({}))) as ThrottleEnvelope<T>;\n if (!res.ok) throw new ThrottleInvoicesError({ code: json.error?.code ?? 'unknown_error', message: json.error?.message ?? `HTTP ${res.status}`, statusCode: res.status, details: json.error?.details, responseHeaders: res.headers });\n return json;\n } finally { clearTimeout(timer); }\n }\n async list(params: ListInvoicesParams = {}): Promise<PaginatedInvoices> {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) if (v !== undefined && v !== null && v !== '') q.set(k, String(v));\n const suffix = q.toString() ? `?${q}` : '';\n const env = await this.requestEnvelope<Invoice[]>('GET', `/api/v1/invoices${suffix}`);\n return { data: env.data ?? [], pagination: env.meta?.pagination ? { cursor: env.meta.pagination.cursor ?? null, hasMore: Boolean(env.meta.pagination.hasMore) } : undefined };\n }\n async get(id: string): Promise<Invoice> {\n const env = await this.requestEnvelope<Invoice>('GET', `/api/v1/invoices/${encodeURIComponent(id)}`);\n return env.data as Invoice;\n }\n async getDownloadUrl(id: string): Promise<string> {\n const env = await this.requestEnvelope<{ url: string }>('GET', `/api/v1/invoices/${encodeURIComponent(id)}/download?format=json`);\n return (env.data as { url: string }).url;\n }\n}\nexport function createInvoicesClient(opts: InvoicesClientOptions): InvoicesClient { return new InvoicesClient(opts); }\n","import { createContext, useCallback, useContext, useMemo, useReducer, type ReactNode } from 'react';\nimport { InvoicesClient } from './client';\nimport type {\n InvoiceFetcher,\n InvoicesProviderProps,\n InvoicesClientContract,\n} from './types';\n\ninterface InvoiceContextValue {\n client: InvoicesClientContract;\n cacheVersion: number;\n invalidate: () => void;\n}\n\nconst InvoiceContext = createContext<InvoiceContextValue | null>(null);\n\nexport function InvoiceProvider({\n children,\n client,\n fetcher,\n baseUrl,\n timeoutMs,\n}: InvoicesProviderProps) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const resolvedClient = useMemo(() => {\n if (client) return client;\n return new InvoicesClient({\n fetcher: fetcher ?? createInvoiceFetcher('/api/throttle'),\n baseUrl,\n timeoutMs,\n });\n }, [baseUrl, client, fetcher, timeoutMs]);\n\n const value = useMemo(\n () => ({ client: resolvedClient, cacheVersion, invalidate }),\n [cacheVersion, resolvedClient],\n );\n\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n\nexport function useInvoiceClient(): InvoicesClientContract {\n return useInvoiceContext().client;\n}\n\nexport function useInvoiceInvalidation(): () => void {\n return useInvoiceContext().invalidate;\n}\n\nexport function useInvoiceCacheVersion(): number {\n return useInvoiceContext().cacheVersion;\n}\n\nexport function createInvoiceFetcher(basePath: string): InvoiceFetcher {\n const cleanBase = basePath.replace(/\\/+$/, '');\n return (path, init) => {\n const cleanPath = path.startsWith('/') ? path : `/${path}`;\n return fetch(`${cleanBase}${cleanPath}`, init);\n };\n}\n\nexport function useInvoiceContext(): InvoiceContextValue {\n const ctx = useContext(InvoiceContext);\n if (!ctx) {\n throw new Error(\n '@usethrottle/invoices hooks must be used inside <InvoiceProvider />',\n );\n }\n return ctx;\n}\n\nexport function InvoiceProviderWithClient({\n children,\n client,\n}: {\n children: ReactNode;\n client: InvoicesClientContract;\n}) {\n const [cacheVersion, invalidate] = useReducer((value: number) => value + 1, 0);\n const value = useMemo(() => ({ client, cacheVersion, invalidate }), [cacheVersion, client]);\n return <InvoiceContext.Provider value={value}>{children}</InvoiceContext.Provider>;\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport {\n useInvoiceCacheVersion,\n useInvoiceClient,\n} from './provider';\nimport type {\n Invoice,\n ListInvoicesParams,\n PaginatedInvoices,\n QueryOptions,\n QueryState,\n} from './types';\n\nexport function useInvoices(\n params: ListInvoicesParams = {},\n options: QueryOptions<PaginatedInvoices> = {},\n): QueryState<PaginatedInvoices> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n const p = useStableValue(params);\n return useAsyncQuery(() => client.list(p), [client, p, v], options);\n}\n\nexport function useInvoice(\n id: string | null | undefined,\n options: QueryOptions<Invoice> = {},\n): QueryState<Invoice> {\n const client = useInvoiceClient();\n const v = useInvoiceCacheVersion();\n return useAsyncQuery(\n () => (id ? client.get(id) : Promise.resolve(null)),\n [client, id, v],\n { ...options, enabled: options.enabled ?? Boolean(id) },\n );\n}\n\nexport function useDownloadInvoice() {\n const client = useInvoiceClient();\n return async (id: string) => {\n const url = await client.getDownloadUrl(id);\n if (typeof window !== 'undefined') window.open(url, '_blank');\n return url;\n };\n}\n\nfunction useAsyncQuery<T>(\n load: () => Promise<T | null>,\n deps: readonly unknown[],\n options: QueryOptions<T>,\n): QueryState<T> {\n const enabled = options.enabled ?? true;\n const [data, setData] = useState<T | null>(options.initialData ?? null);\n const [error, setError] = useState<unknown>(null);\n const [isLoading, setIsLoading] = useState(enabled && options.initialData === undefined);\n const [isFetching, setIsFetching] = useState(false);\n const loadRef = useRef(load);\n loadRef.current = load;\n\n const refetch = useCallback(async () => {\n if (!enabled) return data;\n setIsFetching(true);\n setError(null);\n try {\n const next = await loadRef.current();\n setData(next);\n return next;\n } catch (err) {\n setError(err);\n throw err;\n } finally {\n setIsFetching(false);\n setIsLoading(false);\n }\n }, [data, enabled]);\n\n useEffect(() => {\n if (!enabled) {\n setIsLoading(false);\n return;\n }\n let cancelled = false;\n setIsFetching(true);\n setError(null);\n load()\n .then((next) => {\n if (!cancelled) setData(next);\n })\n .catch((err) => {\n if (!cancelled) setError(err);\n })\n .finally(() => {\n if (!cancelled) {\n setIsLoading(false);\n setIsFetching(false);\n }\n });\n\n return () => {\n cancelled = true;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [enabled, ...deps]);\n\n return { data, error, isLoading, isFetching, refetch };\n}\n\nfunction useStableValue<T>(value: T): T {\n const key = JSON.stringify(value);\n return useMemo(() => value, [key]);\n}\n"],"mappings":"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","names":["ThrottleError","value","useCallback","useMemo","useCallback","useMemo"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@usethrottle/invoices",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "React hooks + server proxy for Throttle customer invoices.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
"README.md"
|
|
24
24
|
],
|
|
25
25
|
"dependencies": {
|
|
26
|
-
"@usethrottle/errors": "^1.
|
|
26
|
+
"@usethrottle/errors": "^1.1.0"
|
|
27
27
|
},
|
|
28
28
|
"peerDependencies": {
|
|
29
29
|
"react": ">=18"
|