@soulbatical/tetra-core 0.1.7 → 0.1.9

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.

Potentially problematic release.


This version of @soulbatical/tetra-core might be problematic. Click here for more details.

Files changed (37) hide show
  1. package/dist/index.d.ts +9 -0
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +9 -0
  4. package/dist/index.js.map +1 -1
  5. package/dist/middleware/entitlementsMiddleware.d.ts +142 -0
  6. package/dist/middleware/entitlementsMiddleware.d.ts.map +1 -0
  7. package/dist/middleware/entitlementsMiddleware.js +246 -0
  8. package/dist/middleware/entitlementsMiddleware.js.map +1 -0
  9. package/dist/middleware/permissionsMiddleware.d.ts +181 -0
  10. package/dist/middleware/permissionsMiddleware.d.ts.map +1 -0
  11. package/dist/middleware/permissionsMiddleware.js +237 -0
  12. package/dist/middleware/permissionsMiddleware.js.map +1 -0
  13. package/dist/shared/affiliate/AffiliateAttributionService.d.ts +47 -0
  14. package/dist/shared/affiliate/AffiliateAttributionService.d.ts.map +1 -0
  15. package/dist/shared/affiliate/AffiliateAttributionService.js +308 -0
  16. package/dist/shared/affiliate/AffiliateAttributionService.js.map +1 -0
  17. package/dist/shared/affiliate/AffiliateClickService.d.ts +35 -0
  18. package/dist/shared/affiliate/AffiliateClickService.d.ts.map +1 -0
  19. package/dist/shared/affiliate/AffiliateClickService.js +87 -0
  20. package/dist/shared/affiliate/AffiliateClickService.js.map +1 -0
  21. package/dist/shared/affiliate/affiliateFeatureConfig.d.ts +11 -0
  22. package/dist/shared/affiliate/affiliateFeatureConfig.d.ts.map +1 -0
  23. package/dist/shared/affiliate/affiliateFeatureConfig.js +242 -0
  24. package/dist/shared/affiliate/affiliateFeatureConfig.js.map +1 -0
  25. package/dist/shared/affiliate/index.d.ts +11 -0
  26. package/dist/shared/affiliate/index.d.ts.map +1 -0
  27. package/dist/shared/affiliate/index.js +13 -0
  28. package/dist/shared/affiliate/index.js.map +1 -0
  29. package/dist/shared/affiliate/routes.d.ts +87 -0
  30. package/dist/shared/affiliate/routes.d.ts.map +1 -0
  31. package/dist/shared/affiliate/routes.js +404 -0
  32. package/dist/shared/affiliate/routes.js.map +1 -0
  33. package/dist/shared/affiliate/types.d.ts +170 -0
  34. package/dist/shared/affiliate/types.d.ts.map +1 -0
  35. package/dist/shared/affiliate/types.js +11 -0
  36. package/dist/shared/affiliate/types.js.map +1 -0
  37. package/package.json +1 -1
