UNPKG

a0-purchases

Version:

Lightweight subscription management for AI apps with auto-detecting providers

178 lines 8.17 kB
import { PURCHASES_ERROR_CODE } from '../types'; import { API_BASE_URL, APP_ID, API_KEY, APP_LIVE } from '../constants'; class BackendClient { constructor() { this.config = { debug: false }; } configure(config) { this.config = Object.assign(Object.assign({}, this.config), config); } logEvent(event, data) { if (this.config.debug) { console.log(`[Backend] ${event}`, data ? JSON.stringify(data, null, 2) : ''); } } createError(message, code = PURCHASES_ERROR_CODE.UNKNOWN_ERROR, originalError) { this.logEvent('Error occurred', { message, code, originalError }); const error = new Error(message); error.code = code; error.message = message; error.userCancelled = false; if (originalError) { error.underlyingError = originalError; if (originalError.message && message !== originalError.message) { error.message = `${message} (Details: ${originalError.message})`; } } return error; } async fetchApi(endpoint, options = {}) { var _a, _b, _c, _d; const url = `${API_BASE_URL}${endpoint}`; this.logEvent(`Requesting ${options.method || 'GET'} ${url}`, options.body); if (!APP_ID || !API_KEY) { throw this.createError('Missing required configuration: APP_ID or API_KEY', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } try { const response = await fetch(url, Object.assign(Object.assign({}, options), { headers: Object.assign({ 'Content-Type': 'application/json', 'x-a0-project-id': APP_ID, 'a0-project-key': API_KEY, 'environment': `${APP_LIVE ? 'production' : 'development'}` }, (options.headers || {})) })); const responseData = await response.json(); if (!response.ok) { this.logEvent(`Request failed: ${response.status} ${url}`, responseData); if (((_a = responseData === null || responseData === void 0 ? void 0 : responseData.error) === null || _a === void 0 ? void 0 : _a.code) && ((_b = responseData === null || responseData === void 0 ? void 0 : responseData.error) === null || _b === void 0 ? void 0 : _b.message)) { throw this.createError(responseData.error.message, responseData.error.code); } else if (responseData === null || responseData === void 0 ? void 0 : responseData.message) { throw this.createError(responseData.message, PURCHASES_ERROR_CODE.UNKNOWN_ERROR, responseData); } else { throw this.createError(`HTTP error ${response.status}`, PURCHASES_ERROR_CODE.UNKNOWN_ERROR, responseData); } } this.logEvent(`Request successful: ${url}`, responseData); if (responseData.success === false) { throw this.createError(((_c = responseData.error) === null || _c === void 0 ? void 0 : _c.message) || 'Backend indicated failure', ((_d = responseData.error) === null || _d === void 0 ? void 0 : _d.code) || PURCHASES_ERROR_CODE.UNKNOWN_ERROR, responseData.error); } return responseData.data || responseData; } catch (error) { if (error.code && error.message) { throw error; // Re-throw if it's already a LibraryError } this.logEvent(`Network or parsing error: ${url}`, error); throw this.createError(error.message || 'Network request failed', PURCHASES_ERROR_CODE.UNKNOWN_ERROR, error); } } async fetchOfferings(provider) { this.logEvent('Fetching offerings from backend', { provider }); const response = await this.fetchApi(`/${APP_ID}/offerings?provider=${provider || 'stripe'}`); if (response && response.offerings) { return response.offerings; } else { console.warn('[Backend] No offerings found in response', response); return { all: {}, current: null }; } } async getCustomerInfo(appUserId) { if (!appUserId) { throw this.createError('App User ID is required', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } return this.fetchApi(`/customer/${encodeURIComponent(appUserId)}`); } async login(appUserId) { if (!appUserId) { throw this.createError('App User ID is required for login', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } return this.fetchApi('/login', { method: 'POST', body: JSON.stringify({ app_user_id: appUserId, project_id: APP_ID }), }); } async postPurchase(appUserId, productId, purchaseToken, transactionId, receipt, platform) { if (!appUserId) { throw this.createError('App User ID is required', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } const body = { app_user_id: appUserId, product_id: productId, transaction_receipt: receipt, }; if (platform === 'ios' && transactionId) { body.apple_transaction_id = transactionId; } else if (platform === 'android' && purchaseToken) { // Add Android-specific fields if needed } this.logEvent('Posting purchase data', body); return this.fetchApi('/purchase', { method: 'POST', body: JSON.stringify(body), }); } async fetchPaymentSheetParams(appUserId, pkg) { return this.fetchApi(`/${APP_ID}/payment-sheet`, { method: 'POST', body: JSON.stringify({ app_user_id: appUserId, pkg: { product_id: pkg.product.identifier, package_id: pkg.identifier, offering_id: pkg.presentedOfferingContext.offeringIdentifier, }, }), }); } async createCheckoutSession(appUserId, pkg) { return this.fetchApi(`/${APP_ID}/checkout-session`, { method: 'POST', body: JSON.stringify({ app_user_id: appUserId, pkg: { product_id: pkg.product.identifier, package_id: pkg.identifier, offering_id: pkg.presentedOfferingContext.offeringIdentifier, }, }), }); } async createManageSubscriptionSession(appUserId) { if (!appUserId) { throw this.createError('App User ID is required', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } return this.fetchApi(`/${APP_ID}/manage-subscription`, { method: 'POST', body: JSON.stringify({ app_user_id: appUserId }), }); } async getStripeInformation() { return this.fetchApi(`/${APP_ID}/stripe-info`); } async restorePurchases(appUserId, appleTransactionId) { if (!appUserId) { throw this.createError('App User ID is required for restore', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } if (!appleTransactionId) { throw this.createError('Apple transaction ID is required for restore', PURCHASES_ERROR_CODE.PURCHASE_INVALID_ERROR); } this.logEvent('Restoring purchases', { appUserId, appleTransactionId }); return this.fetchApi('/restore', { method: 'POST', body: JSON.stringify({ app_user_id: appUserId, apple_transaction_id: appleTransactionId }), }); } async linkAlias(oldId, newId) { if (!oldId || !newId) { throw this.createError('Both oldId and newId are required', PURCHASES_ERROR_CODE.INVALID_APP_USER_ID_ERROR); } await this.fetchApi(`/app/link-alias`, { method: 'POST', body: JSON.stringify({ old_id: oldId, new_id: newId, project_id: APP_ID }), }); } } // Export singleton instance export const backendClient = new BackendClient(); //# sourceMappingURL=backendClient.js.map