@soulbatical/tetra-core 0.1.8 → 0.1.10
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/core/adminDb.d.ts +12 -3
- package/dist/core/adminDb.d.ts.map +1 -1
- package/dist/core/adminDb.js +12 -3
- package/dist/core/adminDb.js.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +5 -0
- package/dist/index.js.map +1 -1
- package/dist/shared/affiliate/AffiliateAttributionService.d.ts +47 -0
- package/dist/shared/affiliate/AffiliateAttributionService.d.ts.map +1 -0
- package/dist/shared/affiliate/AffiliateAttributionService.js +308 -0
- package/dist/shared/affiliate/AffiliateAttributionService.js.map +1 -0
- package/dist/shared/affiliate/AffiliateClickService.d.ts +35 -0
- package/dist/shared/affiliate/AffiliateClickService.d.ts.map +1 -0
- package/dist/shared/affiliate/AffiliateClickService.js +87 -0
- package/dist/shared/affiliate/AffiliateClickService.js.map +1 -0
- package/dist/shared/affiliate/affiliateFeatureConfig.d.ts +11 -0
- package/dist/shared/affiliate/affiliateFeatureConfig.d.ts.map +1 -0
- package/dist/shared/affiliate/affiliateFeatureConfig.js +242 -0
- package/dist/shared/affiliate/affiliateFeatureConfig.js.map +1 -0
- package/dist/shared/affiliate/index.d.ts +11 -0
- package/dist/shared/affiliate/index.d.ts.map +1 -0
- package/dist/shared/affiliate/index.js +13 -0
- package/dist/shared/affiliate/index.js.map +1 -0
- package/dist/shared/affiliate/routes.d.ts +87 -0
- package/dist/shared/affiliate/routes.d.ts.map +1 -0
- package/dist/shared/affiliate/routes.js +404 -0
- package/dist/shared/affiliate/routes.js.map +1 -0
- package/dist/shared/affiliate/types.d.ts +170 -0
- package/dist/shared/affiliate/types.d.ts.map +1 -0
- package/dist/shared/affiliate/types.js +11 -0
- package/dist/shared/affiliate/types.js.map +1 -0
- package/package.json +5 -3
- package/src/shared/affiliate/migrations/001_create_affiliates.sql +49 -0
- package/src/shared/affiliate/migrations/002_create_affiliate_commissions.sql +31 -0
- package/src/shared/affiliate/migrations/003_create_affiliate_clicks.sql +26 -0
- package/src/shared/affiliate/migrations/004_create_affiliate_payments.sql +34 -0
- package/src/shared/affiliate/migrations/005_create_affiliate_tier_history.sql +19 -0
- package/src/shared/affiliate/migrations/006_create_affiliate_rpc_functions.sql +209 -0
- package/src/shared/affiliate/migrations/007_create_affiliate_rls_policies.sql +123 -0
- package/src/shared/auth/migrations/000_auth_org_helpers.sql +71 -0
package/dist/core/adminDb.d.ts
CHANGED
|
@@ -1,8 +1,17 @@
|
|
|
1
1
|
import { AuthenticatedRequest } from '../middleware/authMiddleware.js';
|
|
2
2
|
/**
|
|
3
|
-
* Admin database helper - for organization admin operations
|
|
4
|
-
*
|
|
5
|
-
* RLS policies
|
|
3
|
+
* Admin database helper - for organization admin operations.
|
|
4
|
+
* Creates a Supabase client authenticated with the user's JWT token,
|
|
5
|
+
* so RLS policies are enforced using the user's identity.
|
|
6
|
+
*
|
|
7
|
+
* IMPORTANT — RLS Organization Filtering:
|
|
8
|
+
* This client passes the user's JWT to Supabase. RLS policies that use
|
|
9
|
+
* auth_org_id() will filter data by organization. The auth_org_id()
|
|
10
|
+
* function MUST read from users_public.active_organization_id (database),
|
|
11
|
+
* NOT from JWT app_metadata claims. JWT claims are set at login time and
|
|
12
|
+
* become stale when users switch organizations.
|
|
13
|
+
*
|
|
14
|
+
* See: packages/core/src/shared/auth/migrations/000_auth_org_helpers.sql
|
|
6
15
|
*
|
|
7
16
|
* @example
|
|
8
17
|
* ```typescript
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminDb.d.ts","sourceRoot":"","sources":["../../src/core/adminDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAMvE
|
|
1
|
+
{"version":3,"file":"adminDb.d.ts","sourceRoot":"","sources":["../../src/core/adminDb.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,MAAM,iCAAiC,CAAC;AAMvE;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,oBAAoB,8FA0BtD"}
|
package/dist/core/adminDb.js
CHANGED
|
@@ -2,9 +2,18 @@ import { SupabaseUserClient } from './SupabaseUserClient.js';
|
|
|
2
2
|
import { createLogger } from '../utils/logger.js';
|
|
3
3
|
const logger = createLogger('security:db:admin');
|
|
4
4
|
/**
|
|
5
|
-
* Admin database helper - for organization admin operations
|
|
6
|
-
*
|
|
7
|
-
* RLS policies
|
|
5
|
+
* Admin database helper - for organization admin operations.
|
|
6
|
+
* Creates a Supabase client authenticated with the user's JWT token,
|
|
7
|
+
* so RLS policies are enforced using the user's identity.
|
|
8
|
+
*
|
|
9
|
+
* IMPORTANT — RLS Organization Filtering:
|
|
10
|
+
* This client passes the user's JWT to Supabase. RLS policies that use
|
|
11
|
+
* auth_org_id() will filter data by organization. The auth_org_id()
|
|
12
|
+
* function MUST read from users_public.active_organization_id (database),
|
|
13
|
+
* NOT from JWT app_metadata claims. JWT claims are set at login time and
|
|
14
|
+
* become stale when users switch organizations.
|
|
15
|
+
*
|
|
16
|
+
* See: packages/core/src/shared/auth/migrations/000_auth_org_helpers.sql
|
|
8
17
|
*
|
|
9
18
|
* @example
|
|
10
19
|
* ```typescript
|
package/dist/core/adminDb.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adminDb.js","sourceRoot":"","sources":["../../src/core/adminDb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAEjD
|
|
1
|
+
{"version":3,"file":"adminDb.js","sourceRoot":"","sources":["../../src/core/adminDb.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAC7D,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,MAAM,MAAM,GAAG,YAAY,CAAC,mBAAmB,CAAC,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,GAAyB;IACrD,IAAI,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC;QACnB,0EAA0E;QAC1E,MAAM,IAAI,KAAK,CACb,0CAA0C;YAC1C,wEAAwE;YACxE,yDAAyD,CAC1D,CAAC;IACJ,CAAC;IAED,sEAAsE;IACtE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,cAAc,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,aAAa,EAAE,CAAC;QAC1D,MAAM,CAAC,KAAK,CAAC,kDAAkD,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/E,4EAA4E;QAC5E,MAAM,IAAI,KAAK,CACb,qCAAqC;YACrC,sFAAsF;YACtF,mEAAmE,CACpE,CAAC;IACJ,CAAC;IAED,gEAAgE;IAChE,MAAM,CAAC,KAAK,CAAC,+BAA+B,GAAG,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,CAAC,IAAI,CAAC,cAAc,IAAI,YAAY,EAAE,CAAC,CAAC;IAE1G,8DAA8D;IAC9D,OAAO,kBAAkB,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;AACzD,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -78,6 +78,11 @@ export { userDB } from './core/userDb.js';
|
|
|
78
78
|
export { superadminDB } from './core/superadminDb.js';
|
|
79
79
|
export { webhookDB } from './core/webhookDb.js';
|
|
80
80
|
export { SupabaseUserClient } from './core/SupabaseUserClient.js';
|
|
81
|
+
export { AffiliateAttributionService } from './shared/affiliate/AffiliateAttributionService.js';
|
|
82
|
+
export { AffiliateClickService } from './shared/affiliate/AffiliateClickService.js';
|
|
83
|
+
export { defaultAffiliateFeatureConfig } from './shared/affiliate/affiliateFeatureConfig.js';
|
|
84
|
+
export { addAffiliateAdminRoutes, addAffiliateUserRoutes, addAffiliatePublicRoutes } from './shared/affiliate/routes.js';
|
|
85
|
+
export type { AffiliateConfig, AffiliateTierConfig, AffiliateAttribution, AffiliateOrder, Affiliate, AffiliateCommission, AffiliateClick, AffiliatePayment, AffiliateTierHistory, AffiliateFilters, AffiliateDashboard, AffiliateDashboardStats, AffiliateDashboardCommission, AffiliateTierProgress } from './shared/affiliate/types.js';
|
|
81
86
|
export { createApp } from './core/createApp.js';
|
|
82
87
|
export type { CreateAppConfig } from './core/createApp.js';
|
|
83
88
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/index.js
CHANGED
|
@@ -74,6 +74,11 @@ export { userDB } from './core/userDb.js';
|
|
|
74
74
|
export { superadminDB } from './core/superadminDb.js';
|
|
75
75
|
export { webhookDB } from './core/webhookDb.js';
|
|
76
76
|
export { SupabaseUserClient } from './core/SupabaseUserClient.js';
|
|
77
|
+
// ─── Affiliate Module ──────────────────────────────────────
|
|
78
|
+
export { AffiliateAttributionService } from './shared/affiliate/AffiliateAttributionService.js';
|
|
79
|
+
export { AffiliateClickService } from './shared/affiliate/AffiliateClickService.js';
|
|
80
|
+
export { defaultAffiliateFeatureConfig } from './shared/affiliate/affiliateFeatureConfig.js';
|
|
81
|
+
export { addAffiliateAdminRoutes, addAffiliateUserRoutes, addAffiliatePublicRoutes } from './shared/affiliate/routes.js';
|
|
77
82
|
// ─── App Bootstrap ──────────────────────────────────────────
|
|
78
83
|
export { createApp } from './core/createApp.js';
|
|
79
84
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AffiliateAttributionService
|
|
3
|
+
*
|
|
4
|
+
* Generic affiliate attribution and commission engine.
|
|
5
|
+
* Internal referral only (voucher > URL > cookie).
|
|
6
|
+
* Config-driven tier upgrades.
|
|
7
|
+
*
|
|
8
|
+
* @module @soulbatical/tetra-core/affiliate
|
|
9
|
+
*/
|
|
10
|
+
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
11
|
+
import type { Request } from 'express';
|
|
12
|
+
import type { AffiliateAttribution, AffiliateConfig, AffiliateOrder } from './types.js';
|
|
13
|
+
export declare class AffiliateAttributionService {
|
|
14
|
+
private supabase;
|
|
15
|
+
private organizationId?;
|
|
16
|
+
private config;
|
|
17
|
+
constructor(supabase: SupabaseClient, config?: Partial<AffiliateConfig>, organizationId?: string);
|
|
18
|
+
/**
|
|
19
|
+
* Determine affiliate attribution for an order.
|
|
20
|
+
* Priority: Voucher > URL (?ref=) > Cookie
|
|
21
|
+
*/
|
|
22
|
+
determineAttribution(req: Request, voucherCode?: string): Promise<AffiliateAttribution | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Create a commission record for an affiliate sale.
|
|
25
|
+
* Updates affiliate stats and checks for tier upgrade.
|
|
26
|
+
*/
|
|
27
|
+
createCommission(order: AffiliateOrder, attribution: AffiliateAttribution): Promise<void>;
|
|
28
|
+
/**
|
|
29
|
+
* Generate a referral code for a new affiliate.
|
|
30
|
+
* Uses custom generator from config or default format.
|
|
31
|
+
*/
|
|
32
|
+
generateReferralCode(contactName: string): string;
|
|
33
|
+
private checkVoucherAttribution;
|
|
34
|
+
private checkUrlParameter;
|
|
35
|
+
private checkCookie;
|
|
36
|
+
/**
|
|
37
|
+
* Resolve an affiliate from referral code or ID.
|
|
38
|
+
*/
|
|
39
|
+
resolveAffiliate(reference: string, affiliateId: string | null): Promise<any>;
|
|
40
|
+
private updateAffiliateStats;
|
|
41
|
+
/**
|
|
42
|
+
* Check if affiliate qualifies for tier upgrade (config-driven).
|
|
43
|
+
*/
|
|
44
|
+
checkTierUpgrade(affiliateId: string, totalSales: number): Promise<void>;
|
|
45
|
+
private upgradeAffiliateTier;
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=AffiliateAttributionService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AffiliateAttributionService.d.ts","sourceRoot":"","sources":["../../../src/shared/affiliate/AffiliateAttributionService.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAGvC,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AA0BxF,qBAAa,2BAA2B;IACtC,OAAO,CAAC,QAAQ,CAAiB;IACjC,OAAO,CAAC,cAAc,CAAC,CAAS;IAChC,OAAO,CAAC,MAAM,CAAkB;gBAG9B,QAAQ,EAAE,cAAc,EACxB,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,EACjC,cAAc,CAAC,EAAE,MAAM;IASzB;;;OAGG;IACG,oBAAoB,CACxB,GAAG,EAAE,OAAO,EACZ,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,oBAAoB,GAAG,IAAI,CAAC;IAgCvC;;;OAGG;IACG,gBAAgB,CACpB,KAAK,EAAE,cAAc,EACrB,WAAW,EAAE,oBAAoB,GAChC,OAAO,CAAC,IAAI,CAAC;IA6DhB;;;OAGG;IACH,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM;YAOnC,uBAAuB;IAwBrC,OAAO,CAAC,iBAAiB;IAYzB,OAAO,CAAC,WAAW;IAiCnB;;OAEG;IACG,gBAAgB,CACpB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,GAAG,IAAI,GACzB,OAAO,CAAC,GAAG,CAAC;YAkCD,oBAAoB;IAgBlC;;OAEG;IACG,gBAAgB,CAAC,WAAW,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YA8ChE,oBAAoB;CAkDnC"}
|
|
@@ -0,0 +1,308 @@
|
|
|
1
|
+
import crypto from 'crypto';
|
|
2
|
+
import { createLogger } from '../../utils/logger.js';
|
|
3
|
+
const logger = createLogger('service:affiliate:attribution');
|
|
4
|
+
const DEFAULT_CONFIG = {
|
|
5
|
+
defaultCommissionPercentage: 30,
|
|
6
|
+
cookieDurationDays: 90,
|
|
7
|
+
tiers: [
|
|
8
|
+
{ name: 'starter', minSales: 0, commissionPercentage: 30 },
|
|
9
|
+
{ name: 'active', minSales: 10, commissionPercentage: 35 },
|
|
10
|
+
],
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* Generate a referral code from a contact name.
|
|
14
|
+
* Format: firstname-XXXX (e.g., 'monique-1234')
|
|
15
|
+
*/
|
|
16
|
+
function defaultReferralCodeGenerator(contactName) {
|
|
17
|
+
const normalized = contactName
|
|
18
|
+
.toLowerCase()
|
|
19
|
+
.replace(/[^a-z0-9]/g, '')
|
|
20
|
+
.substring(0, 15);
|
|
21
|
+
const randomDigits = crypto.randomInt(1000, 10000);
|
|
22
|
+
return `${normalized}-${randomDigits}`;
|
|
23
|
+
}
|
|
24
|
+
export class AffiliateAttributionService {
|
|
25
|
+
supabase;
|
|
26
|
+
organizationId;
|
|
27
|
+
config;
|
|
28
|
+
constructor(supabase, config, organizationId) {
|
|
29
|
+
this.supabase = supabase;
|
|
30
|
+
this.organizationId = organizationId;
|
|
31
|
+
this.config = { ...DEFAULT_CONFIG, ...config };
|
|
32
|
+
}
|
|
33
|
+
// ─── Attribution ────────────────────────────────────────────
|
|
34
|
+
/**
|
|
35
|
+
* Determine affiliate attribution for an order.
|
|
36
|
+
* Priority: Voucher > URL (?ref=) > Cookie
|
|
37
|
+
*/
|
|
38
|
+
async determineAttribution(req, voucherCode) {
|
|
39
|
+
logger.info('Determining affiliate attribution', { voucherCode });
|
|
40
|
+
// 1. Voucher with affiliate
|
|
41
|
+
if (voucherCode) {
|
|
42
|
+
const attribution = await this.checkVoucherAttribution(voucherCode);
|
|
43
|
+
if (attribution) {
|
|
44
|
+
logger.info('Attribution via voucher', attribution);
|
|
45
|
+
return attribution;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
// 2. URL parameter (?ref=)
|
|
49
|
+
const urlAttribution = this.checkUrlParameter(req);
|
|
50
|
+
if (urlAttribution) {
|
|
51
|
+
logger.info('Attribution via URL', urlAttribution);
|
|
52
|
+
return urlAttribution;
|
|
53
|
+
}
|
|
54
|
+
// 3. Cookie fallback
|
|
55
|
+
const cookieAttribution = this.checkCookie(req);
|
|
56
|
+
if (cookieAttribution) {
|
|
57
|
+
logger.info('Attribution via cookie', cookieAttribution);
|
|
58
|
+
return cookieAttribution;
|
|
59
|
+
}
|
|
60
|
+
logger.info('No affiliate attribution found');
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
// ─── Commission ─────────────────────────────────────────────
|
|
64
|
+
/**
|
|
65
|
+
* Create a commission record for an affiliate sale.
|
|
66
|
+
* Updates affiliate stats and checks for tier upgrade.
|
|
67
|
+
*/
|
|
68
|
+
async createCommission(order, attribution) {
|
|
69
|
+
logger.info('Creating commission', { orderId: order.id, attribution });
|
|
70
|
+
const affiliate = await this.resolveAffiliate(attribution.reference, attribution.affiliate_id);
|
|
71
|
+
if (!affiliate) {
|
|
72
|
+
logger.warn('Affiliate not found', { attribution });
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const orderAmount = order.total_excl_vat;
|
|
76
|
+
const commissionAmount = orderAmount * (affiliate.commission_percentage / 100);
|
|
77
|
+
logger.info('Commission calculated', {
|
|
78
|
+
affiliateId: affiliate.id,
|
|
79
|
+
orderAmount,
|
|
80
|
+
commissionPercentage: affiliate.commission_percentage,
|
|
81
|
+
commissionAmount,
|
|
82
|
+
});
|
|
83
|
+
// Create commission record
|
|
84
|
+
const { data: commission, error } = await this.supabase
|
|
85
|
+
.from('affiliate_commissions')
|
|
86
|
+
.insert({
|
|
87
|
+
organization_id: order.organization_id,
|
|
88
|
+
affiliate_id: affiliate.id,
|
|
89
|
+
order_id: order.id,
|
|
90
|
+
affiliate_source: 'internal',
|
|
91
|
+
product_name: 'Order',
|
|
92
|
+
order_amount_excl_vat: orderAmount,
|
|
93
|
+
commission_percentage: affiliate.commission_percentage,
|
|
94
|
+
commission_amount: commissionAmount,
|
|
95
|
+
status: 'pending',
|
|
96
|
+
})
|
|
97
|
+
.select()
|
|
98
|
+
.single();
|
|
99
|
+
if (error) {
|
|
100
|
+
logger.error('Failed to create commission', { error, orderId: order.id });
|
|
101
|
+
throw error;
|
|
102
|
+
}
|
|
103
|
+
logger.info('Commission created', { commissionId: commission.id });
|
|
104
|
+
// Update affiliate stats
|
|
105
|
+
await this.updateAffiliateStats(affiliate.id, {
|
|
106
|
+
total_sales: affiliate.total_sales + 1,
|
|
107
|
+
total_revenue: affiliate.total_revenue + orderAmount,
|
|
108
|
+
total_commission_earned: affiliate.total_commission_earned + commissionAmount,
|
|
109
|
+
last_sale_at: new Date().toISOString(),
|
|
110
|
+
});
|
|
111
|
+
// Check for tier upgrade
|
|
112
|
+
await this.checkTierUpgrade(affiliate.id, affiliate.total_sales + 1);
|
|
113
|
+
}
|
|
114
|
+
// ─── Referral Code ──────────────────────────────────────────
|
|
115
|
+
/**
|
|
116
|
+
* Generate a referral code for a new affiliate.
|
|
117
|
+
* Uses custom generator from config or default format.
|
|
118
|
+
*/
|
|
119
|
+
generateReferralCode(contactName) {
|
|
120
|
+
const generator = this.config.referralCodeGenerator || defaultReferralCodeGenerator;
|
|
121
|
+
return generator(contactName);
|
|
122
|
+
}
|
|
123
|
+
// ─── Private: Attribution Checks ────────────────────────────
|
|
124
|
+
async checkVoucherAttribution(voucherCode) {
|
|
125
|
+
try {
|
|
126
|
+
const { data: voucher, error } = await this.supabase
|
|
127
|
+
.from('vouchers')
|
|
128
|
+
.select('id, affiliate_id')
|
|
129
|
+
.eq('code', voucherCode)
|
|
130
|
+
.single();
|
|
131
|
+
if (error || !voucher?.affiliate_id) {
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
return {
|
|
135
|
+
affiliate_id: voucher.affiliate_id,
|
|
136
|
+
source: 'internal',
|
|
137
|
+
attribution_type: 'voucher',
|
|
138
|
+
reference: voucherCode,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
logger.error('Error checking voucher attribution', error);
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
checkUrlParameter(req) {
|
|
147
|
+
const ref = req.query.ref;
|
|
148
|
+
if (!ref)
|
|
149
|
+
return null;
|
|
150
|
+
return {
|
|
151
|
+
affiliate_id: null,
|
|
152
|
+
source: 'internal',
|
|
153
|
+
attribution_type: 'url',
|
|
154
|
+
reference: ref,
|
|
155
|
+
};
|
|
156
|
+
}
|
|
157
|
+
checkCookie(req) {
|
|
158
|
+
const cookie = req.cookies?.affiliate_ref;
|
|
159
|
+
if (!cookie)
|
|
160
|
+
return null;
|
|
161
|
+
try {
|
|
162
|
+
const data = JSON.parse(cookie);
|
|
163
|
+
const age = Date.now() - data.timestamp;
|
|
164
|
+
const maxAge = this.config.cookieDurationDays * 24 * 60 * 60 * 1000;
|
|
165
|
+
if (age > maxAge) {
|
|
166
|
+
logger.info('Affiliate cookie expired', { ageDays: Math.floor(age / (24 * 60 * 60 * 1000)) });
|
|
167
|
+
return null;
|
|
168
|
+
}
|
|
169
|
+
// Only accept internal source in tetra-core
|
|
170
|
+
if (data.source && data.source !== 'internal') {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
return {
|
|
174
|
+
affiliate_id: null,
|
|
175
|
+
source: 'internal',
|
|
176
|
+
attribution_type: 'cookie',
|
|
177
|
+
reference: data.ref,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
catch (error) {
|
|
181
|
+
logger.error('Error parsing affiliate cookie', error);
|
|
182
|
+
return null;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
// ─── Private: Affiliate Resolution ──────────────────────────
|
|
186
|
+
/**
|
|
187
|
+
* Resolve an affiliate from referral code or ID.
|
|
188
|
+
*/
|
|
189
|
+
async resolveAffiliate(reference, affiliateId) {
|
|
190
|
+
// If affiliate ID already known (voucher attribution)
|
|
191
|
+
if (affiliateId) {
|
|
192
|
+
const { data, error } = await this.supabase
|
|
193
|
+
.from('affiliates')
|
|
194
|
+
.select('*')
|
|
195
|
+
.eq('id', affiliateId)
|
|
196
|
+
.eq('status', 'active')
|
|
197
|
+
.single();
|
|
198
|
+
if (error) {
|
|
199
|
+
logger.error('Failed to fetch affiliate by ID', { error, affiliateId });
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
return data;
|
|
203
|
+
}
|
|
204
|
+
// Look up by referral code
|
|
205
|
+
const { data, error } = await this.supabase
|
|
206
|
+
.from('affiliates')
|
|
207
|
+
.select('*')
|
|
208
|
+
.eq('referral_code', reference)
|
|
209
|
+
.eq('status', 'active')
|
|
210
|
+
.single();
|
|
211
|
+
if (error) {
|
|
212
|
+
logger.error('Failed to fetch affiliate by referral code', { error, reference });
|
|
213
|
+
return null;
|
|
214
|
+
}
|
|
215
|
+
return data;
|
|
216
|
+
}
|
|
217
|
+
// ─── Private: Stats & Tiers ─────────────────────────────────
|
|
218
|
+
async updateAffiliateStats(affiliateId, updates) {
|
|
219
|
+
const { error } = await this.supabase
|
|
220
|
+
.from('affiliates')
|
|
221
|
+
.update(updates)
|
|
222
|
+
.eq('id', affiliateId);
|
|
223
|
+
if (error) {
|
|
224
|
+
logger.error('Failed to update affiliate stats', { error, affiliateId });
|
|
225
|
+
throw error;
|
|
226
|
+
}
|
|
227
|
+
logger.info('Affiliate stats updated', { affiliateId, updates });
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* Check if affiliate qualifies for tier upgrade (config-driven).
|
|
231
|
+
*/
|
|
232
|
+
async checkTierUpgrade(affiliateId, totalSales) {
|
|
233
|
+
const { data: affiliate, error } = await this.supabase
|
|
234
|
+
.from('affiliates')
|
|
235
|
+
.select('tier, commission_percentage')
|
|
236
|
+
.eq('id', affiliateId)
|
|
237
|
+
.single();
|
|
238
|
+
if (error || !affiliate) {
|
|
239
|
+
logger.error('Failed to fetch affiliate for tier check', { error, affiliateId });
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
242
|
+
// Find the highest qualifying tier
|
|
243
|
+
const sortedTiers = [...this.config.tiers].sort((a, b) => b.minSales - a.minSales);
|
|
244
|
+
const qualifyingTier = sortedTiers.find(t => totalSales >= t.minSales);
|
|
245
|
+
if (!qualifyingTier || qualifyingTier.name === affiliate.tier) {
|
|
246
|
+
return; // No upgrade needed
|
|
247
|
+
}
|
|
248
|
+
// Check if this is actually an upgrade (not a downgrade)
|
|
249
|
+
const currentTierIndex = this.config.tiers.findIndex(t => t.name === affiliate.tier);
|
|
250
|
+
const newTierIndex = this.config.tiers.findIndex(t => t.name === qualifyingTier.name);
|
|
251
|
+
if (newTierIndex <= currentTierIndex) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
logger.info('Tier upgrade triggered', {
|
|
255
|
+
affiliateId,
|
|
256
|
+
oldTier: affiliate.tier,
|
|
257
|
+
newTier: qualifyingTier.name,
|
|
258
|
+
oldCommission: affiliate.commission_percentage,
|
|
259
|
+
newCommission: qualifyingTier.commissionPercentage,
|
|
260
|
+
totalSales,
|
|
261
|
+
});
|
|
262
|
+
await this.upgradeAffiliateTier(affiliateId, {
|
|
263
|
+
old_tier: affiliate.tier,
|
|
264
|
+
new_tier: qualifyingTier.name,
|
|
265
|
+
old_commission: affiliate.commission_percentage,
|
|
266
|
+
new_commission: qualifyingTier.commissionPercentage,
|
|
267
|
+
reason: 'milestone_reached',
|
|
268
|
+
triggered_by_sale_count: totalSales,
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
async upgradeAffiliateTier(affiliateId, upgrade) {
|
|
272
|
+
// Update affiliate tier and commission
|
|
273
|
+
const { error: updateError } = await this.supabase
|
|
274
|
+
.from('affiliates')
|
|
275
|
+
.update({
|
|
276
|
+
tier: upgrade.new_tier,
|
|
277
|
+
commission_percentage: upgrade.new_commission,
|
|
278
|
+
updated_at: new Date().toISOString(),
|
|
279
|
+
})
|
|
280
|
+
.eq('id', affiliateId);
|
|
281
|
+
if (updateError) {
|
|
282
|
+
logger.error('Failed to update affiliate tier', { error: updateError, affiliateId });
|
|
283
|
+
throw updateError;
|
|
284
|
+
}
|
|
285
|
+
// Record in tier history
|
|
286
|
+
const { error: historyError } = await this.supabase
|
|
287
|
+
.from('affiliate_tier_history')
|
|
288
|
+
.insert({
|
|
289
|
+
affiliate_id: affiliateId,
|
|
290
|
+
old_tier: upgrade.old_tier,
|
|
291
|
+
new_tier: upgrade.new_tier,
|
|
292
|
+
old_commission_percentage: upgrade.old_commission,
|
|
293
|
+
new_commission_percentage: upgrade.new_commission,
|
|
294
|
+
reason: upgrade.reason,
|
|
295
|
+
triggered_by_sale_count: upgrade.triggered_by_sale_count,
|
|
296
|
+
});
|
|
297
|
+
if (historyError) {
|
|
298
|
+
logger.error('Failed to record tier history', { error: historyError, affiliateId });
|
|
299
|
+
// Don't throw — tier upgrade succeeded even if history failed
|
|
300
|
+
}
|
|
301
|
+
logger.info('Tier upgraded successfully', {
|
|
302
|
+
affiliateId,
|
|
303
|
+
oldTier: upgrade.old_tier,
|
|
304
|
+
newTier: upgrade.new_tier,
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
//# sourceMappingURL=AffiliateAttributionService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AffiliateAttributionService.js","sourceRoot":"","sources":["../../../src/shared/affiliate/AffiliateAttributionService.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* AffiliateClickService
|
|
3
|
+
*
|
|
4
|
+
* Handles click tracking and conversion marking for the affiliate module.
|
|
5
|
+
*
|
|
6
|
+
* @module @soulbatical/tetra-core/affiliate
|
|
7
|
+
*/
|
|
8
|
+
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
9
|
+
export declare class AffiliateClickService {
|
|
10
|
+
private supabase;
|
|
11
|
+
constructor(supabase: SupabaseClient);
|
|
12
|
+
/**
|
|
13
|
+
* Register an affiliate click event.
|
|
14
|
+
* Returns the click record ID.
|
|
15
|
+
*/
|
|
16
|
+
registerClick(data: {
|
|
17
|
+
affiliate_id?: string | null;
|
|
18
|
+
organization_id?: string | null;
|
|
19
|
+
affiliate_source: string;
|
|
20
|
+
visitor_ip?: string | null;
|
|
21
|
+
user_agent?: string | null;
|
|
22
|
+
referrer_url?: string | null;
|
|
23
|
+
landing_page?: string | null;
|
|
24
|
+
external_click_ref?: string | null;
|
|
25
|
+
}): Promise<string | null>;
|
|
26
|
+
/**
|
|
27
|
+
* Increment affiliate total_clicks counter.
|
|
28
|
+
*/
|
|
29
|
+
incrementClickCount(affiliateId: string): Promise<void>;
|
|
30
|
+
/**
|
|
31
|
+
* Mark a click as converted after a successful order.
|
|
32
|
+
*/
|
|
33
|
+
markConverted(clickId: string, orderId: string): Promise<void>;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=AffiliateClickService.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AffiliateClickService.d.ts","sourceRoot":"","sources":["../../../src/shared/affiliate/AffiliateClickService.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAK5D,qBAAa,qBAAqB;IAChC,OAAO,CAAC,QAAQ,CAAiB;gBAErB,QAAQ,EAAE,cAAc;IAIpC;;;OAGG;IACG,aAAa,CAAC,IAAI,EAAE;QACxB,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAChC,gBAAgB,EAAE,MAAM,CAAC;QACzB,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC3B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC7B,kBAAkB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;KACpC,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IA0B1B;;OAEG;IACG,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuB7D;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA4BrE"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { createLogger } from '../../utils/logger.js';
|
|
2
|
+
const logger = createLogger('service:affiliate:clicks');
|
|
3
|
+
export class AffiliateClickService {
|
|
4
|
+
supabase;
|
|
5
|
+
constructor(supabase) {
|
|
6
|
+
this.supabase = supabase;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Register an affiliate click event.
|
|
10
|
+
* Returns the click record ID.
|
|
11
|
+
*/
|
|
12
|
+
async registerClick(data) {
|
|
13
|
+
const { data: click, error } = await this.supabase
|
|
14
|
+
.from('affiliate_clicks')
|
|
15
|
+
.insert({
|
|
16
|
+
organization_id: data.organization_id || null,
|
|
17
|
+
affiliate_id: data.affiliate_id || null,
|
|
18
|
+
visitor_ip: data.visitor_ip || null,
|
|
19
|
+
user_agent: data.user_agent || null,
|
|
20
|
+
referrer_url: data.referrer_url || null,
|
|
21
|
+
landing_page: data.landing_page || null,
|
|
22
|
+
affiliate_source: data.affiliate_source,
|
|
23
|
+
external_click_ref: data.external_click_ref || null,
|
|
24
|
+
converted: false,
|
|
25
|
+
})
|
|
26
|
+
.select('id')
|
|
27
|
+
.single();
|
|
28
|
+
if (error) {
|
|
29
|
+
logger.error('Failed to record click', { error });
|
|
30
|
+
return null;
|
|
31
|
+
}
|
|
32
|
+
logger.info('Click registered', { clickId: click.id, affiliateId: data.affiliate_id });
|
|
33
|
+
return click.id;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Increment affiliate total_clicks counter.
|
|
37
|
+
*/
|
|
38
|
+
async incrementClickCount(affiliateId) {
|
|
39
|
+
// Fetch current count, then increment (safe for low-concurrency affiliate use case)
|
|
40
|
+
const { data: affiliate, error: fetchError } = await this.supabase
|
|
41
|
+
.from('affiliates')
|
|
42
|
+
.select('total_clicks')
|
|
43
|
+
.eq('id', affiliateId)
|
|
44
|
+
.single();
|
|
45
|
+
if (fetchError || !affiliate) {
|
|
46
|
+
logger.error('Failed to fetch affiliate for click count update', { error: fetchError, affiliateId });
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
const { error: updateError } = await this.supabase
|
|
50
|
+
.from('affiliates')
|
|
51
|
+
.update({ total_clicks: (affiliate.total_clicks || 0) + 1 })
|
|
52
|
+
.eq('id', affiliateId);
|
|
53
|
+
if (updateError) {
|
|
54
|
+
logger.error('Failed to update click count', { error: updateError, affiliateId });
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Mark a click as converted after a successful order.
|
|
59
|
+
*/
|
|
60
|
+
async markConverted(clickId, orderId) {
|
|
61
|
+
const { data: click, error: fetchError } = await this.supabase
|
|
62
|
+
.from('affiliate_clicks')
|
|
63
|
+
.select('clicked_at')
|
|
64
|
+
.eq('id', clickId)
|
|
65
|
+
.single();
|
|
66
|
+
let conversionTimeHours = null;
|
|
67
|
+
if (!fetchError && click?.clicked_at) {
|
|
68
|
+
const clickedAt = new Date(click.clicked_at).getTime();
|
|
69
|
+
conversionTimeHours = Math.round((Date.now() - clickedAt) / (1000 * 60 * 60));
|
|
70
|
+
}
|
|
71
|
+
const { error } = await this.supabase
|
|
72
|
+
.from('affiliate_clicks')
|
|
73
|
+
.update({
|
|
74
|
+
converted: true,
|
|
75
|
+
order_id: orderId,
|
|
76
|
+
conversion_time_hours: conversionTimeHours,
|
|
77
|
+
})
|
|
78
|
+
.eq('id', clickId);
|
|
79
|
+
if (error) {
|
|
80
|
+
logger.error('Failed to mark click as converted', { error, clickId, orderId });
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
logger.info('Click marked as converted', { clickId, orderId, conversionTimeHours });
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=AffiliateClickService.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AffiliateClickService.js","sourceRoot":"","sources":["../../../src/shared/affiliate/AffiliateClickService.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,MAAM,GAAG,YAAY,CAAC,0BAA0B,CAAC,CAAC;AAExD,MAAM,OAAO,qBAAqB;IACxB,QAAQ,CAAiB;IAEjC,YAAY,QAAwB;QAClC,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;IAC3B,CAAC;IAED;;;OAGG;IACH,KAAK,CAAC,aAAa,CAAC,IASnB;QACC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAC/C,IAAI,CAAC,kBAAkB,CAAC;aACxB,MAAM,CAAC;YACN,eAAe,EAAE,IAAI,CAAC,eAAe,IAAI,IAAI;YAC7C,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI;YACvC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;YACnC,UAAU,EAAE,IAAI,CAAC,UAAU,IAAI,IAAI;YACnC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI;YACvC,YAAY,EAAE,IAAI,CAAC,YAAY,IAAI,IAAI;YACvC,gBAAgB,EAAE,IAAI,CAAC,gBAAgB;YACvC,kBAAkB,EAAE,IAAI,CAAC,kBAAkB,IAAI,IAAI;YACnD,SAAS,EAAE,KAAK;SACjB,CAAC;aACD,MAAM,CAAC,IAAI,CAAC;aACZ,MAAM,EAAE,CAAC;QAEZ,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,wBAAwB,EAAE,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,OAAO,IAAI,CAAC;QACd,CAAC;QAED,MAAM,CAAC,IAAI,CAAC,kBAAkB,EAAE,EAAE,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,WAAW,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QACvF,OAAO,KAAK,CAAC,EAAE,CAAC;IAClB,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,mBAAmB,CAAC,WAAmB;QAC3C,oFAAoF;QACpF,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAC/D,IAAI,CAAC,YAAY,CAAC;aAClB,MAAM,CAAC,cAAc,CAAC;aACtB,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC;aACrB,MAAM,EAAE,CAAC;QAEZ,IAAI,UAAU,IAAI,CAAC,SAAS,EAAE,CAAC;YAC7B,MAAM,CAAC,KAAK,CAAC,kDAAkD,EAAE,EAAE,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC,CAAC;YACrG,OAAO;QACT,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAC/C,IAAI,CAAC,YAAY,CAAC;aAClB,MAAM,CAAC,EAAE,YAAY,EAAE,CAAC,SAAS,CAAC,YAAY,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC;aAC3D,EAAE,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;QAEzB,IAAI,WAAW,EAAE,CAAC;YAChB,MAAM,CAAC,KAAK,CAAC,8BAA8B,EAAE,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC,CAAC;QACpF,CAAC;IACH,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,aAAa,CAAC,OAAe,EAAE,OAAe;QAClD,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAC3D,IAAI,CAAC,kBAAkB,CAAC;aACxB,MAAM,CAAC,YAAY,CAAC;aACpB,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC;aACjB,MAAM,EAAE,CAAC;QAEZ,IAAI,mBAAmB,GAAkB,IAAI,CAAC;QAC9C,IAAI,CAAC,UAAU,IAAI,KAAK,EAAE,UAAU,EAAE,CAAC;YACrC,MAAM,SAAS,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,OAAO,EAAE,CAAC;YACvD,mBAAmB,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC;QAChF,CAAC;QAED,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,QAAQ;aAClC,IAAI,CAAC,kBAAkB,CAAC;aACxB,MAAM,CAAC;YACN,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,OAAO;YACjB,qBAAqB,EAAE,mBAAmB;SAC3C,CAAC;aACD,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAErB,IAAI,KAAK,EAAE,CAAC;YACV,MAAM,CAAC,KAAK,CAAC,mCAAmC,EAAE,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;QACjF,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,IAAI,CAAC,2BAA2B,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default Affiliate FeatureConfig
|
|
3
|
+
*
|
|
4
|
+
* Projects can use this directly or extend with project-specific fields.
|
|
5
|
+
* Config-driven: auto-generates admin pages, filters, sorting, and pagination.
|
|
6
|
+
*
|
|
7
|
+
* @module @soulbatical/tetra-core/affiliate
|
|
8
|
+
*/
|
|
9
|
+
import type { FeatureConfig } from '../types/feature-config.js';
|
|
10
|
+
export declare const defaultAffiliateFeatureConfig: FeatureConfig;
|
|
11
|
+
//# sourceMappingURL=affiliateFeatureConfig.d.ts.map
|