@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 @@
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":"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"}
@@ -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
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affiliateFeatureConfig.d.ts","sourceRoot":"","sources":["../../../src/shared/affiliate/affiliateFeatureConfig.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAEhE,eAAO,MAAM,6BAA6B,EAAE,aAyP3C,CAAC"}
@@ -0,0 +1,242 @@
1
+ export const defaultAffiliateFeatureConfig = {
2
+ // ─── Database ───────────────────────────────────────────
3
+ tableName: 'affiliates',
4
+ organizationIdField: 'organization_id',
5
+ // ─── RPC (v3.0 Window Function Pattern) ─────────────────
6
+ countsRpcName: 'get_affiliates_counts',
7
+ resultsRpcName: 'get_affiliates_results',
8
+ // ─── Search ─────────────────────────────────────────────
9
+ searchFields: ['contact_name', 'email', 'company_name', 'referral_code'],
10
+ // ─── Sorting ────────────────────────────────────────────
11
+ defaultSortField: 'created_at',
12
+ allowedSortFields: ['created_at', 'contact_name', 'email', 'total_sales', 'total_revenue', 'total_commission_earned'],
13
+ sortFields: [
14
+ {
15
+ field: 'created_at',
16
+ alias: 'date',
17
+ label: 'Join Date',
18
+ defaultDirection: 'desc',
19
+ ui: { ascLabel: 'Oldest first', descLabel: 'Newest first' },
20
+ },
21
+ {
22
+ field: 'contact_name',
23
+ alias: 'name',
24
+ label: 'Name',
25
+ defaultDirection: 'asc',
26
+ ui: { ascLabel: 'A-Z', descLabel: 'Z-A' },
27
+ },
28
+ {
29
+ field: 'total_sales',
30
+ alias: 'sales',
31
+ label: 'Sales',
32
+ defaultDirection: 'desc',
33
+ ui: { ascLabel: 'Low to High', descLabel: 'High to Low' },
34
+ },
35
+ {
36
+ field: 'total_revenue',
37
+ alias: 'revenue',
38
+ label: 'Revenue',
39
+ defaultDirection: 'desc',
40
+ ui: { ascLabel: 'Low to High', descLabel: 'High to Low' },
41
+ },
42
+ {
43
+ field: 'total_commission_earned',
44
+ alias: 'commission',
45
+ label: 'Commission',
46
+ defaultDirection: 'desc',
47
+ ui: { ascLabel: 'Low to High', descLabel: 'High to Low' },
48
+ },
49
+ ],
50
+ // ─── Pagination ─────────────────────────────────────────
51
+ pagination: {
52
+ defaultLimit: 20,
53
+ maxLimit: 100,
54
+ minLimit: 1,
55
+ },
56
+ // ─── Includes ───────────────────────────────────────────
57
+ includeMapping: {
58
+ users_public: {
59
+ foreignKey: 'affiliates_user_id_fkey',
60
+ tableName: 'users_public',
61
+ fields: ['id', 'firstname', 'lastname', 'email'],
62
+ },
63
+ organization: {
64
+ foreignKey: 'affiliates_organization_id_fkey',
65
+ tableName: 'organizations',
66
+ fields: ['id', 'name', 'custom_domain', 'slug'],
67
+ },
68
+ },
69
+ // ─── Filters ────────────────────────────────────────────
70
+ filters: [
71
+ {
72
+ name: 'ids',
73
+ type: 'array',
74
+ dbField: 'id',
75
+ rpcParam: 'ids',
76
+ },
77
+ {
78
+ name: 'status',
79
+ type: 'enum',
80
+ column: 'status',
81
+ values: ['pending', 'active', 'inactive', 'rejected'],
82
+ countsKey: 'byStatus',
83
+ ui: {
84
+ label: 'Status',
85
+ placeholder: 'Filter by status...',
86
+ options: [
87
+ { value: 'all', label: 'All Statuses' },
88
+ { value: 'pending', label: 'Pending Approval' },
89
+ { value: 'active', label: 'Active' },
90
+ { value: 'inactive', label: 'Inactive' },
91
+ { value: 'rejected', label: 'Rejected' },
92
+ ],
93
+ order: 1,
94
+ defaultVisible: true,
95
+ },
96
+ },
97
+ {
98
+ name: 'tier',
99
+ type: 'enum',
100
+ column: 'tier',
101
+ values: ['starter', 'active'],
102
+ countsKey: 'byTier',
103
+ ui: {
104
+ label: 'Tier',
105
+ placeholder: 'Filter by tier...',
106
+ options: [
107
+ { value: 'all', label: 'All Tiers' },
108
+ { value: 'starter', label: 'Starter' },
109
+ { value: 'active', label: 'Active' },
110
+ ],
111
+ order: 2,
112
+ defaultVisible: true,
113
+ },
114
+ },
115
+ {
116
+ name: 'search',
117
+ type: 'search',
118
+ sqlGeneration: {
119
+ searchFields: ['contact_name', 'email', 'company_name', 'referral_code'],
120
+ },
121
+ ui: {
122
+ label: 'Search',
123
+ placeholder: 'Search by name, email, company, or code...',
124
+ order: 0,
125
+ defaultVisible: true,
126
+ },
127
+ },
128
+ {
129
+ name: 'has_user',
130
+ type: 'nullable',
131
+ column: 'user_id',
132
+ countsKey: 'byUserAccount',
133
+ ui: {
134
+ label: 'User Account',
135
+ placeholder: 'Filter by user account...',
136
+ options: [
137
+ { value: 'all', label: 'All Affiliates' },
138
+ { value: 'with', label: 'With User Account' },
139
+ { value: 'without', label: 'Without User Account' },
140
+ ],
141
+ order: 3,
142
+ defaultVisible: false,
143
+ },
144
+ },
145
+ {
146
+ name: 'time_period',
147
+ type: 'time',
148
+ dateField: 'created_at',
149
+ rpcParam: 'time_period',
150
+ countsKey: 'byTimePeriod',
151
+ ui: {
152
+ label: 'Join Date',
153
+ placeholder: 'Filter by join date...',
154
+ options: [
155
+ { value: 'all', label: 'All Time' },
156
+ { value: 'this-week', label: 'Last 7 Days' },
157
+ { value: 'this-month', label: 'Last 30 Days' },
158
+ { value: 'older', label: 'Older than 30 Days' },
159
+ ],
160
+ order: 4,
161
+ defaultVisible: false,
162
+ },
163
+ },
164
+ ],
165
+ // ─── Counts ─────────────────────────────────────────────
166
+ counts: {
167
+ total: { type: 'total' },
168
+ byStatus: { type: 'breakdown', column: 'status' },
169
+ byTier: { type: 'breakdown', column: 'tier' },
170
+ withUserAccount: { type: 'nullable', column: 'user_id', mode: 'with' },
171
+ withoutUserAccount: { type: 'nullable', column: 'user_id', mode: 'without' },
172
+ thisWeek: { type: 'time', period: 'week', column: 'created_at' },
173
+ thisMonth: { type: 'time', period: 'month', column: 'created_at' },
174
+ older: { type: 'time', period: 'older', column: 'created_at' },
175
+ },
176
+ // ─── Display ────────────────────────────────────────────
177
+ display: {
178
+ page: {
179
+ title: 'Affiliates',
180
+ entityName: 'affiliates',
181
+ entitySingular: 'affiliate',
182
+ entityPlural: 'affiliates',
183
+ createButton: {
184
+ label: 'Add Affiliate',
185
+ dialog: 'CreateAffiliateDialog',
186
+ },
187
+ viewModes: ['list'],
188
+ byIdsInclude: 'users_public',
189
+ },
190
+ list: {
191
+ type: 'grid',
192
+ emptyMessage: 'No affiliates found matching your filters',
193
+ },
194
+ card: {
195
+ title: {
196
+ template: '{{contact_name}}',
197
+ fallback: '{{email}}',
198
+ },
199
+ badges: [
200
+ {
201
+ field: 'status',
202
+ variantMap: {
203
+ active: 'default',
204
+ pending: 'secondary',
205
+ inactive: 'outline',
206
+ rejected: 'destructive',
207
+ },
208
+ },
209
+ {
210
+ field: 'tier',
211
+ variant: 'outline',
212
+ },
213
+ ],
214
+ metadata: [
215
+ {
216
+ type: 'text',
217
+ field: 'email',
218
+ className: 'text-sm text-gray-600',
219
+ },
220
+ {
221
+ type: 'text',
222
+ field: 'company_name',
223
+ className: 'text-sm font-medium',
224
+ showIf: { field: 'company_name', condition: 'exists' },
225
+ },
226
+ {
227
+ type: 'text',
228
+ template: 'Code: {{referral_code}}',
229
+ className: 'text-xs text-gray-500 font-mono',
230
+ },
231
+ {
232
+ type: 'text',
233
+ template: '{{total_sales}} sales | {{total_revenue}} revenue',
234
+ className: 'text-xs text-gray-500',
235
+ },
236
+ ],
237
+ navigationPanels: ['users_public'],
238
+ actions: [],
239
+ },
240
+ },
241
+ };
242
+ //# sourceMappingURL=affiliateFeatureConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"affiliateFeatureConfig.js","sourceRoot":"","sources":["../../../src/shared/affiliate/affiliateFeatureConfig.ts"],"names":[],"mappings":"AAUA,MAAM,CAAC,MAAM,6BAA6B,GAAkB;IAC1D,2DAA2D;IAC3D,SAAS,EAAE,YAAY;IACvB,mBAAmB,EAAE,iBAAiB;IAEtC,2DAA2D;IAC3D,aAAa,EAAE,uBAAuB;IACtC,cAAc,EAAE,wBAAwB;IAExC,2DAA2D;IAC3D,YAAY,EAAE,CAAC,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,CAAC;IAExE,2DAA2D;IAC3D,gBAAgB,EAAE,YAAY;IAC9B,iBAAiB,EAAE,CAAC,YAAY,EAAE,cAAc,EAAE,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,yBAAyB,CAAC;IAErH,UAAU,EAAE;QACV;YACE,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,WAAW;YAClB,gBAAgB,EAAE,MAAM;YACxB,EAAE,EAAE,EAAE,QAAQ,EAAE,cAAc,EAAE,SAAS,EAAE,cAAc,EAAE;SAC5D;QACD;YACE,KAAK,EAAE,cAAc;YACrB,KAAK,EAAE,MAAM;YACb,KAAK,EAAE,MAAM;YACb,gBAAgB,EAAE,KAAK;YACvB,EAAE,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE;SAC1C;QACD;YACE,KAAK,EAAE,aAAa;YACpB,KAAK,EAAE,OAAO;YACd,KAAK,EAAE,OAAO;YACd,gBAAgB,EAAE,MAAM;YACxB,EAAE,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE;SAC1D;QACD;YACE,KAAK,EAAE,eAAe;YACtB,KAAK,EAAE,SAAS;YAChB,KAAK,EAAE,SAAS;YAChB,gBAAgB,EAAE,MAAM;YACxB,EAAE,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE;SAC1D;QACD;YACE,KAAK,EAAE,yBAAyB;YAChC,KAAK,EAAE,YAAY;YACnB,KAAK,EAAE,YAAY;YACnB,gBAAgB,EAAE,MAAM;YACxB,EAAE,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,SAAS,EAAE,aAAa,EAAE;SAC1D;KACF;IAED,2DAA2D;IAC3D,UAAU,EAAE;QACV,YAAY,EAAE,EAAE;QAChB,QAAQ,EAAE,GAAG;QACb,QAAQ,EAAE,CAAC;KACZ;IAED,2DAA2D;IAC3D,cAAc,EAAE;QACd,YAAY,EAAE;YACZ,UAAU,EAAE,yBAAyB;YACrC,SAAS,EAAE,cAAc;YACzB,MAAM,EAAE,CAAC,IAAI,EAAE,WAAW,EAAE,UAAU,EAAE,OAAO,CAAC;SACjD;QACD,YAAY,EAAE;YACZ,UAAU,EAAE,iCAAiC;YAC7C,SAAS,EAAE,eAAe;YAC1B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,MAAM,CAAC;SAChD;KACF;IAED,2DAA2D;IAC3D,OAAO,EAAE;QACP;YACE,IAAI,EAAE,KAAK;YACX,IAAI,EAAE,OAAO;YACb,OAAO,EAAE,IAAI;YACb,QAAQ,EAAE,KAAK;SAChB;QACD;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,QAAQ;YAChB,MAAM,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,UAAU,EAAE,UAAU,CAAC;YACrD,SAAS,EAAE,UAAU;YACrB,EAAE,EAAE;gBACF,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,qBAAqB;gBAClC,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,cAAc,EAAE;oBACvC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,kBAAkB,EAAE;oBAC/C,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;oBACpC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;oBACxC,EAAE,KAAK,EAAE,UAAU,EAAE,KAAK,EAAE,UAAU,EAAE;iBACzC;gBACD,KAAK,EAAE,CAAC;gBACR,cAAc,EAAE,IAAI;aACrB;SACF;QACD;YACE,IAAI,EAAE,MAAM;YACZ,IAAI,EAAE,MAAM;YACZ,MAAM,EAAE,MAAM;YACd,MAAM,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;YAC7B,SAAS,EAAE,QAAQ;YACnB,EAAE,EAAE;gBACF,KAAK,EAAE,MAAM;gBACb,WAAW,EAAE,mBAAmB;gBAChC,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE;oBACpC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;oBACtC,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,QAAQ,EAAE;iBACrC;gBACD,KAAK,EAAE,CAAC;gBACR,cAAc,EAAE,IAAI;aACrB;SACF;QACD;YACE,IAAI,EAAE,QAAQ;YACd,IAAI,EAAE,QAAQ;YACd,aAAa,EAAE;gBACb,YAAY,EAAE,CAAC,cAAc,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,CAAC;aACzE;YACD,EAAE,EAAE;gBACF,KAAK,EAAE,QAAQ;gBACf,WAAW,EAAE,4CAA4C;gBACzD,KAAK,EAAE,CAAC;gBACR,cAAc,EAAE,IAAI;aACrB;SACF;QACD;YACE,IAAI,EAAE,UAAU;YAChB,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,SAAS;YACjB,SAAS,EAAE,eAAe;YAC1B,EAAE,EAAE;gBACF,KAAK,EAAE,cAAc;gBACrB,WAAW,EAAE,2BAA2B;gBACxC,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,gBAAgB,EAAE;oBACzC,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,mBAAmB,EAAE;oBAC7C,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,sBAAsB,EAAE;iBACpD;gBACD,KAAK,EAAE,CAAC;gBACR,cAAc,EAAE,KAAK;aACtB;SACF;QACD;YACE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,MAAM;YACZ,SAAS,EAAE,YAAY;YACvB,QAAQ,EAAE,aAAa;YACvB,SAAS,EAAE,cAAc;YACzB,EAAE,EAAE;gBACF,KAAK,EAAE,WAAW;gBAClB,WAAW,EAAE,wBAAwB;gBACrC,OAAO,EAAE;oBACP,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE;oBACnC,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE;oBAC5C,EAAE,KAAK,EAAE,YAAY,EAAE,KAAK,EAAE,cAAc,EAAE;oBAC9C,EAAE,KAAK,EAAE,OAAO,EAAE,KAAK,EAAE,oBAAoB,EAAE;iBAChD;gBACD,KAAK,EAAE,CAAC;gBACR,cAAc,EAAE,KAAK;aACtB;SACF;KACF;IAED,2DAA2D;IAC3D,MAAM,EAAE;QACN,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE;QACxB,QAAQ,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,QAAQ,EAAE;QACjD,MAAM,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,MAAM,EAAE;QAC7C,eAAe,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE;QACtE,kBAAkB,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE;QAC5E,QAAQ,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE;QAChE,SAAS,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE;QAClE,KAAK,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE;KAC/D;IAED,2DAA2D;IAC3D,OAAO,EAAE;QACP,IAAI,EAAE;YACJ,KAAK,EAAE,YAAY;YACnB,UAAU,EAAE,YAAY;YACxB,cAAc,EAAE,WAAW;YAC3B,YAAY,EAAE,YAAY;YAC1B,YAAY,EAAE;gBACZ,KAAK,EAAE,eAAe;gBACtB,MAAM,EAAE,uBAAuB;aAChC;YACD,SAAS,EAAE,CAAC,MAAM,CAAC;YACnB,YAAY,EAAE,cAAc;SAC7B;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,MAAM;YACZ,YAAY,EAAE,2CAA2C;SAC1D;QACD,IAAI,EAAE;YACJ,KAAK,EAAE;gBACL,QAAQ,EAAE,kBAAkB;gBAC5B,QAAQ,EAAE,WAAW;aACtB;YACD,MAAM,EAAE;gBACN;oBACE,KAAK,EAAE,QAAQ;oBACf,UAAU,EAAE;wBACV,MAAM,EAAE,SAAS;wBACjB,OAAO,EAAE,WAAW;wBACpB,QAAQ,EAAE,SAAS;wBACnB,QAAQ,EAAE,aAAa;qBACxB;iBACF;gBACD;oBACE,KAAK,EAAE,MAAM;oBACb,OAAO,EAAE,SAAS;iBACnB;aACF;YACD,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE,OAAO;oBACd,SAAS,EAAE,uBAAuB;iBACnC;gBACD;oBACE,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE,cAAc;oBACrB,SAAS,EAAE,qBAAqB;oBAChC,MAAM,EAAE,EAAE,KAAK,EAAE,cAAc,EAAE,SAAS,EAAE,QAAQ,EAAE;iBACvD;gBACD;oBACE,IAAI,EAAE,MAAM;oBACZ,QAAQ,EAAE,yBAAyB;oBACnC,SAAS,EAAE,iCAAiC;iBAC7C;gBACD;oBACE,IAAI,EAAE,MAAM;oBACZ,QAAQ,EAAE,mDAAmD;oBAC7D,SAAS,EAAE,uBAAuB;iBACnC;aACF;YACD,gBAAgB,EAAE,CAAC,cAAc,CAAC;YAClC,OAAO,EAAE,EAAE;SACZ;KACF;CACF,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Affiliate Module — Barrel Export
3
+ *
4
+ * @module @soulbatical/tetra-core/affiliate
5
+ */
6
+ export { AffiliateAttributionService } from './AffiliateAttributionService.js';
7
+ export { AffiliateClickService } from './AffiliateClickService.js';
8
+ export { defaultAffiliateFeatureConfig } from './affiliateFeatureConfig.js';
9
+ export { addAffiliateAdminRoutes, addAffiliateUserRoutes, addAffiliatePublicRoutes } from './routes.js';
10
+ export type { AffiliateConfig, AffiliateTierConfig, AffiliateAttribution, AffiliateOrder, Affiliate, AffiliateCommission, AffiliateClick, AffiliatePayment, AffiliateTierHistory, AffiliateFilters, AffiliateDashboard, AffiliateDashboardStats, AffiliateDashboardCommission, AffiliateTierProgress, } from './types.js';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/shared/affiliate/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAGnE,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAG5E,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC;AAGxG,YAAY,EACV,eAAe,EACf,mBAAmB,EACnB,oBAAoB,EACpB,cAAc,EACd,SAAS,EACT,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,oBAAoB,EACpB,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,4BAA4B,EAC5B,qBAAqB,GACtB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Affiliate Module — Barrel Export
3
+ *
4
+ * @module @soulbatical/tetra-core/affiliate
5
+ */
6
+ // Services
7
+ export { AffiliateAttributionService } from './AffiliateAttributionService.js';
8
+ export { AffiliateClickService } from './AffiliateClickService.js';
9
+ // Config
10
+ export { defaultAffiliateFeatureConfig } from './affiliateFeatureConfig.js';
11
+ // Routes
12
+ export { addAffiliateAdminRoutes, addAffiliateUserRoutes, addAffiliatePublicRoutes } from './routes.js';
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/shared/affiliate/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,WAAW;AACX,OAAO,EAAE,2BAA2B,EAAE,MAAM,kCAAkC,CAAC;AAC/E,OAAO,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAEnE,SAAS;AACT,OAAO,EAAE,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAE5E,SAAS;AACT,OAAO,EAAE,uBAAuB,EAAE,sBAAsB,EAAE,wBAAwB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Affiliate Route Helpers
3
+ *
4
+ * Factory functions that generate standard affiliate routes.
5
+ * Projects call these in their route setup to get admin, user, and public endpoints.
6
+ *
7
+ * Usage:
8
+ * ```typescript
9
+ * import { addAffiliateAdminRoutes, addAffiliatePublicRoutes } from '@soulbatical/tetra-core';
10
+ *
11
+ * // In admin routes file:
12
+ * const router = Router();
13
+ * router.use(authenticateToken, requireOrganizationAdmin);
14
+ * addAffiliateAdminRoutes(router, { featureConfig, queryController, filterController, crudController });
15
+ *
16
+ * // In public routes file:
17
+ * const publicRouter = Router();
18
+ * addAffiliatePublicRoutes(publicRouter, { config: { defaultCommissionPercentage: 20, ... } });
19
+ * ```
20
+ *
21
+ * @module @soulbatical/tetra-core/affiliate
22
+ */
23
+ import { Router, Request, Response } from 'express';
24
+ import type { SupabaseClient } from '@supabase/supabase-js';
25
+ import type { FeatureConfig } from '../types/feature-config.js';
26
+ import type { AffiliateConfig } from './types.js';
27
+ interface PublicRouteOptions {
28
+ /** Affiliate config for defaults */
29
+ config?: Partial<AffiliateConfig>;
30
+ /** Function to get systemDB client */
31
+ getSystemDB: () => SupabaseClient;
32
+ /** Function to resolve organization_id from request (for multi-tenant) */
33
+ resolveOrganizationId?: (req: Request) => Promise<string | null>;
34
+ }
35
+ /**
36
+ * Add public affiliate routes (no auth required).
37
+ *
38
+ * Routes:
39
+ * - POST /click — Register affiliate click
40
+ * - POST /apply — Submit affiliate application
41
+ */
42
+ export declare function addAffiliatePublicRoutes(router: Router, options: PublicRouteOptions): void;
43
+ interface UserRouteOptions {
44
+ /** Function to get a Supabase client for the authenticated user */
45
+ getUserDB: (req: any) => Promise<SupabaseClient>;
46
+ /** Tier config for progress calculation */
47
+ tiers?: AffiliateConfig['tiers'];
48
+ }
49
+ /**
50
+ * Add user affiliate routes (authenticated user).
51
+ *
52
+ * Routes:
53
+ * - GET /dashboard — Dashboard stats
54
+ * - GET /profile — Affiliate profile
55
+ * - GET /commissions — Commission history
56
+ */
57
+ export declare function addAffiliateUserRoutes(router: Router, options: UserRouteOptions): void;
58
+ interface AdminRouteOptions {
59
+ /** FeatureConfig for the affiliate feature */
60
+ featureConfig: FeatureConfig;
61
+ /** Query controller (auto-bound via BaseQueryController) */
62
+ queryController: any;
63
+ /** Filter controller (created via createFilterConfigController) */
64
+ filterController: any;
65
+ /** CRUD controller with create/update/delete methods */
66
+ crudController: {
67
+ create: (req: any, res: Response) => Promise<any>;
68
+ update: (req: any, res: Response) => Promise<any>;
69
+ delete: (req: any, res: Response) => Promise<any>;
70
+ };
71
+ }
72
+ /**
73
+ * Add admin affiliate routes (requires admin auth).
74
+ *
75
+ * Routes:
76
+ * - POST / — Create affiliate
77
+ * - PUT /:id — Update affiliate
78
+ * - DELETE /:id — Delete affiliate
79
+ * - GET /filters — Filter configurations
80
+ * - GET /by-ids — Get by IDs
81
+ * - GET /counts — Get counts
82
+ * - GET / — List affiliates
83
+ * - GET /:id — Get single affiliate
84
+ */
85
+ export declare function addAffiliateAdminRoutes(router: Router, options: AdminRouteOptions): void;
86
+ export {};
87
+ //# sourceMappingURL=routes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"routes.d.ts","sourceRoot":"","sources":["../../../src/shared/affiliate/routes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAgB,MAAM,SAAS,CAAC;AAElE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAC5D,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAUlD,UAAU,kBAAkB;IAC1B,oCAAoC;IACpC,MAAM,CAAC,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IAClC,sCAAsC;IACtC,WAAW,EAAE,MAAM,cAAc,CAAC;IAClC,0EAA0E;IAC1E,qBAAqB,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAClE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,kBAAkB,GAC1B,IAAI,CA8NN;AAID,UAAU,gBAAgB;IACxB,mEAAmE;IACnE,SAAS,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IACjD,2CAA2C;IAC3C,KAAK,CAAC,EAAE,eAAe,CAAC,OAAO,CAAC,CAAC;CAClC;AAED;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,gBAAgB,GACxB,IAAI,CAmJN;AAID,UAAU,iBAAiB;IACzB,8CAA8C;IAC9C,aAAa,EAAE,aAAa,CAAC;IAC7B,4DAA4D;IAC5D,eAAe,EAAE,GAAG,CAAC;IACrB,mEAAmE;IACnE,gBAAgB,EAAE,GAAG,CAAC;IACtB,wDAAwD;IACxD,cAAc,EAAE;QACd,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;QAClD,MAAM,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,QAAQ,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC;KACnD,CAAC;CACH;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,iBAAiB,GACzB,IAAI,CAqBN"}