billsdk 0.0.1 → 0.1.1
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/adapters/drizzle/index.d.ts +1 -0
- package/dist/adapters/drizzle/index.js +3 -0
- package/dist/adapters/drizzle/index.js.map +1 -0
- package/dist/adapters/memory-adapter/index.d.ts +3 -0
- package/dist/adapters/memory-adapter/index.js +3 -0
- package/dist/adapters/memory-adapter/index.js.map +1 -0
- package/dist/adapters/payment/index.d.ts +1 -0
- package/dist/adapters/payment/index.js +3 -0
- package/dist/adapters/payment/index.js.map +1 -0
- package/dist/client/index.d.ts +133 -0
- package/dist/client/index.js +257 -0
- package/dist/client/index.js.map +1 -0
- package/dist/client/react/index.d.ts +120 -0
- package/dist/client/react/index.js +248 -0
- package/dist/client/react/index.js.map +1 -0
- package/dist/index.d.ts +25 -5
- package/dist/index.js +1293 -29
- package/dist/index.js.map +1 -1
- package/dist/integrations/next.d.ts +31 -0
- package/dist/integrations/next.js +15 -0
- package/dist/integrations/next.js.map +1 -0
- package/dist/types-Ofy1HBSd.d.ts +113 -0
- package/package.json +90 -23
- package/README.md +0 -22
- package/dist/index.d.mts +0 -8
- package/dist/index.mjs +0 -10
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { useRef, useCallback, useSyncExternalStore } from 'react';
|
|
2
|
+
|
|
3
|
+
// src/client/atoms.ts
|
|
4
|
+
function atom(initialValue) {
|
|
5
|
+
let value = initialValue;
|
|
6
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
7
|
+
return {
|
|
8
|
+
get() {
|
|
9
|
+
return value;
|
|
10
|
+
},
|
|
11
|
+
set(newValue) {
|
|
12
|
+
value = newValue;
|
|
13
|
+
for (const listener of listeners) {
|
|
14
|
+
listener(value);
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
subscribe(callback) {
|
|
18
|
+
listeners.add(callback);
|
|
19
|
+
callback(value);
|
|
20
|
+
return () => {
|
|
21
|
+
listeners.delete(callback);
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
function asyncAtom(fetcher, options = {}) {
|
|
27
|
+
const valueAtom = atom(null);
|
|
28
|
+
const loadingAtom = atom(false);
|
|
29
|
+
const errorAtom = atom(null);
|
|
30
|
+
const refresh = async () => {
|
|
31
|
+
loadingAtom.set(true);
|
|
32
|
+
errorAtom.set(null);
|
|
33
|
+
try {
|
|
34
|
+
const data = await fetcher();
|
|
35
|
+
valueAtom.set(data);
|
|
36
|
+
} catch (err) {
|
|
37
|
+
errorAtom.set(err instanceof Error ? err : new Error(String(err)));
|
|
38
|
+
} finally {
|
|
39
|
+
loadingAtom.set(false);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
if (options.autoFetch !== false) {
|
|
43
|
+
refresh();
|
|
44
|
+
}
|
|
45
|
+
return {
|
|
46
|
+
get() {
|
|
47
|
+
return valueAtom.get();
|
|
48
|
+
},
|
|
49
|
+
isLoading() {
|
|
50
|
+
return loadingAtom.get();
|
|
51
|
+
},
|
|
52
|
+
error() {
|
|
53
|
+
return errorAtom.get();
|
|
54
|
+
},
|
|
55
|
+
refresh,
|
|
56
|
+
subscribe(callback) {
|
|
57
|
+
return valueAtom.subscribe(callback);
|
|
58
|
+
}
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// src/client/proxy.ts
|
|
63
|
+
function createFetch(config = {}) {
|
|
64
|
+
const baseFetch = config.fetch ?? fetch;
|
|
65
|
+
const baseURL = config.baseURL ?? "/api/billing";
|
|
66
|
+
return async (path, options = {}) => {
|
|
67
|
+
const method = options.method ?? "GET";
|
|
68
|
+
let url = `${baseURL}${path}`;
|
|
69
|
+
if (options.query) {
|
|
70
|
+
const params = new URLSearchParams();
|
|
71
|
+
for (const [key, value] of Object.entries(options.query)) {
|
|
72
|
+
if (value !== void 0) {
|
|
73
|
+
params.set(key, value);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
const queryString = params.toString();
|
|
77
|
+
if (queryString) {
|
|
78
|
+
url += `?${queryString}`;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
const headers = {
|
|
82
|
+
"Content-Type": "application/json",
|
|
83
|
+
...config.headers,
|
|
84
|
+
...options.headers
|
|
85
|
+
};
|
|
86
|
+
const fetchOptions = {
|
|
87
|
+
method,
|
|
88
|
+
headers,
|
|
89
|
+
credentials: config.credentials ?? "include"
|
|
90
|
+
};
|
|
91
|
+
if (options.body && ["POST", "PUT", "PATCH"].includes(method)) {
|
|
92
|
+
fetchOptions.body = JSON.stringify(options.body);
|
|
93
|
+
}
|
|
94
|
+
const response = await baseFetch(url, fetchOptions);
|
|
95
|
+
if (!response.ok) {
|
|
96
|
+
const errorData = await response.json().catch(() => ({ error: { message: "Unknown error" } }));
|
|
97
|
+
throw new Error(
|
|
98
|
+
errorData?.error?.message ?? `Request failed: ${response.status}`
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return response.json();
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function useStore(atom2) {
|
|
105
|
+
const snapshotRef = useRef(atom2.get());
|
|
106
|
+
const subscribe = useCallback(
|
|
107
|
+
(onChange) => {
|
|
108
|
+
const emitChange = (value) => {
|
|
109
|
+
if (snapshotRef.current === value) return;
|
|
110
|
+
snapshotRef.current = value;
|
|
111
|
+
onChange();
|
|
112
|
+
};
|
|
113
|
+
return atom2.subscribe(emitChange);
|
|
114
|
+
},
|
|
115
|
+
[atom2]
|
|
116
|
+
);
|
|
117
|
+
const get = () => snapshotRef.current;
|
|
118
|
+
return useSyncExternalStore(subscribe, get, get);
|
|
119
|
+
}
|
|
120
|
+
function useAsyncStore(atom2) {
|
|
121
|
+
const snapshotRef = useRef(atom2.get());
|
|
122
|
+
const subscribe = useCallback(
|
|
123
|
+
(onChange) => {
|
|
124
|
+
const emitChange = (value) => {
|
|
125
|
+
if (snapshotRef.current === value) return;
|
|
126
|
+
snapshotRef.current = value;
|
|
127
|
+
onChange();
|
|
128
|
+
};
|
|
129
|
+
return atom2.subscribe(emitChange);
|
|
130
|
+
},
|
|
131
|
+
[atom2]
|
|
132
|
+
);
|
|
133
|
+
const get = () => snapshotRef.current;
|
|
134
|
+
const data = useSyncExternalStore(subscribe, get, get);
|
|
135
|
+
return {
|
|
136
|
+
data,
|
|
137
|
+
isLoading: atom2.isLoading(),
|
|
138
|
+
error: atom2.error(),
|
|
139
|
+
refresh: atom2.refresh
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// src/client/react/index.ts
|
|
144
|
+
function createBillingClient(config = {}) {
|
|
145
|
+
const $fetch = createFetch(config);
|
|
146
|
+
const customerIdAtom = atom(null);
|
|
147
|
+
const $customer = asyncAtom(
|
|
148
|
+
async () => {
|
|
149
|
+
const customerId = customerIdAtom.get();
|
|
150
|
+
if (!customerId) return null;
|
|
151
|
+
const response = await $fetch(
|
|
152
|
+
"/customer",
|
|
153
|
+
{
|
|
154
|
+
method: "GET",
|
|
155
|
+
query: { externalId: customerId }
|
|
156
|
+
}
|
|
157
|
+
);
|
|
158
|
+
return response.customer;
|
|
159
|
+
},
|
|
160
|
+
{ autoFetch: false }
|
|
161
|
+
);
|
|
162
|
+
const $subscription = asyncAtom(
|
|
163
|
+
async () => {
|
|
164
|
+
const customerId = customerIdAtom.get();
|
|
165
|
+
if (!customerId) return null;
|
|
166
|
+
const response = await $fetch("/subscription", {
|
|
167
|
+
method: "GET",
|
|
168
|
+
query: { customerId }
|
|
169
|
+
});
|
|
170
|
+
return response;
|
|
171
|
+
},
|
|
172
|
+
{ autoFetch: false }
|
|
173
|
+
);
|
|
174
|
+
const $plans = asyncAtom(
|
|
175
|
+
async () => {
|
|
176
|
+
const response = await $fetch("/plans", {
|
|
177
|
+
method: "GET"
|
|
178
|
+
});
|
|
179
|
+
return response.plans;
|
|
180
|
+
},
|
|
181
|
+
{ autoFetch: true }
|
|
182
|
+
);
|
|
183
|
+
return {
|
|
184
|
+
// React hooks
|
|
185
|
+
useCustomer: () => useAsyncStore($customer),
|
|
186
|
+
useSubscription: () => useAsyncStore($subscription),
|
|
187
|
+
usePlans: () => useAsyncStore($plans),
|
|
188
|
+
// Raw atoms
|
|
189
|
+
$customer,
|
|
190
|
+
$subscription,
|
|
191
|
+
$plans,
|
|
192
|
+
// API methods (typed wrapper around proxy)
|
|
193
|
+
customer: {
|
|
194
|
+
async get(options) {
|
|
195
|
+
return $fetch("/customer", { method: "GET", query: options.query });
|
|
196
|
+
},
|
|
197
|
+
async create(options) {
|
|
198
|
+
return $fetch("/customer", { method: "POST", body: options.body });
|
|
199
|
+
}
|
|
200
|
+
},
|
|
201
|
+
plans: {
|
|
202
|
+
async list() {
|
|
203
|
+
return $fetch("/plans", { method: "GET" });
|
|
204
|
+
}
|
|
205
|
+
},
|
|
206
|
+
plan: {
|
|
207
|
+
async get(options) {
|
|
208
|
+
return $fetch("/plan", { method: "GET", query: options.query });
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
subscription: {
|
|
212
|
+
async get(options) {
|
|
213
|
+
return $fetch("/subscription", { method: "GET", query: options.query });
|
|
214
|
+
},
|
|
215
|
+
async create(options) {
|
|
216
|
+
return $fetch("/subscription", { method: "POST", body: options.body });
|
|
217
|
+
},
|
|
218
|
+
async cancel(options) {
|
|
219
|
+
return $fetch("/subscription/cancel", {
|
|
220
|
+
method: "POST",
|
|
221
|
+
body: options.body
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
},
|
|
225
|
+
health: {
|
|
226
|
+
async get() {
|
|
227
|
+
return $fetch("/health", { method: "GET" });
|
|
228
|
+
}
|
|
229
|
+
},
|
|
230
|
+
// Utility methods
|
|
231
|
+
setCustomerId(customerId) {
|
|
232
|
+
customerIdAtom.set(customerId);
|
|
233
|
+
$customer.refresh();
|
|
234
|
+
$subscription.refresh();
|
|
235
|
+
},
|
|
236
|
+
async refresh() {
|
|
237
|
+
await Promise.all([
|
|
238
|
+
$customer.refresh(),
|
|
239
|
+
$subscription.refresh(),
|
|
240
|
+
$plans.refresh()
|
|
241
|
+
]);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export { createBillingClient, useAsyncStore, useStore };
|
|
247
|
+
//# sourceMappingURL=index.js.map
|
|
248
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/client/atoms.ts","../../../src/client/proxy.ts","../../../src/client/react/react-store.ts","../../../src/client/react/index.ts"],"names":["atom"],"mappings":"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","file":"index.js","sourcesContent":["import type { AsyncAtom, Atom } from \"./types\";\n\n/**\n * Create a simple atom for reactive state\n */\nexport function atom<T>(initialValue: T): Atom<T> {\n let value = initialValue;\n const listeners = new Set<(value: T) => void>();\n\n return {\n get() {\n return value;\n },\n\n set(newValue: T) {\n value = newValue;\n for (const listener of listeners) {\n listener(value);\n }\n },\n\n subscribe(callback: (value: T) => void) {\n listeners.add(callback);\n // Call immediately with current value\n callback(value);\n // Return unsubscribe function\n return () => {\n listeners.delete(callback);\n };\n },\n };\n}\n\n/**\n * Create an async atom that fetches data\n */\nexport function asyncAtom<T>(\n fetcher: () => Promise<T>,\n options: { autoFetch?: boolean } = {},\n): AsyncAtom<T> {\n const valueAtom = atom<T | null>(null);\n const loadingAtom = atom(false);\n const errorAtom = atom<Error | null>(null);\n\n const refresh = async () => {\n loadingAtom.set(true);\n errorAtom.set(null);\n\n try {\n const data = await fetcher();\n valueAtom.set(data);\n } catch (err) {\n errorAtom.set(err instanceof Error ? err : new Error(String(err)));\n } finally {\n loadingAtom.set(false);\n }\n };\n\n // Auto-fetch on creation if enabled\n if (options.autoFetch !== false) {\n refresh();\n }\n\n return {\n get() {\n return valueAtom.get();\n },\n\n isLoading() {\n return loadingAtom.get();\n },\n\n error() {\n return errorAtom.get();\n },\n\n refresh,\n\n subscribe(callback: (value: T | null) => void) {\n return valueAtom.subscribe(callback);\n },\n };\n}\n\n/**\n * Computed atom that derives from other atoms\n */\nexport function computed<T, R>(\n sourceAtom: Atom<T>,\n transform: (value: T) => R,\n): Atom<R> {\n const computedAtom = atom(transform(sourceAtom.get()));\n\n sourceAtom.subscribe((value) => {\n computedAtom.set(transform(value));\n });\n\n return {\n get() {\n return computedAtom.get();\n },\n set() {\n throw new Error(\"Cannot set a computed atom directly\");\n },\n subscribe: computedAtom.subscribe,\n };\n}\n","import type { ClientConfig } from \"./types\";\n\n/**\n * HTTP methods\n */\ntype HttpMethod = \"GET\" | \"POST\" | \"PUT\" | \"PATCH\" | \"DELETE\";\n\n/**\n * Fetch options\n */\ninterface FetchOptions {\n method?: HttpMethod;\n body?: unknown;\n query?: Record<string, string | undefined>;\n headers?: Record<string, string>;\n}\n\n/**\n * Create a configured fetch function\n */\nexport function createFetch(config: ClientConfig = {}) {\n const baseFetch = config.fetch ?? fetch;\n const baseURL = config.baseURL ?? \"/api/billing\";\n\n return async <T>(path: string, options: FetchOptions = {}): Promise<T> => {\n const method = options.method ?? \"GET\";\n let url = `${baseURL}${path}`;\n\n // Add query params\n if (options.query) {\n const params = new URLSearchParams();\n for (const [key, value] of Object.entries(options.query)) {\n if (value !== undefined) {\n params.set(key, value);\n }\n }\n const queryString = params.toString();\n if (queryString) {\n url += `?${queryString}`;\n }\n }\n\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n ...config.headers,\n ...options.headers,\n };\n\n const fetchOptions: RequestInit = {\n method,\n headers,\n credentials: config.credentials ?? \"include\",\n };\n\n if (options.body && [\"POST\", \"PUT\", \"PATCH\"].includes(method)) {\n fetchOptions.body = JSON.stringify(options.body);\n }\n\n const response = await baseFetch(url, fetchOptions);\n\n if (!response.ok) {\n const errorData = (await response\n .json()\n .catch(() => ({ error: { message: \"Unknown error\" } }))) as {\n error?: { message?: string };\n };\n throw new Error(\n errorData?.error?.message ?? `Request failed: ${response.status}`,\n );\n }\n\n return response.json() as Promise<T>;\n };\n}\n\n/**\n * Path segments for the proxy\n */\ntype PathSegment = string;\n\n/**\n * Create a proxy that converts method calls to API requests\n *\n * @example\n * ```typescript\n * const api = createProxy($fetch);\n * await api.customer.get({ query: { externalId: \"123\" } });\n * await api.plans.list();\n * ```\n */\nexport function createProxy<T extends ReturnType<typeof createFetch>>(\n $fetch: T,\n pathMethods: Record<string, HttpMethod> = {},\n): Record<string, unknown> {\n // Default path methods\n const _methods: Record<string, HttpMethod> = {\n \"/customer:GET\": \"GET\",\n \"/customer:POST\": \"POST\",\n \"/plans:GET\": \"GET\",\n \"/plan:GET\": \"GET\",\n \"/subscription:GET\": \"GET\",\n \"/health:GET\": \"GET\",\n ...pathMethods,\n };\n\n function createNestedProxy(segments: PathSegment[]): unknown {\n return new Proxy(() => {}, {\n get(_, prop: string) {\n // Handle special methods\n if (prop === \"then\" || prop === \"catch\" || prop === \"finally\") {\n return undefined;\n }\n\n // Add segment and return nested proxy\n return createNestedProxy([...segments, prop]);\n },\n\n apply(_, __, args: unknown[]) {\n // Convert segments to path\n // e.g., [\"customer\", \"get\"] -> \"/customer\" with GET method\n const lastSegment = segments[segments.length - 1] ?? \"\";\n const pathSegments = segments.slice(0, -1);\n\n // Determine method from last segment or default\n let method: HttpMethod = \"GET\";\n if (lastSegment === \"get\" || lastSegment === \"list\") {\n method = \"GET\";\n } else if (lastSegment === \"create\" || lastSegment === \"post\") {\n method = \"POST\";\n } else if (lastSegment === \"update\" || lastSegment === \"put\") {\n method = \"PUT\";\n } else if (lastSegment === \"patch\") {\n method = \"PATCH\";\n } else if (lastSegment === \"delete\" || lastSegment === \"remove\") {\n method = \"DELETE\";\n } else {\n // If last segment isn't a method, include it in path\n pathSegments.push(lastSegment);\n }\n\n // Build path\n const path =\n \"/\" +\n pathSegments\n .join(\"/\")\n .replace(/([A-Z])/g, \"-$1\")\n .toLowerCase();\n\n // Get options from args\n const options = (args[0] as FetchOptions) ?? {};\n\n return $fetch(path, { ...options, method });\n },\n });\n }\n\n return createNestedProxy([]) as Record<string, unknown>;\n}\n","import { useCallback, useRef, useSyncExternalStore } from \"react\";\nimport type { AsyncAtom, Atom } from \"../types\";\n\n/**\n * Hook to subscribe to an atom in React\n * Similar to nanostores' useStore\n */\nexport function useStore<T>(atom: Atom<T>): T {\n const snapshotRef = useRef<T>(atom.get());\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const emitChange = (value: T) => {\n if (snapshotRef.current === value) return;\n snapshotRef.current = value;\n onChange();\n };\n\n // Subscribe to atom changes\n return atom.subscribe(emitChange);\n },\n [atom],\n );\n\n const get = () => snapshotRef.current;\n\n return useSyncExternalStore(subscribe, get, get);\n}\n\n/**\n * Hook to subscribe to an async atom in React\n * Returns { data, isLoading, error, refresh }\n */\nexport function useAsyncStore<T>(atom: AsyncAtom<T>): {\n data: T | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n} {\n const snapshotRef = useRef<T | null>(atom.get());\n\n const subscribe = useCallback(\n (onChange: () => void) => {\n const emitChange = (value: T | null) => {\n if (snapshotRef.current === value) return;\n snapshotRef.current = value;\n onChange();\n };\n\n return atom.subscribe(emitChange);\n },\n [atom],\n );\n\n const get = () => snapshotRef.current;\n\n const data = useSyncExternalStore(subscribe, get, get);\n\n return {\n data,\n isLoading: atom.isLoading(),\n error: atom.error(),\n refresh: atom.refresh,\n };\n}\n","import type { Customer, Plan } from \"../../types/models\";\nimport { asyncAtom, atom } from \"../atoms\";\nimport { createFetch } from \"../proxy\";\nimport type {\n AsyncAtom,\n CancelSubscriptionInput,\n CancelSubscriptionResponse,\n ClientConfig,\n CreateSubscriptionInput,\n CreateSubscriptionResponse,\n HealthResponse,\n SubscriptionResponse,\n} from \"../types\";\nimport { useAsyncStore } from \"./react-store\";\n\n/**\n * React billing client interface\n */\nexport interface BillingClientReact {\n // React hooks (auto-subscribing)\n useCustomer: () => {\n data: Customer | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n };\n useSubscription: () => {\n data: SubscriptionResponse | null;\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n };\n usePlans: () => {\n data: Plan[];\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n };\n\n // Raw atoms (for advanced usage)\n $customer: AsyncAtom<Customer | null>;\n $subscription: AsyncAtom<SubscriptionResponse | null>;\n $plans: AsyncAtom<Plan[]>;\n\n // API methods\n customer: {\n get(options: {\n query: { externalId: string };\n }): Promise<{ customer: Customer | null }>;\n create(options: {\n body: { externalId: string; email: string; name?: string };\n }): Promise<{ customer: Customer }>;\n };\n\n plans: {\n list(): Promise<{ plans: Plan[] }>;\n };\n\n plan: {\n get(options: {\n query: { id?: string; code?: string };\n }): Promise<{ plan: Plan | null; prices: unknown[] }>;\n };\n\n subscription: {\n get(options: {\n query: { customerId: string };\n }): Promise<SubscriptionResponse>;\n create(options: {\n body: CreateSubscriptionInput;\n }): Promise<CreateSubscriptionResponse>;\n cancel(options: {\n body: CancelSubscriptionInput;\n }): Promise<CancelSubscriptionResponse>;\n };\n\n health: {\n get(): Promise<HealthResponse>;\n };\n\n // Utility methods\n setCustomerId(customerId: string): void;\n refresh(): Promise<void>;\n}\n\n/**\n * Create a React billing client\n *\n * @example\n * ```typescript\n * import { createBillingClient } from \"@billsdk/core/react\";\n *\n * // Uses default baseURL: \"/api/billing\"\n * export const billing = createBillingClient();\n *\n * // In a component\n * function Dashboard() {\n * const { data: subscription, isLoading } = billing.useSubscription();\n *\n * if (isLoading) return <Loading />;\n * return <div>Plan: {subscription?.plan?.name}</div>;\n * }\n * ```\n */\nexport function createBillingClient(\n config: ClientConfig = {},\n): BillingClientReact {\n const $fetch = createFetch(config);\n\n // Current customer ID atom\n const customerIdAtom = atom<string | null>(null);\n\n // Async atoms for reactive state\n const $customer = asyncAtom<Customer | null>(\n async () => {\n const customerId = customerIdAtom.get();\n if (!customerId) return null;\n\n const response = await $fetch<{ customer: Customer | null }>(\n \"/customer\",\n {\n method: \"GET\",\n query: { externalId: customerId },\n },\n );\n return response.customer;\n },\n { autoFetch: false },\n );\n\n const $subscription = asyncAtom<SubscriptionResponse | null>(\n async () => {\n const customerId = customerIdAtom.get();\n if (!customerId) return null;\n\n const response = await $fetch<SubscriptionResponse>(\"/subscription\", {\n method: \"GET\",\n query: { customerId },\n });\n return response;\n },\n { autoFetch: false },\n );\n\n const $plans = asyncAtom<Plan[]>(\n async () => {\n const response = await $fetch<{ plans: Plan[] }>(\"/plans\", {\n method: \"GET\",\n });\n return response.plans;\n },\n { autoFetch: true },\n );\n\n return {\n // React hooks\n useCustomer: () => useAsyncStore($customer),\n useSubscription: () => useAsyncStore($subscription),\n usePlans: () =>\n useAsyncStore($plans) as {\n data: Plan[];\n isLoading: boolean;\n error: Error | null;\n refresh: () => Promise<void>;\n },\n\n // Raw atoms\n $customer,\n $subscription,\n $plans,\n\n // API methods (typed wrapper around proxy)\n customer: {\n async get(options) {\n return $fetch(\"/customer\", { method: \"GET\", query: options.query });\n },\n async create(options) {\n return $fetch(\"/customer\", { method: \"POST\", body: options.body });\n },\n },\n\n plans: {\n async list() {\n return $fetch(\"/plans\", { method: \"GET\" });\n },\n },\n\n plan: {\n async get(options) {\n return $fetch(\"/plan\", { method: \"GET\", query: options.query });\n },\n },\n\n subscription: {\n async get(options) {\n return $fetch(\"/subscription\", { method: \"GET\", query: options.query });\n },\n async create(options) {\n return $fetch(\"/subscription\", { method: \"POST\", body: options.body });\n },\n async cancel(options) {\n return $fetch(\"/subscription/cancel\", {\n method: \"POST\",\n body: options.body,\n });\n },\n },\n\n health: {\n async get() {\n return $fetch(\"/health\", { method: \"GET\" });\n },\n },\n\n // Utility methods\n setCustomerId(customerId: string) {\n customerIdAtom.set(customerId);\n // Refresh customer-dependent atoms\n $customer.refresh();\n $subscription.refresh();\n },\n\n async refresh() {\n await Promise.all([\n $customer.refresh(),\n $subscription.refresh(),\n $plans.refresh(),\n ]);\n },\n };\n}\n\n// Re-export types\nexport type * from \"../types\";\n// Re-export store hooks for advanced usage\nexport { useAsyncStore, useStore } from \"./react-store\";\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,8 +1,28 @@
|
|
|
1
|
+
export * from '@billsdk/core';
|
|
2
|
+
export { BillSDK, BillSDKOptions, BillingInterval, ConfirmResult, Customer, DBAdapter, ExtractFeatureCodes, Feature, FeatureConfig, PaymentAdapter, PaymentParams, PaymentResult, PaymentResultActive, PaymentResultFailed, PaymentResultPending, Plan, PlanConfig, PlanFeature, PlanPrice, PlanPriceConfig, SortBy, SortDirection, Subscription, SubscriptionStatus, Where, WhereOperator } from '@billsdk/core';
|
|
3
|
+
export { DrizzleAdapterConfig, DrizzleDB, drizzleAdapter } from '@billsdk/drizzle-adapter';
|
|
4
|
+
export { memoryAdapter } from '@billsdk/memory-adapter';
|
|
5
|
+
export { paymentAdapter } from '@billsdk/payment-adapter';
|
|
6
|
+
import { FeatureConfig, BillSDKOptions, BillSDK } from '@billsdk/core/types';
|
|
7
|
+
|
|
1
8
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
9
|
+
* Create a BillSDK instance
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```typescript
|
|
13
|
+
* import { billsdk } from "@billsdk/core";
|
|
14
|
+
*
|
|
15
|
+
* export const billing = billsdk({
|
|
16
|
+
* basePath: "/api/billing",
|
|
17
|
+
* features: [
|
|
18
|
+
* { code: "export", name: "Export" },
|
|
19
|
+
* ],
|
|
20
|
+
* plans: [
|
|
21
|
+
* { code: "pro", features: ["export"] }, // Validated!
|
|
22
|
+
* ],
|
|
23
|
+
* });
|
|
24
|
+
* ```
|
|
4
25
|
*/
|
|
5
|
-
declare const
|
|
6
|
-
declare function billsdk(): string;
|
|
26
|
+
declare function billsdk<const TFeatures extends readonly FeatureConfig<string>[]>(options: BillSDKOptions<TFeatures>): BillSDK<BillSDKOptions<TFeatures>>;
|
|
7
27
|
|
|
8
|
-
export { billsdk
|
|
28
|
+
export { billsdk };
|