@gamifyio/node 0.1.0 → 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/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
'use strict';var l="https://
|
|
1
|
+
'use strict';var l="https://boostapi-production.up.railway.app";var c=class{secretKey;baseUrl;timeout;retries;constructor(e){if(!e.secretKey)throw new Error("GamifyClient requires a secretKey");if(!e.secretKey.startsWith("sk_"))throw new Error("GamifyClient requires a secret key (sk_live_*). Publishable keys (pk_live_*) should only be used in client-side SDKs.");this.secretKey=e.secretKey,this.baseUrl=(e.baseUrl||l).replace(/\/$/,""),this.timeout=e.timeout||3e4,this.retries=e.retries||3;}async track(e){return this.request("/v1/events/track",{userId:e.userId,event:e.event,properties:e.properties||{},timestamp:e.timestamp||new Date().toISOString()})}async purchase(e){return this.track({userId:e.userId,event:"purchase",properties:{orderId:e.orderId,amount:e.amount,currency:e.currency||"USD",items:e.items},timestamp:e.timestamp})}async identify(e,t){return this.track({userId:e,event:"$profile_update",properties:t})}async referralSuccess(e){return this.track({userId:e.referredUserId,event:"referral_success",properties:{referralCode:e.referralCode},timestamp:e.timestamp})}async checkoutComplete(e){return this.track({userId:e.userId,event:"checkout_complete",properties:{orderId:e.orderId,amount:e.amount,currency:e.currency||"USD",items:e.items},timestamp:e.timestamp})}async request(e,t){let u=`${this.baseUrl}${e}`,n=null;for(let i=0;i<this.retries;i++)try{let r=new AbortController,m=setTimeout(()=>r.abort(),this.timeout),s=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.secretKey,"User-Agent":"gamify-node/0.1.0"},body:JSON.stringify(t),signal:r.signal});if(clearTimeout(m),!s.ok){let a=await s.text(),o;try{let p=JSON.parse(a);o=p.message||p.error||a;}catch{o=a||`HTTP ${s.status}`;}if(s.status>=400&&s.status<500)return {success:!1,error:o};throw new Error(o)}return {success:!0}}catch(r){if(n=r instanceof Error?r:new Error(String(r)),n.name==="AbortError")return {success:false,error:"Request timeout"};i<this.retries-1&&await this.sleep(Math.pow(2,i)*100);}return {success:false,error:n?.message||"Request failed after retries"}}sleep(e){return new Promise(t=>setTimeout(t,e))}};
|
|
2
2
|
exports.GamifyClient=c;//# sourceMappingURL=index.cjs.map
|
|
3
3
|
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","GamifyClient","config","event","data","userId","traits","path","body","url","lastError","attempt","controller","timeoutId","response","errorBody","errorMessage","errorJson","error","ms","resolve"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n GamifyConfig,\n TrackEvent,\n PurchaseEvent,\n UserTraits,\n ReferralEvent,\n ApiResponse,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.gamify.io';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Gamify Node.js SDK Client\n *\n * Use this client for server-side event tracking with your secret API key.\n * This client can send all event types including financial events like purchases.\n *\n * @example\n * ```typescript\n * import { GamifyClient } from '@gamifyio/node';\n *\n * const client = new GamifyClient({\n * secretKey: 'sk_live_your_key_here',\n * });\n *\n * // Track a purchase\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * });\n * ```\n */\nexport class GamifyClient {\n private readonly secretKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(config: GamifyConfig) {\n // Validate secret key format\n if (!config.secretKey) {\n throw new Error('GamifyClient requires a secretKey');\n }\n\n if (!config.secretKey.startsWith('sk_')) {\n throw new Error(\n 'GamifyClient requires a secret key (sk_live_*). ' +\n 'Publishable keys (pk_live_*) should only be used in client-side SDKs.'\n );\n }\n\n this.secretKey = config.secretKey;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.retries = config.retries || DEFAULT_RETRIES;\n }\n\n /**\n * Track a custom event\n *\n * @example\n * ```typescript\n * await client.track({\n * userId: 'user_123',\n * event: 'subscription_renewed',\n * properties: {\n * plan: 'premium',\n * amount: 2999,\n * },\n * });\n * ```\n */\n async track(event: TrackEvent): Promise<ApiResponse> {\n return this.request('/v1/events/track', {\n userId: event.userId,\n event: event.event,\n properties: event.properties || {},\n timestamp: event.timestamp || new Date().toISOString(),\n });\n }\n\n /**\n * Track a purchase event\n *\n * This is a convenience method that sends a properly formatted purchase event.\n * Purchase events are used for affiliate commission calculations.\n *\n * @example\n * ```typescript\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * items: [\n * { productId: 'prod_1', name: 'Widget', unitPrice: 4999, quantity: 2 },\n * ],\n * });\n * ```\n */\n async purchase(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'purchase',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Identify a user with traits\n *\n * Updates user profile information for personalization and segmentation.\n *\n * @example\n * ```typescript\n * await client.identify('user_123', {\n * email: 'john@example.com',\n * name: 'John Doe',\n * plan: 'premium',\n * signupDate: '2024-01-15',\n * });\n * ```\n */\n async identify(userId: string, traits: UserTraits): Promise<ApiResponse> {\n return this.track({\n userId,\n event: '$profile_update',\n properties: traits,\n });\n }\n\n /**\n * Track a successful referral\n *\n * Call this when a referred user completes a qualifying action\n * (e.g., makes their first purchase, completes signup).\n *\n * @example\n * ```typescript\n * await client.referralSuccess({\n * referredUserId: 'new_user_123',\n * referralCode: 'FRIEND20',\n * });\n * ```\n */\n async referralSuccess(data: ReferralEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.referredUserId,\n event: 'referral_success',\n properties: {\n referralCode: data.referralCode,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Track checkout completion\n *\n * Alternative event name for purchase tracking.\n * Use either purchase() or checkoutComplete(), not both for the same transaction.\n */\n async checkoutComplete(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'checkout_complete',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Make an HTTP request to the Gamify API\n */\n private async request(\n path: string,\n body: Record<string, unknown>\n ): Promise<ApiResponse> {\n const url = `${this.baseUrl}${path}`;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.secretKey,\n 'User-Agent': `gamify-node/0.1.0`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorBody);\n errorMessage = errorJson.message || errorJson.error || errorBody;\n } catch {\n errorMessage = errorBody || `HTTP ${response.status}`;\n }\n\n // Don't retry on client errors (4xx)\n if (response.status >= 400 && response.status < 500) {\n return {\n success: false,\n error: errorMessage,\n };\n }\n\n throw new Error(errorMessage);\n }\n\n return { success: true };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on abort (timeout)\n if (lastError.name === 'AbortError') {\n return {\n success: false,\n error: 'Request timeout',\n };\n }\n\n // Wait before retrying (exponential backoff)\n if (attempt < this.retries - 1) {\n await this.sleep(Math.pow(2, attempt) * 100);\n }\n }\n }\n\n return {\n success: false,\n error: lastError?.message || 'Request failed after retries',\n };\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","GamifyClient","config","event","data","userId","traits","path","body","url","lastError","attempt","controller","timeoutId","response","errorBody","errorMessage","errorJson","error","ms","resolve"],"mappings":"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","file":"index.cjs","sourcesContent":["import type {\n GamifyConfig,\n TrackEvent,\n PurchaseEvent,\n UserTraits,\n ReferralEvent,\n ApiResponse,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://boostapi-production.up.railway.app';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Gamify Node.js SDK Client\n *\n * Use this client for server-side event tracking with your secret API key.\n * This client can send all event types including financial events like purchases.\n *\n * @example\n * ```typescript\n * import { GamifyClient } from '@gamifyio/node';\n *\n * const client = new GamifyClient({\n * secretKey: 'sk_live_your_key_here',\n * });\n *\n * // Track a purchase\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * });\n * ```\n */\nexport class GamifyClient {\n private readonly secretKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(config: GamifyConfig) {\n // Validate secret key format\n if (!config.secretKey) {\n throw new Error('GamifyClient requires a secretKey');\n }\n\n if (!config.secretKey.startsWith('sk_')) {\n throw new Error(\n 'GamifyClient requires a secret key (sk_live_*). ' +\n 'Publishable keys (pk_live_*) should only be used in client-side SDKs.'\n );\n }\n\n this.secretKey = config.secretKey;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.retries = config.retries || DEFAULT_RETRIES;\n }\n\n /**\n * Track a custom event\n *\n * @example\n * ```typescript\n * await client.track({\n * userId: 'user_123',\n * event: 'subscription_renewed',\n * properties: {\n * plan: 'premium',\n * amount: 2999,\n * },\n * });\n * ```\n */\n async track(event: TrackEvent): Promise<ApiResponse> {\n return this.request('/v1/events/track', {\n userId: event.userId,\n event: event.event,\n properties: event.properties || {},\n timestamp: event.timestamp || new Date().toISOString(),\n });\n }\n\n /**\n * Track a purchase event\n *\n * This is a convenience method that sends a properly formatted purchase event.\n * Purchase events are used for affiliate commission calculations.\n *\n * @example\n * ```typescript\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * items: [\n * { productId: 'prod_1', name: 'Widget', unitPrice: 4999, quantity: 2 },\n * ],\n * });\n * ```\n */\n async purchase(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'purchase',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Identify a user with traits\n *\n * Updates user profile information for personalization and segmentation.\n *\n * @example\n * ```typescript\n * await client.identify('user_123', {\n * email: 'john@example.com',\n * name: 'John Doe',\n * plan: 'premium',\n * signupDate: '2024-01-15',\n * });\n * ```\n */\n async identify(userId: string, traits: UserTraits): Promise<ApiResponse> {\n return this.track({\n userId,\n event: '$profile_update',\n properties: traits,\n });\n }\n\n /**\n * Track a successful referral\n *\n * Call this when a referred user completes a qualifying action\n * (e.g., makes their first purchase, completes signup).\n *\n * @example\n * ```typescript\n * await client.referralSuccess({\n * referredUserId: 'new_user_123',\n * referralCode: 'FRIEND20',\n * });\n * ```\n */\n async referralSuccess(data: ReferralEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.referredUserId,\n event: 'referral_success',\n properties: {\n referralCode: data.referralCode,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Track checkout completion\n *\n * Alternative event name for purchase tracking.\n * Use either purchase() or checkoutComplete(), not both for the same transaction.\n */\n async checkoutComplete(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'checkout_complete',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Make an HTTP request to the Gamify API\n */\n private async request(\n path: string,\n body: Record<string, unknown>\n ): Promise<ApiResponse> {\n const url = `${this.baseUrl}${path}`;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.secretKey,\n 'User-Agent': `gamify-node/0.1.0`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorBody);\n errorMessage = errorJson.message || errorJson.error || errorBody;\n } catch {\n errorMessage = errorBody || `HTTP ${response.status}`;\n }\n\n // Don't retry on client errors (4xx)\n if (response.status >= 400 && response.status < 500) {\n return {\n success: false,\n error: errorMessage,\n };\n }\n\n throw new Error(errorMessage);\n }\n\n return { success: true };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on abort (timeout)\n if (lastError.name === 'AbortError') {\n return {\n success: false,\n error: 'Request timeout',\n };\n }\n\n // Wait before retrying (exponential backoff)\n if (attempt < this.retries - 1) {\n await this.sleep(Math.pow(2, attempt) * 100);\n }\n }\n }\n\n return {\n success: false,\n error: lastError?.message || 'Request failed after retries',\n };\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var l="https://
|
|
1
|
+
var l="https://boostapi-production.up.railway.app";var c=class{secretKey;baseUrl;timeout;retries;constructor(e){if(!e.secretKey)throw new Error("GamifyClient requires a secretKey");if(!e.secretKey.startsWith("sk_"))throw new Error("GamifyClient requires a secret key (sk_live_*). Publishable keys (pk_live_*) should only be used in client-side SDKs.");this.secretKey=e.secretKey,this.baseUrl=(e.baseUrl||l).replace(/\/$/,""),this.timeout=e.timeout||3e4,this.retries=e.retries||3;}async track(e){return this.request("/v1/events/track",{userId:e.userId,event:e.event,properties:e.properties||{},timestamp:e.timestamp||new Date().toISOString()})}async purchase(e){return this.track({userId:e.userId,event:"purchase",properties:{orderId:e.orderId,amount:e.amount,currency:e.currency||"USD",items:e.items},timestamp:e.timestamp})}async identify(e,t){return this.track({userId:e,event:"$profile_update",properties:t})}async referralSuccess(e){return this.track({userId:e.referredUserId,event:"referral_success",properties:{referralCode:e.referralCode},timestamp:e.timestamp})}async checkoutComplete(e){return this.track({userId:e.userId,event:"checkout_complete",properties:{orderId:e.orderId,amount:e.amount,currency:e.currency||"USD",items:e.items},timestamp:e.timestamp})}async request(e,t){let u=`${this.baseUrl}${e}`,n=null;for(let i=0;i<this.retries;i++)try{let r=new AbortController,m=setTimeout(()=>r.abort(),this.timeout),s=await fetch(u,{method:"POST",headers:{"Content-Type":"application/json","x-api-key":this.secretKey,"User-Agent":"gamify-node/0.1.0"},body:JSON.stringify(t),signal:r.signal});if(clearTimeout(m),!s.ok){let a=await s.text(),o;try{let p=JSON.parse(a);o=p.message||p.error||a;}catch{o=a||`HTTP ${s.status}`;}if(s.status>=400&&s.status<500)return {success:!1,error:o};throw new Error(o)}return {success:!0}}catch(r){if(n=r instanceof Error?r:new Error(String(r)),n.name==="AbortError")return {success:false,error:"Request timeout"};i<this.retries-1&&await this.sleep(Math.pow(2,i)*100);}return {success:false,error:n?.message||"Request failed after retries"}}sleep(e){return new Promise(t=>setTimeout(t,e))}};
|
|
2
2
|
export{c as GamifyClient};//# sourceMappingURL=index.js.map
|
|
3
3
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","GamifyClient","config","event","data","userId","traits","path","body","url","lastError","attempt","controller","timeoutId","response","errorBody","errorMessage","errorJson","error","ms","resolve"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n GamifyConfig,\n TrackEvent,\n PurchaseEvent,\n UserTraits,\n ReferralEvent,\n ApiResponse,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.gamify.io';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Gamify Node.js SDK Client\n *\n * Use this client for server-side event tracking with your secret API key.\n * This client can send all event types including financial events like purchases.\n *\n * @example\n * ```typescript\n * import { GamifyClient } from '@gamifyio/node';\n *\n * const client = new GamifyClient({\n * secretKey: 'sk_live_your_key_here',\n * });\n *\n * // Track a purchase\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * });\n * ```\n */\nexport class GamifyClient {\n private readonly secretKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(config: GamifyConfig) {\n // Validate secret key format\n if (!config.secretKey) {\n throw new Error('GamifyClient requires a secretKey');\n }\n\n if (!config.secretKey.startsWith('sk_')) {\n throw new Error(\n 'GamifyClient requires a secret key (sk_live_*). ' +\n 'Publishable keys (pk_live_*) should only be used in client-side SDKs.'\n );\n }\n\n this.secretKey = config.secretKey;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.retries = config.retries || DEFAULT_RETRIES;\n }\n\n /**\n * Track a custom event\n *\n * @example\n * ```typescript\n * await client.track({\n * userId: 'user_123',\n * event: 'subscription_renewed',\n * properties: {\n * plan: 'premium',\n * amount: 2999,\n * },\n * });\n * ```\n */\n async track(event: TrackEvent): Promise<ApiResponse> {\n return this.request('/v1/events/track', {\n userId: event.userId,\n event: event.event,\n properties: event.properties || {},\n timestamp: event.timestamp || new Date().toISOString(),\n });\n }\n\n /**\n * Track a purchase event\n *\n * This is a convenience method that sends a properly formatted purchase event.\n * Purchase events are used for affiliate commission calculations.\n *\n * @example\n * ```typescript\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * items: [\n * { productId: 'prod_1', name: 'Widget', unitPrice: 4999, quantity: 2 },\n * ],\n * });\n * ```\n */\n async purchase(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'purchase',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Identify a user with traits\n *\n * Updates user profile information for personalization and segmentation.\n *\n * @example\n * ```typescript\n * await client.identify('user_123', {\n * email: 'john@example.com',\n * name: 'John Doe',\n * plan: 'premium',\n * signupDate: '2024-01-15',\n * });\n * ```\n */\n async identify(userId: string, traits: UserTraits): Promise<ApiResponse> {\n return this.track({\n userId,\n event: '$profile_update',\n properties: traits,\n });\n }\n\n /**\n * Track a successful referral\n *\n * Call this when a referred user completes a qualifying action\n * (e.g., makes their first purchase, completes signup).\n *\n * @example\n * ```typescript\n * await client.referralSuccess({\n * referredUserId: 'new_user_123',\n * referralCode: 'FRIEND20',\n * });\n * ```\n */\n async referralSuccess(data: ReferralEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.referredUserId,\n event: 'referral_success',\n properties: {\n referralCode: data.referralCode,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Track checkout completion\n *\n * Alternative event name for purchase tracking.\n * Use either purchase() or checkoutComplete(), not both for the same transaction.\n */\n async checkoutComplete(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'checkout_complete',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Make an HTTP request to the Gamify API\n */\n private async request(\n path: string,\n body: Record<string, unknown>\n ): Promise<ApiResponse> {\n const url = `${this.baseUrl}${path}`;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.secretKey,\n 'User-Agent': `gamify-node/0.1.0`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorBody);\n errorMessage = errorJson.message || errorJson.error || errorBody;\n } catch {\n errorMessage = errorBody || `HTTP ${response.status}`;\n }\n\n // Don't retry on client errors (4xx)\n if (response.status >= 400 && response.status < 500) {\n return {\n success: false,\n error: errorMessage,\n };\n }\n\n throw new Error(errorMessage);\n }\n\n return { success: true };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on abort (timeout)\n if (lastError.name === 'AbortError') {\n return {\n success: false,\n error: 'Request timeout',\n };\n }\n\n // Wait before retrying (exponential backoff)\n if (attempt < this.retries - 1) {\n await this.sleep(Math.pow(2, attempt) * 100);\n }\n }\n }\n\n return {\n success: false,\n error: lastError?.message || 'Request failed after retries',\n };\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"names":["DEFAULT_BASE_URL","GamifyClient","config","event","data","userId","traits","path","body","url","lastError","attempt","controller","timeoutId","response","errorBody","errorMessage","errorJson","error","ms","resolve"],"mappings":"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","file":"index.js","sourcesContent":["import type {\n GamifyConfig,\n TrackEvent,\n PurchaseEvent,\n UserTraits,\n ReferralEvent,\n ApiResponse,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://boostapi-production.up.railway.app';\nconst DEFAULT_TIMEOUT = 30000;\nconst DEFAULT_RETRIES = 3;\n\n/**\n * Gamify Node.js SDK Client\n *\n * Use this client for server-side event tracking with your secret API key.\n * This client can send all event types including financial events like purchases.\n *\n * @example\n * ```typescript\n * import { GamifyClient } from '@gamifyio/node';\n *\n * const client = new GamifyClient({\n * secretKey: 'sk_live_your_key_here',\n * });\n *\n * // Track a purchase\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * });\n * ```\n */\nexport class GamifyClient {\n private readonly secretKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly retries: number;\n\n constructor(config: GamifyConfig) {\n // Validate secret key format\n if (!config.secretKey) {\n throw new Error('GamifyClient requires a secretKey');\n }\n\n if (!config.secretKey.startsWith('sk_')) {\n throw new Error(\n 'GamifyClient requires a secret key (sk_live_*). ' +\n 'Publishable keys (pk_live_*) should only be used in client-side SDKs.'\n );\n }\n\n this.secretKey = config.secretKey;\n this.baseUrl = (config.baseUrl || DEFAULT_BASE_URL).replace(/\\/$/, '');\n this.timeout = config.timeout || DEFAULT_TIMEOUT;\n this.retries = config.retries || DEFAULT_RETRIES;\n }\n\n /**\n * Track a custom event\n *\n * @example\n * ```typescript\n * await client.track({\n * userId: 'user_123',\n * event: 'subscription_renewed',\n * properties: {\n * plan: 'premium',\n * amount: 2999,\n * },\n * });\n * ```\n */\n async track(event: TrackEvent): Promise<ApiResponse> {\n return this.request('/v1/events/track', {\n userId: event.userId,\n event: event.event,\n properties: event.properties || {},\n timestamp: event.timestamp || new Date().toISOString(),\n });\n }\n\n /**\n * Track a purchase event\n *\n * This is a convenience method that sends a properly formatted purchase event.\n * Purchase events are used for affiliate commission calculations.\n *\n * @example\n * ```typescript\n * await client.purchase({\n * userId: 'user_123',\n * orderId: 'order_456',\n * amount: 9999, // $99.99 in cents\n * currency: 'USD',\n * items: [\n * { productId: 'prod_1', name: 'Widget', unitPrice: 4999, quantity: 2 },\n * ],\n * });\n * ```\n */\n async purchase(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'purchase',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Identify a user with traits\n *\n * Updates user profile information for personalization and segmentation.\n *\n * @example\n * ```typescript\n * await client.identify('user_123', {\n * email: 'john@example.com',\n * name: 'John Doe',\n * plan: 'premium',\n * signupDate: '2024-01-15',\n * });\n * ```\n */\n async identify(userId: string, traits: UserTraits): Promise<ApiResponse> {\n return this.track({\n userId,\n event: '$profile_update',\n properties: traits,\n });\n }\n\n /**\n * Track a successful referral\n *\n * Call this when a referred user completes a qualifying action\n * (e.g., makes their first purchase, completes signup).\n *\n * @example\n * ```typescript\n * await client.referralSuccess({\n * referredUserId: 'new_user_123',\n * referralCode: 'FRIEND20',\n * });\n * ```\n */\n async referralSuccess(data: ReferralEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.referredUserId,\n event: 'referral_success',\n properties: {\n referralCode: data.referralCode,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Track checkout completion\n *\n * Alternative event name for purchase tracking.\n * Use either purchase() or checkoutComplete(), not both for the same transaction.\n */\n async checkoutComplete(data: PurchaseEvent): Promise<ApiResponse> {\n return this.track({\n userId: data.userId,\n event: 'checkout_complete',\n properties: {\n orderId: data.orderId,\n amount: data.amount,\n currency: data.currency || 'USD',\n items: data.items,\n },\n timestamp: data.timestamp,\n });\n }\n\n /**\n * Make an HTTP request to the Gamify API\n */\n private async request(\n path: string,\n body: Record<string, unknown>\n ): Promise<ApiResponse> {\n const url = `${this.baseUrl}${path}`;\n let lastError: Error | null = null;\n\n for (let attempt = 0; attempt < this.retries; attempt++) {\n try {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n 'x-api-key': this.secretKey,\n 'User-Agent': `gamify-node/0.1.0`,\n },\n body: JSON.stringify(body),\n signal: controller.signal,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n const errorBody = await response.text();\n let errorMessage: string;\n\n try {\n const errorJson = JSON.parse(errorBody);\n errorMessage = errorJson.message || errorJson.error || errorBody;\n } catch {\n errorMessage = errorBody || `HTTP ${response.status}`;\n }\n\n // Don't retry on client errors (4xx)\n if (response.status >= 400 && response.status < 500) {\n return {\n success: false,\n error: errorMessage,\n };\n }\n\n throw new Error(errorMessage);\n }\n\n return { success: true };\n } catch (error) {\n lastError = error instanceof Error ? error : new Error(String(error));\n\n // Don't retry on abort (timeout)\n if (lastError.name === 'AbortError') {\n return {\n success: false,\n error: 'Request timeout',\n };\n }\n\n // Wait before retrying (exponential backoff)\n if (attempt < this.retries - 1) {\n await this.sleep(Math.pow(2, attempt) * 100);\n }\n }\n }\n\n return {\n success: false,\n error: lastError?.message || 'Request failed after retries',\n };\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n"]}
|