@@ -0,0 +1,404 @@
1
+ import { AffiliateClickService } from './AffiliateClickService.js';
2
+ import { createLogger } from '../../utils/logger.js';
3
+ import { addQueryRoutes } from '../factories/QueryRouteFactory.js';
4
+ const logger = createLogger('http:routes:affiliates');
5
+ /**
6
+ * Add public affiliate routes (no auth required).
7
+ *
8
+ * Routes:
9
+ * - POST /click — Register affiliate click
10
+ * - POST /apply — Submit affiliate application
11
+ */
12
+ export function addAffiliatePublicRoutes(router, options) {
13
+ const affiliateConfig = {
14
+ defaultCommissionPercentage: 30,
15
+ cookieDurationDays: 90,
16
+ tiers: [
17
+ { name: 'starter', minSales: 0, commissionPercentage: 30 },
18
+ { name: 'active', minSales: 10, commissionPercentage: 35 },
19
+ ],
20
+ ...options.config,
21
+ };
22
+ // POST /click — Register affiliate click
23
+ router.post('/click', async (req, res, next) => {
24
+ try {
25
+ const { affiliate_ref: affiliateRef, affiliate_source: affiliateSource, landing_page: landingPage, referrer } = req.body;
26
+ if (!affiliateRef || !affiliateSource) {
27
+ res.status(400).json({
28
+ error: 'Missing required fields',
29
+ required: ['affiliate_ref', 'affiliate_source'],
30
+ });
31
+ return;
32
+ }
33
+ if (affiliateSource !== 'internal') {
34
+ res.status(400).json({
35
+ error: 'Invalid affiliate_source',
36
+ valid: ['internal'],
37
+ });
38
+ return;
39
+ }
40
+ const supabase = options.getSystemDB();
41
+ const clickService = new AffiliateClickService(supabase);
42
+ // Resolve affiliate by referral code
43
+ let affiliateId = null;
44
+ let organizationId = null;
45
+ const { data: affiliate } = await supabase
46
+ .from('affiliates')
47
+ .select('id, organization_id')
48
+ .eq('referral_code', affiliateRef)
49
+ .eq('status', 'active')
50
+ .single();
51
+ if (affiliate) {
52
+ affiliateId = affiliate.id;
53
+ organizationId = affiliate.organization_id;
54
+ }
55
+ const clickId = await clickService.registerClick({
56
+ affiliate_id: affiliateId,
57
+ organization_id: organizationId,
58
+ affiliate_source: affiliateSource,
59
+ visitor_ip: req.ip || null,
60
+ user_agent: req.headers['user-agent'] || null,
61
+ referrer_url: referrer || null,
62
+ landing_page: landingPage || null,
63
+ });
64
+ // Increment click count
65
+ if (affiliateId) {
66
+ await clickService.incrementClickCount(affiliateId);
67
+ }
68
+ res.status(201).json({
69
+ success: true,
70
+ click_id: clickId,
71
+ message: 'Click registered successfully',
72
+ });
73
+ }
74
+ catch (error) {
75
+ logger.error('Error registering click', error);
76
+ next(error);
77
+ }
78
+ });
79
+ // POST /apply — Submit affiliate application
80
+ router.post('/apply', async (req, res, next) => {
81
+ try {
82
+ const { contact_name: contactName, email, phone, company_name: companyName, website, address, postal_code: postalCode, city, country, vat_number: vatNumber, kvk_number: kvkNumber, motivation, audience_size: audienceSize, preferred_code: preferredCode, } = req.body;
83
+ if (!contactName || !email) {
84
+ res.status(400).json({
85
+ error: 'Missing required fields',
86
+ required: ['contact_name', 'email'],
87
+ });
88
+ return;
89
+ }
90
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
91
+ if (!emailRegex.test(email)) {
92
+ res.status(400).json({ error: 'Invalid email format' });
93
+ return;
94
+ }
95
+ const supabase = options.getSystemDB();
96
+ // Check if email already exists
97
+ const { data: existing } = await supabase
98
+ .from('affiliates')
99
+ .select('id, status')
100
+ .eq('email', email)
101
+ .maybeSingle();
102
+ if (existing) {
103
+ const message = existing.status === 'pending'
104
+ ? 'Application already submitted and pending review'
105
+ : 'An affiliate account with this email already exists';
106
+ res.status(409).json({ error: 'Email already registered', message, status: existing.status });
107
+ return;
108
+ }
109
+ // Generate referral code
110
+ let referralCode = preferredCode?.toLowerCase().replace(/[^a-z0-9]/g, '');
111
+ if (!referralCode || referralCode.length < 3) {
112
+ referralCode = contactName.toLowerCase().replace(/[^a-z0-9]/g, '').substring(0, 10);
113
+ }
114
+ // Ensure uniqueness
115
+ let finalReferralCode = referralCode;
116
+ let counter = 1;
117
+ let isUnique = false;
118
+ while (!isUnique && counter < 100) {
119
+ const { data: existingCode } = await supabase
120
+ .from('affiliates')
121
+ .select('id')
122
+ .eq('referral_code', finalReferralCode)
123
+ .maybeSingle();
124
+ if (!existingCode) {
125
+ isUnique = true;
126
+ }
127
+ else {
128
+ finalReferralCode = `${referralCode}${counter}`;
129
+ counter++;
130
+ }
131
+ }
132
+ if (!isUnique) {
133
+ res.status(500).json({ error: 'Could not generate unique referral code' });
134
+ return;
135
+ }
136
+ // Resolve organization ID
137
+ let organizationId = null;
138
+ if (options.resolveOrganizationId) {
139
+ organizationId = await options.resolveOrganizationId(req);
140
+ }
141
+ else {
142
+ // Fallback: first organization in database
143
+ const { data: org } = await supabase
144
+ .from('organizations')
145
+ .select('id')
146
+ .limit(1)
147
+ .maybeSingle();
148
+ organizationId = org?.id || null;
149
+ }
150
+ if (!organizationId) {
151
+ res.status(500).json({ error: 'Could not resolve organization' });
152
+ return;
153
+ }
154
+ // Create affiliate application
155
+ const { data: affiliate, error: insertError } = await supabase
156
+ .from('affiliates')
157
+ .insert({
158
+ organization_id: organizationId,
159
+ email,
160
+ contact_name: contactName,
161
+ phone: phone || null,
162
+ company_name: companyName || null,
163
+ website: website || null,
164
+ address: address || null,
165
+ postal_code: postalCode || null,
166
+ city: city || null,
167
+ country: country || 'NL',
168
+ vat_number: vatNumber || null,
169
+ kvk_number: kvkNumber || null,
170
+ referral_code: finalReferralCode,
171
+ status: 'pending',
172
+ tier: affiliateConfig.tiers[0]?.name || 'starter',
173
+ commission_percentage: affiliateConfig.defaultCommissionPercentage,
174
+ cookie_duration_days: affiliateConfig.cookieDurationDays,
175
+ notes: motivation ? `Motivation: ${motivation}\nAudience size: ${audienceSize || 'Not specified'}` : null,
176
+ })
177
+ .select()
178
+ .single();
179
+ if (insertError) {
180
+ logger.error('Failed to create affiliate application', { error: insertError });
181
+ throw insertError;
182
+ }
183
+ res.status(201).json({
184
+ success: true,
185
+ message: 'Application submitted successfully',
186
+ data: {
187
+ id: affiliate.id,
188
+ referral_code: finalReferralCode,
189
+ status: 'pending',
190
+ message: 'Your application is pending review. You will receive an email once approved.',
191
+ },
192
+ });
193
+ }
194
+ catch (error) {
195
+ logger.error('Error processing affiliate application', error);
196
+ next(error);
197
+ }
198
+ });
199
+ }
200
+ /**
201
+ * Add user affiliate routes (authenticated user).
202
+ *
203
+ * Routes:
204
+ * - GET /dashboard — Dashboard stats
205
+ * - GET /profile — Affiliate profile
206
+ * - GET /commissions — Commission history
207
+ */
208
+ export function addAffiliateUserRoutes(router, options) {
209
+ const tiers = options.tiers || [
210
+ { name: 'starter', minSales: 0, commissionPercentage: 30 },
211
+ { name: 'active', minSales: 10, commissionPercentage: 35 },
212
+ ];
213
+ // GET /dashboard
214
+ router.get('/dashboard', async (req, res, next) => {
215
+ try {
216
+ if (!req.user) {
217
+ res.status(401).json({ error: 'Authentication required' });
218
+ return;
219
+ }
220
+ const userId = req.user.id;
221
+ const supabase = await options.getUserDB(req);
222
+ const { data: affiliate, error: affiliateError } = await supabase
223
+ .from('affiliates')
224
+ .select('*')
225
+ .eq('user_id', userId)
226
+ .eq('status', 'active')
227
+ .single();
228
+ if (affiliateError || !affiliate) {
229
+ res.status(404).json({
230
+ error: 'Affiliate account not found or not active',
231
+ message: 'Please apply to become an affiliate first',
232
+ });
233
+ return;
234
+ }
235
+ const conversionRate = affiliate.total_clicks > 0
236
+ ? ((affiliate.total_sales / affiliate.total_clicks) * 100)
237
+ : 0;
238
+ const averageOrderValue = affiliate.total_sales > 0
239
+ ? (affiliate.total_revenue / affiliate.total_sales)
240
+ : 0;
241
+ const pendingCommission = affiliate.total_commission_earned - affiliate.total_commission_paid;
242
+ const tierProgress = calculateTierProgress(tiers, affiliate.tier, affiliate.total_sales);
243
+ const { data: recentCommissions } = await supabase
244
+ .from('affiliate_commissions')
245
+ .select('id, order_id, product_name, order_amount_excl_vat, commission_amount, commission_percentage, status, created_at')
246
+ .eq('affiliate_id', affiliate.id)
247
+ .order('created_at', { ascending: false })
248
+ .limit(10);
249
+ res.json({
250
+ success: true,
251
+ data: {
252
+ affiliate: {
253
+ id: affiliate.id,
254
+ referral_code: affiliate.referral_code,
255
+ tier: affiliate.tier,
256
+ commission_percentage: affiliate.commission_percentage,
257
+ status: affiliate.status,
258
+ active_since: affiliate.active_since,
259
+ contact_name: affiliate.contact_name,
260
+ email: affiliate.email,
261
+ },
262
+ stats: {
263
+ total_clicks: affiliate.total_clicks,
264
+ total_sales: affiliate.total_sales,
265
+ total_revenue: parseFloat(affiliate.total_revenue),
266
+ conversion_rate: parseFloat(conversionRate.toFixed(2)),
267
+ average_order_value: parseFloat(averageOrderValue.toFixed(2)),
268
+ },
269
+ commission: {
270
+ total_earned: parseFloat(affiliate.total_commission_earned),
271
+ total_paid: parseFloat(affiliate.total_commission_paid),
272
+ pending: parseFloat(pendingCommission.toFixed(2)),
273
+ },
274
+ tier_progress: tierProgress,
275
+ recent_commissions: recentCommissions || [],
276
+ },
277
+ });
278
+ }
279
+ catch (error) {
280
+ logger.error('Error fetching dashboard', error);
281
+ next(error);
282
+ }
283
+ });
284
+ // GET /profile
285
+ router.get('/profile', async (req, res, next) => {
286
+ try {
287
+ if (!req.user) {
288
+ res.status(401).json({ error: 'Authentication required' });
289
+ return;
290
+ }
291
+ const supabase = await options.getUserDB(req);
292
+ const { data: affiliate, error } = await supabase
293
+ .from('affiliates')
294
+ .select('*')
295
+ .eq('user_id', req.user.id)
296
+ .single();
297
+ if (error || !affiliate) {
298
+ res.status(404).json({ error: 'Affiliate account not found' });
299
+ return;
300
+ }
301
+ res.json({ success: true, data: affiliate });
302
+ }
303
+ catch (error) {
304
+ logger.error('Error fetching profile', error);
305
+ next(error);
306
+ }
307
+ });
308
+ // GET /commissions
309
+ router.get('/commissions', async (req, res, next) => {
310
+ try {
311
+ if (!req.user) {
312
+ res.status(401).json({ error: 'Authentication required' });
313
+ return;
314
+ }
315
+ const supabase = await options.getUserDB(req);
316
+ const { data: affiliate, error: affiliateError } = await supabase
317
+ .from('affiliates')
318
+ .select('id')
319
+ .eq('user_id', req.user.id)
320
+ .single();
321
+ if (affiliateError || !affiliate) {
322
+ res.status(404).json({ error: 'Affiliate account not found' });
323
+ return;
324
+ }
325
+ const { data: commissions, error } = await supabase
326
+ .from('affiliate_commissions')
327
+ .select('*')
328
+ .eq('affiliate_id', affiliate.id)
329
+ .order('created_at', { ascending: false });
330
+ if (error)
331
+ throw error;
332
+ res.json({ success: true, data: commissions || [] });
333
+ }
334
+ catch (error) {
335
+ logger.error('Error fetching commissions', error);
336
+ next(error);
337
+ }
338
+ });
339
+ }
340
+ /**
341
+ * Add admin affiliate routes (requires admin auth).
342
+ *
343
+ * Routes:
344
+ * - POST / — Create affiliate
345
+ * - PUT /:id — Update affiliate
346
+ * - DELETE /:id — Delete affiliate
347
+ * - GET /filters — Filter configurations
348
+ * - GET /by-ids — Get by IDs
349
+ * - GET /counts — Get counts
350
+ * - GET / — List affiliates
351
+ * - GET /:id — Get single affiliate
352
+ */
353
+ export function addAffiliateAdminRoutes(router, options) {
354
+ // CRUD routes first (must be before query routes to avoid /:id collision)
355
+ const crud = options.crudController;
356
+ router.post('/', (req, res) => crud.create(req, res));
357
+ router.put('/:id', (req, res) => crud.update(req, res));
358
+ router.delete('/:id', (req, res) => crud.delete(req, res));
359
+ // Standard query routes
360
+ addQueryRoutes(router, {
361
+ featureConfig: options.featureConfig,
362
+ controller: options.queryController,
363
+ filterController: options.filterController,
364
+ maxLimit: 1000,
365
+ defaultLimit: 20,
366
+ allowSearch: true,
367
+ allowedFields: [
368
+ 'id', 'email', 'contact_name', 'company_name', 'referral_code',
369
+ 'status', 'tier', 'commission_percentage', 'total_sales', 'total_revenue',
370
+ 'total_commission_earned', 'created_at', 'organization_id',
371
+ ],
372
+ });
373
+ }
374
+ // ─── Tier Progress Helper ─────────────────────────────────────
375
+ function calculateTierProgress(tiers, currentTier, totalSales) {
376
+ const sortedTiers = [...tiers].sort((a, b) => a.minSales - b.minSales);
377
+ const currentTierInfo = sortedTiers.find(t => t.name === currentTier) || sortedTiers[0];
378
+ const currentIndex = sortedTiers.indexOf(currentTierInfo);
379
+ const nextTierInfo = currentIndex < sortedTiers.length - 1 ? sortedTiers[currentIndex + 1] : null;
380
+ if (!nextTierInfo) {
381
+ return {
382
+ current_tier: currentTier,
383
+ current_commission: currentTierInfo.commissionPercentage,
384
+ current_sales: totalSales,
385
+ is_max_tier: true,
386
+ };
387
+ }
388
+ const salesInCurrentTier = totalSales - currentTierInfo.minSales;
389
+ const salesNeededForNextTier = nextTierInfo.minSales - currentTierInfo.minSales;
390
+ const progressPercentage = (salesInCurrentTier / salesNeededForNextTier) * 100;
391
+ const salesUntilNext = nextTierInfo.minSales - totalSales;
392
+ return {
393
+ current_tier: currentTier,
394
+ current_commission: currentTierInfo.commissionPercentage,
395
+ current_sales: totalSales,
396
+ next_tier: nextTierInfo.name,
397
+ next_commission: nextTierInfo.commissionPercentage,
398
+ sales_needed_for_next: salesNeededForNextTier,
399
+ sales_until_next: Math.max(0, salesUntilNext),
400
+ progress_percentage: parseFloat(Math.min(100, progressPercentage).toFixed(1)),
401
+ is_max_tier: false,
402
+ };
403
+ }
404
+ //# sourceMappingURL=routes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/shared/affiliate/routes.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ /**
2
+ * Affiliate Module — Types & Interfaces
3
+ *
4
+ * Generic affiliate types for internal referral systems.
5
+ * No external platform types (ShareASale, TradeTracker, Impact) —
6
+ * those are project-specific extensions.
7
+ *
8
+ * @module @soulbatical/tetra-core/affiliate
9
+ */
10
+ export interface AffiliateConfig {
11
+ /** Default commission percentage for new affiliates (e.g., 30) */
12
+ defaultCommissionPercentage: number;
13
+ /** Cookie duration in days (e.g., 90) */
14
+ cookieDurationDays: number;
15
+ /** Tier configuration for auto-upgrades */
16
+ tiers: AffiliateTierConfig[];
17
+ /** Custom referral code generator (default: firstname-XXXX) */
18
+ referralCodeGenerator?: (name: string) => string;
19
+ }
20
+ export interface AffiliateTierConfig {
21
+ /** Tier name (e.g., 'starter', 'active') */
22
+ name: string;
23
+ /** Minimum total sales to qualify for this tier */
24
+ minSales: number;
25
+ /** Commission percentage for this tier */
26
+ commissionPercentage: number;
27
+ }
28
+ export interface AffiliateAttribution {
29
+ affiliate_id: string | null;
30
+ source: 'internal';
31
+ attribution_type: 'voucher' | 'url' | 'cookie';
32
+ reference: string;
33
+ }
34
+ export interface AffiliateOrder {
35
+ id: string;
36
+ organization_id: string;
37
+ user_id?: string;
38
+ total: number;
39
+ total_excl_vat: number;
40
+ voucher_code?: string;
41
+ created_at: string;
42
+ }
43
+ export interface Affiliate {
44
+ id: string;
45
+ organization_id: string;
46
+ user_id?: string | null;
47
+ email: string;
48
+ contact_name: string;
49
+ company_name?: string | null;
50
+ phone?: string | null;
51
+ address?: string | null;
52
+ postal_code?: string | null;
53
+ city?: string | null;
54
+ country?: string | null;
55
+ vat_number?: string | null;
56
+ kvk_number?: string | null;
57
+ website?: string | null;
58
+ status: 'pending' | 'active' | 'inactive' | 'rejected';
59
+ referral_code: string;
60
+ tier: string;
61
+ commission_percentage: number;
62
+ cookie_duration_days: number;
63
+ total_clicks: number;
64
+ total_sales: number;
65
+ total_revenue: number;
66
+ total_commission_earned: number;
67
+ total_commission_paid: number;
68
+ active_since?: string | null;
69
+ last_sale_at?: string | null;
70
+ notes?: string | null;
71
+ created_at: string;
72
+ updated_at: string;
73
+ }
74
+ export interface AffiliateCommission {
75
+ id: string;
76
+ organization_id: string;
77
+ affiliate_id: string;
78
+ order_id: string;
79
+ affiliate_source: string;
80
+ external_click_ref?: string | null;
81
+ product_name: string;
82
+ order_amount_excl_vat: number;
83
+ commission_percentage: number;
84
+ commission_amount: number;
85
+ status: 'pending' | 'approved' | 'paid' | 'cancelled' | 'refunded';
86
+ approved_at?: string | null;
87
+ approved_by?: string | null;
88
+ paid_at?: string | null;
89
+ payment_id?: string | null;
90
+ notes?: string | null;
91
+ created_at: string;
92
+ updated_at: string;
93
+ }
94
+ export interface AffiliateClick {
95
+ id: string;
96
+ organization_id?: string | null;
97
+ affiliate_id?: string | null;
98
+ visitor_ip?: string | null;
99
+ visitor_country?: string | null;
100
+ user_agent?: string | null;
101
+ referrer_url?: string | null;
102
+ landing_page?: string | null;
103
+ affiliate_source: string;
104
+ external_click_ref?: string | null;
105
+ converted: boolean;
106
+ order_id?: string | null;
107
+ conversion_time_hours?: number | null;
108
+ clicked_at: string;
109
+ }
110
+ export interface AffiliatePayment {
111
+ id: string;
112
+ organization_id: string;
113
+ affiliate_id: string;
114
+ payment_amount: number;
115
+ payment_date: string;
116
+ payment_method?: string | null;
117
+ payment_reference?: string | null;
118
+ commission_ids: string[];
119
+ notes?: string | null;
120
+ created_at: string;
121
+ }
122
+ export interface AffiliateTierHistory {
123
+ id: string;
124
+ affiliate_id: string;
125
+ old_tier: string;
126
+ new_tier: string;
127
+ old_commission_percentage: number;
128
+ new_commission_percentage: number;
129
+ reason?: string | null;
130
+ triggered_by_sale_count?: number | null;
131
+ changed_at: string;
132
+ }
133
+ export interface AffiliateFilters {
134
+ status?: string;
135
+ tier?: string;
136
+ search?: string;
137
+ has_user?: string;
138
+ time_period?: string;
139
+ }
140
+ export interface AffiliateDashboardStats {
141
+ total_clicks: number;
142
+ total_sales: number;
143
+ total_revenue: number;
144
+ conversion_rate: number;
145
+ average_order_value: number;
146
+ }
147
+ export interface AffiliateDashboardCommission {
148
+ total_earned: number;
149
+ total_paid: number;
150
+ pending: number;
151
+ }
152
+ export interface AffiliateTierProgress {
153
+ current_tier: string;
154
+ current_commission: number;
155
+ current_sales: number;
156
+ next_tier?: string;
157
+ next_commission?: number;
158
+ sales_needed_for_next?: number;
159
+ sales_until_next?: number;
160
+ progress_percentage?: number;
161
+ is_max_tier: boolean;
162
+ }
163
+ export interface AffiliateDashboard {
164
+ affiliate: Pick<Affiliate, 'id' | 'referral_code' | 'tier' | 'commission_percentage' | 'status' | 'active_since' | 'contact_name' | 'email'>;
165
+ stats: AffiliateDashboardStats;
166
+ commission: AffiliateDashboardCommission;
167
+ tier_progress: AffiliateTierProgress;
168
+ recent_commissions: AffiliateCommission[];
169
+ }
170
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/shared/affiliate/types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Affiliate Module — Types & Interfaces
3
+ *
4
+ * Generic affiliate types for internal referral systems.
5
+ * No external platform types (ShareASale, TradeTracker, Impact) —
6
+ * those are project-specific extensions.
7
+ *
8
+ * @module @soulbatical/tetra-core/affiliate
9
+ */
10
+ export {};
11
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/shared/affiliate/types.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@soulbatical/tetra-core",
3
- "version": "0.1.7",
3
+ "version": "0.1.9",
4
4
  "publishConfig": {
5
5
  "access": "restricted"
6
6
  },