@gamifyio/node 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +277 -0
- package/dist/index.d.ts +277 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +51 -0
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var l="https://api.gamify.io";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 p=`${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(p,{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 u=JSON.parse(a);o=u.message||u.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
|
+
exports.GamifyClient=c;//# sourceMappingURL=index.cjs.map
|
|
3
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +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"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for the Gamify Node.js SDK
|
|
3
|
+
*/
|
|
4
|
+
interface GamifyConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Your secret API key (starts with sk_live_)
|
|
7
|
+
* Get this from your Gamify dashboard
|
|
8
|
+
*/
|
|
9
|
+
secretKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* Base URL for the Gamify API
|
|
12
|
+
* @default 'https://api.gamify.io'
|
|
13
|
+
*/
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Request timeout in milliseconds
|
|
17
|
+
* @default 30000
|
|
18
|
+
*/
|
|
19
|
+
timeout?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Number of retry attempts for failed requests
|
|
22
|
+
* @default 3
|
|
23
|
+
*/
|
|
24
|
+
retries?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Base event properties that all events share
|
|
28
|
+
*/
|
|
29
|
+
interface BaseEvent {
|
|
30
|
+
/**
|
|
31
|
+
* Unique identifier for the user
|
|
32
|
+
*/
|
|
33
|
+
userId: string;
|
|
34
|
+
/**
|
|
35
|
+
* ISO 8601 timestamp of when the event occurred
|
|
36
|
+
* If not provided, the current time will be used
|
|
37
|
+
*/
|
|
38
|
+
timestamp?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generic event for tracking custom events
|
|
42
|
+
*/
|
|
43
|
+
interface TrackEvent extends BaseEvent {
|
|
44
|
+
/**
|
|
45
|
+
* Name of the event (e.g., 'purchase', 'signup', 'page_view')
|
|
46
|
+
*/
|
|
47
|
+
event: string;
|
|
48
|
+
/**
|
|
49
|
+
* Additional properties for the event
|
|
50
|
+
*/
|
|
51
|
+
properties?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Cart item in a purchase
|
|
55
|
+
*/
|
|
56
|
+
interface PurchaseItem {
|
|
57
|
+
/**
|
|
58
|
+
* Unique identifier for the product
|
|
59
|
+
*/
|
|
60
|
+
productId: string;
|
|
61
|
+
/**
|
|
62
|
+
* Name of the product
|
|
63
|
+
*/
|
|
64
|
+
name: string;
|
|
65
|
+
/**
|
|
66
|
+
* Price per unit in cents
|
|
67
|
+
*/
|
|
68
|
+
unitPrice: number;
|
|
69
|
+
/**
|
|
70
|
+
* Quantity purchased
|
|
71
|
+
*/
|
|
72
|
+
quantity: number;
|
|
73
|
+
/**
|
|
74
|
+
* Optional product category
|
|
75
|
+
*/
|
|
76
|
+
category?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Purchase event data
|
|
80
|
+
*/
|
|
81
|
+
interface PurchaseEvent {
|
|
82
|
+
/**
|
|
83
|
+
* Unique identifier for the user making the purchase
|
|
84
|
+
*/
|
|
85
|
+
userId: string;
|
|
86
|
+
/**
|
|
87
|
+
* Unique order identifier from your system
|
|
88
|
+
*/
|
|
89
|
+
orderId: string;
|
|
90
|
+
/**
|
|
91
|
+
* Total amount in cents (e.g., 1999 for $19.99)
|
|
92
|
+
*/
|
|
93
|
+
amount: number;
|
|
94
|
+
/**
|
|
95
|
+
* ISO 4217 currency code (e.g., 'USD', 'EUR')
|
|
96
|
+
* @default 'USD'
|
|
97
|
+
*/
|
|
98
|
+
currency?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Items in the purchase
|
|
101
|
+
*/
|
|
102
|
+
items?: PurchaseItem[];
|
|
103
|
+
/**
|
|
104
|
+
* ISO 8601 timestamp of when the purchase occurred
|
|
105
|
+
*/
|
|
106
|
+
timestamp?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* User traits for identification
|
|
110
|
+
*/
|
|
111
|
+
interface UserTraits {
|
|
112
|
+
/**
|
|
113
|
+
* User's email address
|
|
114
|
+
*/
|
|
115
|
+
email?: string;
|
|
116
|
+
/**
|
|
117
|
+
* User's display name
|
|
118
|
+
*/
|
|
119
|
+
name?: string;
|
|
120
|
+
/**
|
|
121
|
+
* User's first name
|
|
122
|
+
*/
|
|
123
|
+
firstName?: string;
|
|
124
|
+
/**
|
|
125
|
+
* User's last name
|
|
126
|
+
*/
|
|
127
|
+
lastName?: string;
|
|
128
|
+
/**
|
|
129
|
+
* User's phone number
|
|
130
|
+
*/
|
|
131
|
+
phone?: string;
|
|
132
|
+
/**
|
|
133
|
+
* ISO 8601 timestamp of when the user was created
|
|
134
|
+
*/
|
|
135
|
+
createdAt?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Any additional custom traits
|
|
138
|
+
*/
|
|
139
|
+
[key: string]: unknown;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Referral tracking data
|
|
143
|
+
*/
|
|
144
|
+
interface ReferralEvent {
|
|
145
|
+
/**
|
|
146
|
+
* User ID of the person being referred (the new user)
|
|
147
|
+
*/
|
|
148
|
+
referredUserId: string;
|
|
149
|
+
/**
|
|
150
|
+
* Referral code used
|
|
151
|
+
*/
|
|
152
|
+
referralCode: string;
|
|
153
|
+
/**
|
|
154
|
+
* ISO 8601 timestamp of when the referral occurred
|
|
155
|
+
*/
|
|
156
|
+
timestamp?: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Response from API calls
|
|
160
|
+
*/
|
|
161
|
+
interface ApiResponse<T = void> {
|
|
162
|
+
success: boolean;
|
|
163
|
+
data?: T;
|
|
164
|
+
error?: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Gamify Node.js SDK Client
|
|
169
|
+
*
|
|
170
|
+
* Use this client for server-side event tracking with your secret API key.
|
|
171
|
+
* This client can send all event types including financial events like purchases.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* import { GamifyClient } from '@gamifyio/node';
|
|
176
|
+
*
|
|
177
|
+
* const client = new GamifyClient({
|
|
178
|
+
* secretKey: 'sk_live_your_key_here',
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* // Track a purchase
|
|
182
|
+
* await client.purchase({
|
|
183
|
+
* userId: 'user_123',
|
|
184
|
+
* orderId: 'order_456',
|
|
185
|
+
* amount: 9999, // $99.99 in cents
|
|
186
|
+
* currency: 'USD',
|
|
187
|
+
* });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
declare class GamifyClient {
|
|
191
|
+
private readonly secretKey;
|
|
192
|
+
private readonly baseUrl;
|
|
193
|
+
private readonly timeout;
|
|
194
|
+
private readonly retries;
|
|
195
|
+
constructor(config: GamifyConfig);
|
|
196
|
+
/**
|
|
197
|
+
* Track a custom event
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* await client.track({
|
|
202
|
+
* userId: 'user_123',
|
|
203
|
+
* event: 'subscription_renewed',
|
|
204
|
+
* properties: {
|
|
205
|
+
* plan: 'premium',
|
|
206
|
+
* amount: 2999,
|
|
207
|
+
* },
|
|
208
|
+
* });
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
track(event: TrackEvent): Promise<ApiResponse>;
|
|
212
|
+
/**
|
|
213
|
+
* Track a purchase event
|
|
214
|
+
*
|
|
215
|
+
* This is a convenience method that sends a properly formatted purchase event.
|
|
216
|
+
* Purchase events are used for affiliate commission calculations.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* await client.purchase({
|
|
221
|
+
* userId: 'user_123',
|
|
222
|
+
* orderId: 'order_456',
|
|
223
|
+
* amount: 9999, // $99.99 in cents
|
|
224
|
+
* currency: 'USD',
|
|
225
|
+
* items: [
|
|
226
|
+
* { productId: 'prod_1', name: 'Widget', unitPrice: 4999, quantity: 2 },
|
|
227
|
+
* ],
|
|
228
|
+
* });
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
purchase(data: PurchaseEvent): Promise<ApiResponse>;
|
|
232
|
+
/**
|
|
233
|
+
* Identify a user with traits
|
|
234
|
+
*
|
|
235
|
+
* Updates user profile information for personalization and segmentation.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* await client.identify('user_123', {
|
|
240
|
+
* email: 'john@example.com',
|
|
241
|
+
* name: 'John Doe',
|
|
242
|
+
* plan: 'premium',
|
|
243
|
+
* signupDate: '2024-01-15',
|
|
244
|
+
* });
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
identify(userId: string, traits: UserTraits): Promise<ApiResponse>;
|
|
248
|
+
/**
|
|
249
|
+
* Track a successful referral
|
|
250
|
+
*
|
|
251
|
+
* Call this when a referred user completes a qualifying action
|
|
252
|
+
* (e.g., makes their first purchase, completes signup).
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```typescript
|
|
256
|
+
* await client.referralSuccess({
|
|
257
|
+
* referredUserId: 'new_user_123',
|
|
258
|
+
* referralCode: 'FRIEND20',
|
|
259
|
+
* });
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
referralSuccess(data: ReferralEvent): Promise<ApiResponse>;
|
|
263
|
+
/**
|
|
264
|
+
* Track checkout completion
|
|
265
|
+
*
|
|
266
|
+
* Alternative event name for purchase tracking.
|
|
267
|
+
* Use either purchase() or checkoutComplete(), not both for the same transaction.
|
|
268
|
+
*/
|
|
269
|
+
checkoutComplete(data: PurchaseEvent): Promise<ApiResponse>;
|
|
270
|
+
/**
|
|
271
|
+
* Make an HTTP request to the Gamify API
|
|
272
|
+
*/
|
|
273
|
+
private request;
|
|
274
|
+
private sleep;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export { type ApiResponse, GamifyClient, type GamifyConfig, type PurchaseEvent, type PurchaseItem, type ReferralEvent, type TrackEvent, type UserTraits };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration options for the Gamify Node.js SDK
|
|
3
|
+
*/
|
|
4
|
+
interface GamifyConfig {
|
|
5
|
+
/**
|
|
6
|
+
* Your secret API key (starts with sk_live_)
|
|
7
|
+
* Get this from your Gamify dashboard
|
|
8
|
+
*/
|
|
9
|
+
secretKey: string;
|
|
10
|
+
/**
|
|
11
|
+
* Base URL for the Gamify API
|
|
12
|
+
* @default 'https://api.gamify.io'
|
|
13
|
+
*/
|
|
14
|
+
baseUrl?: string;
|
|
15
|
+
/**
|
|
16
|
+
* Request timeout in milliseconds
|
|
17
|
+
* @default 30000
|
|
18
|
+
*/
|
|
19
|
+
timeout?: number;
|
|
20
|
+
/**
|
|
21
|
+
* Number of retry attempts for failed requests
|
|
22
|
+
* @default 3
|
|
23
|
+
*/
|
|
24
|
+
retries?: number;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Base event properties that all events share
|
|
28
|
+
*/
|
|
29
|
+
interface BaseEvent {
|
|
30
|
+
/**
|
|
31
|
+
* Unique identifier for the user
|
|
32
|
+
*/
|
|
33
|
+
userId: string;
|
|
34
|
+
/**
|
|
35
|
+
* ISO 8601 timestamp of when the event occurred
|
|
36
|
+
* If not provided, the current time will be used
|
|
37
|
+
*/
|
|
38
|
+
timestamp?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Generic event for tracking custom events
|
|
42
|
+
*/
|
|
43
|
+
interface TrackEvent extends BaseEvent {
|
|
44
|
+
/**
|
|
45
|
+
* Name of the event (e.g., 'purchase', 'signup', 'page_view')
|
|
46
|
+
*/
|
|
47
|
+
event: string;
|
|
48
|
+
/**
|
|
49
|
+
* Additional properties for the event
|
|
50
|
+
*/
|
|
51
|
+
properties?: Record<string, unknown>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Cart item in a purchase
|
|
55
|
+
*/
|
|
56
|
+
interface PurchaseItem {
|
|
57
|
+
/**
|
|
58
|
+
* Unique identifier for the product
|
|
59
|
+
*/
|
|
60
|
+
productId: string;
|
|
61
|
+
/**
|
|
62
|
+
* Name of the product
|
|
63
|
+
*/
|
|
64
|
+
name: string;
|
|
65
|
+
/**
|
|
66
|
+
* Price per unit in cents
|
|
67
|
+
*/
|
|
68
|
+
unitPrice: number;
|
|
69
|
+
/**
|
|
70
|
+
* Quantity purchased
|
|
71
|
+
*/
|
|
72
|
+
quantity: number;
|
|
73
|
+
/**
|
|
74
|
+
* Optional product category
|
|
75
|
+
*/
|
|
76
|
+
category?: string;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Purchase event data
|
|
80
|
+
*/
|
|
81
|
+
interface PurchaseEvent {
|
|
82
|
+
/**
|
|
83
|
+
* Unique identifier for the user making the purchase
|
|
84
|
+
*/
|
|
85
|
+
userId: string;
|
|
86
|
+
/**
|
|
87
|
+
* Unique order identifier from your system
|
|
88
|
+
*/
|
|
89
|
+
orderId: string;
|
|
90
|
+
/**
|
|
91
|
+
* Total amount in cents (e.g., 1999 for $19.99)
|
|
92
|
+
*/
|
|
93
|
+
amount: number;
|
|
94
|
+
/**
|
|
95
|
+
* ISO 4217 currency code (e.g., 'USD', 'EUR')
|
|
96
|
+
* @default 'USD'
|
|
97
|
+
*/
|
|
98
|
+
currency?: string;
|
|
99
|
+
/**
|
|
100
|
+
* Items in the purchase
|
|
101
|
+
*/
|
|
102
|
+
items?: PurchaseItem[];
|
|
103
|
+
/**
|
|
104
|
+
* ISO 8601 timestamp of when the purchase occurred
|
|
105
|
+
*/
|
|
106
|
+
timestamp?: string;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* User traits for identification
|
|
110
|
+
*/
|
|
111
|
+
interface UserTraits {
|
|
112
|
+
/**
|
|
113
|
+
* User's email address
|
|
114
|
+
*/
|
|
115
|
+
email?: string;
|
|
116
|
+
/**
|
|
117
|
+
* User's display name
|
|
118
|
+
*/
|
|
119
|
+
name?: string;
|
|
120
|
+
/**
|
|
121
|
+
* User's first name
|
|
122
|
+
*/
|
|
123
|
+
firstName?: string;
|
|
124
|
+
/**
|
|
125
|
+
* User's last name
|
|
126
|
+
*/
|
|
127
|
+
lastName?: string;
|
|
128
|
+
/**
|
|
129
|
+
* User's phone number
|
|
130
|
+
*/
|
|
131
|
+
phone?: string;
|
|
132
|
+
/**
|
|
133
|
+
* ISO 8601 timestamp of when the user was created
|
|
134
|
+
*/
|
|
135
|
+
createdAt?: string;
|
|
136
|
+
/**
|
|
137
|
+
* Any additional custom traits
|
|
138
|
+
*/
|
|
139
|
+
[key: string]: unknown;
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* Referral tracking data
|
|
143
|
+
*/
|
|
144
|
+
interface ReferralEvent {
|
|
145
|
+
/**
|
|
146
|
+
* User ID of the person being referred (the new user)
|
|
147
|
+
*/
|
|
148
|
+
referredUserId: string;
|
|
149
|
+
/**
|
|
150
|
+
* Referral code used
|
|
151
|
+
*/
|
|
152
|
+
referralCode: string;
|
|
153
|
+
/**
|
|
154
|
+
* ISO 8601 timestamp of when the referral occurred
|
|
155
|
+
*/
|
|
156
|
+
timestamp?: string;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Response from API calls
|
|
160
|
+
*/
|
|
161
|
+
interface ApiResponse<T = void> {
|
|
162
|
+
success: boolean;
|
|
163
|
+
data?: T;
|
|
164
|
+
error?: string;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Gamify Node.js SDK Client
|
|
169
|
+
*
|
|
170
|
+
* Use this client for server-side event tracking with your secret API key.
|
|
171
|
+
* This client can send all event types including financial events like purchases.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* ```typescript
|
|
175
|
+
* import { GamifyClient } from '@gamifyio/node';
|
|
176
|
+
*
|
|
177
|
+
* const client = new GamifyClient({
|
|
178
|
+
* secretKey: 'sk_live_your_key_here',
|
|
179
|
+
* });
|
|
180
|
+
*
|
|
181
|
+
* // Track a purchase
|
|
182
|
+
* await client.purchase({
|
|
183
|
+
* userId: 'user_123',
|
|
184
|
+
* orderId: 'order_456',
|
|
185
|
+
* amount: 9999, // $99.99 in cents
|
|
186
|
+
* currency: 'USD',
|
|
187
|
+
* });
|
|
188
|
+
* ```
|
|
189
|
+
*/
|
|
190
|
+
declare class GamifyClient {
|
|
191
|
+
private readonly secretKey;
|
|
192
|
+
private readonly baseUrl;
|
|
193
|
+
private readonly timeout;
|
|
194
|
+
private readonly retries;
|
|
195
|
+
constructor(config: GamifyConfig);
|
|
196
|
+
/**
|
|
197
|
+
* Track a custom event
|
|
198
|
+
*
|
|
199
|
+
* @example
|
|
200
|
+
* ```typescript
|
|
201
|
+
* await client.track({
|
|
202
|
+
* userId: 'user_123',
|
|
203
|
+
* event: 'subscription_renewed',
|
|
204
|
+
* properties: {
|
|
205
|
+
* plan: 'premium',
|
|
206
|
+
* amount: 2999,
|
|
207
|
+
* },
|
|
208
|
+
* });
|
|
209
|
+
* ```
|
|
210
|
+
*/
|
|
211
|
+
track(event: TrackEvent): Promise<ApiResponse>;
|
|
212
|
+
/**
|
|
213
|
+
* Track a purchase event
|
|
214
|
+
*
|
|
215
|
+
* This is a convenience method that sends a properly formatted purchase event.
|
|
216
|
+
* Purchase events are used for affiliate commission calculations.
|
|
217
|
+
*
|
|
218
|
+
* @example
|
|
219
|
+
* ```typescript
|
|
220
|
+
* await client.purchase({
|
|
221
|
+
* userId: 'user_123',
|
|
222
|
+
* orderId: 'order_456',
|
|
223
|
+
* amount: 9999, // $99.99 in cents
|
|
224
|
+
* currency: 'USD',
|
|
225
|
+
* items: [
|
|
226
|
+
* { productId: 'prod_1', name: 'Widget', unitPrice: 4999, quantity: 2 },
|
|
227
|
+
* ],
|
|
228
|
+
* });
|
|
229
|
+
* ```
|
|
230
|
+
*/
|
|
231
|
+
purchase(data: PurchaseEvent): Promise<ApiResponse>;
|
|
232
|
+
/**
|
|
233
|
+
* Identify a user with traits
|
|
234
|
+
*
|
|
235
|
+
* Updates user profile information for personalization and segmentation.
|
|
236
|
+
*
|
|
237
|
+
* @example
|
|
238
|
+
* ```typescript
|
|
239
|
+
* await client.identify('user_123', {
|
|
240
|
+
* email: 'john@example.com',
|
|
241
|
+
* name: 'John Doe',
|
|
242
|
+
* plan: 'premium',
|
|
243
|
+
* signupDate: '2024-01-15',
|
|
244
|
+
* });
|
|
245
|
+
* ```
|
|
246
|
+
*/
|
|
247
|
+
identify(userId: string, traits: UserTraits): Promise<ApiResponse>;
|
|
248
|
+
/**
|
|
249
|
+
* Track a successful referral
|
|
250
|
+
*
|
|
251
|
+
* Call this when a referred user completes a qualifying action
|
|
252
|
+
* (e.g., makes their first purchase, completes signup).
|
|
253
|
+
*
|
|
254
|
+
* @example
|
|
255
|
+
* ```typescript
|
|
256
|
+
* await client.referralSuccess({
|
|
257
|
+
* referredUserId: 'new_user_123',
|
|
258
|
+
* referralCode: 'FRIEND20',
|
|
259
|
+
* });
|
|
260
|
+
* ```
|
|
261
|
+
*/
|
|
262
|
+
referralSuccess(data: ReferralEvent): Promise<ApiResponse>;
|
|
263
|
+
/**
|
|
264
|
+
* Track checkout completion
|
|
265
|
+
*
|
|
266
|
+
* Alternative event name for purchase tracking.
|
|
267
|
+
* Use either purchase() or checkoutComplete(), not both for the same transaction.
|
|
268
|
+
*/
|
|
269
|
+
checkoutComplete(data: PurchaseEvent): Promise<ApiResponse>;
|
|
270
|
+
/**
|
|
271
|
+
* Make an HTTP request to the Gamify API
|
|
272
|
+
*/
|
|
273
|
+
private request;
|
|
274
|
+
private sleep;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
export { type ApiResponse, GamifyClient, type GamifyConfig, type PurchaseEvent, type PurchaseItem, type ReferralEvent, type TrackEvent, type UserTraits };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var l="https://api.gamify.io";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 p=`${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(p,{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 u=JSON.parse(a);o=u.message||u.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
|
+
export{c as GamifyClient};//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +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"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@gamifyio/node",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Server-side Node.js SDK for Gamify - secure event tracking with secret keys",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist"
|
|
23
|
+
],
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "tsup",
|
|
26
|
+
"dev": "tsup --watch",
|
|
27
|
+
"check-types": "tsc --noEmit",
|
|
28
|
+
"lint": "eslint src --max-warnings 0",
|
|
29
|
+
"clean": "rm -rf dist"
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@repo/typescript-config": "*",
|
|
34
|
+
"@types/node": "^20.0.0",
|
|
35
|
+
"tsup": "^8.0.0",
|
|
36
|
+
"typescript": "5.9.2"
|
|
37
|
+
},
|
|
38
|
+
"engines": {
|
|
39
|
+
"node": ">=18.0.0"
|
|
40
|
+
},
|
|
41
|
+
"sideEffects": false,
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"keywords": [
|
|
44
|
+
"analytics",
|
|
45
|
+
"tracking",
|
|
46
|
+
"events",
|
|
47
|
+
"sdk",
|
|
48
|
+
"server",
|
|
49
|
+
"nodejs"
|
|
50
|
+
]
|
|
51
|
+
}
|