@moneybar.online/moneybar 3.2.0 → 3.4.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/README.md +123 -93
- package/dist/index.browser.js +82 -37
- package/dist/index.browser.js.map +1 -1
- package/dist/index.bundle.js +1 -1
- package/dist/index.bundle.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +82 -37
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +82 -37
- package/dist/index.js.map +1 -1
- package/dist/types.d.ts +11 -7
- package/dist/types.d.ts.map +1 -1
- package/example-template.html +113 -57
- package/moneybar-config-template.js +227 -33
- package/package.json +3 -4
- package/src/index.ts +80 -37
- package/src/types.ts +11 -7
- package/dist/index.cjs.js +0 -3058
- package/dist/index.cjs.js.map +0 -1
- package/dist/index.umd.js +0 -2
- package/dist/index.umd.js.map +0 -1
|
@@ -1,28 +1,175 @@
|
|
|
1
1
|
// MoneyBar Configuration Template
|
|
2
2
|
// Copy this file and customize for your project
|
|
3
3
|
|
|
4
|
+
// ========================================
|
|
5
|
+
// THE 3 MONEY-BLOCKING STAGES FOR INDIE HACKERS
|
|
6
|
+
// ========================================
|
|
7
|
+
|
|
8
|
+
// PROBLEM #1: "Forced Sign-In Before Value" (40-60% conversion boost)
|
|
9
|
+
// Solution: Value-first trials - let users try before they buy
|
|
10
|
+
// Use case: PDF generators, image tools, converters
|
|
11
|
+
|
|
12
|
+
// PROBLEM #2: "Silent Drop-Off" (20-30% conversion boost)
|
|
13
|
+
// Solution: Exit feedback capture - learn why users don't convert
|
|
14
|
+
// Use case: SaaS trials, B2B tools, complex products
|
|
15
|
+
|
|
16
|
+
// PROBLEM #3: "Broken Money Flow" (25-40% conversion boost)
|
|
17
|
+
// Solution: Seamless auth + instant payments
|
|
18
|
+
// Use case: Templates, premium features, instant upgrades
|
|
19
|
+
|
|
20
|
+
// ========================================
|
|
21
|
+
// IMPORT OPTIONS
|
|
22
|
+
// ========================================
|
|
23
|
+
|
|
4
24
|
// Option 1: Browser CDN Usage (Recommended for simple projects)
|
|
5
|
-
//
|
|
25
|
+
// Add this import map to your HTML:
|
|
6
26
|
/*
|
|
7
|
-
Add to your HTML:
|
|
8
27
|
<script type="importmap">
|
|
9
28
|
{
|
|
10
29
|
"imports": {
|
|
11
|
-
"@supabase/supabase-js": "https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2
|
|
30
|
+
"@supabase/supabase-js": "https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2/+esm"
|
|
12
31
|
}
|
|
13
32
|
}
|
|
14
33
|
</script>
|
|
15
34
|
*/
|
|
16
|
-
|
|
17
|
-
import { MoneyBar } from 'https://cdn.jsdelivr.net/npm/@moneybar.online/moneybar@3.1.0/dist/index.browser.js';
|
|
35
|
+
import { MoneyBar } from 'https://cdn.jsdelivr.net/npm/@moneybar.online/moneybar/dist/index.browser.js';
|
|
18
36
|
|
|
19
37
|
// Option 2: Self-contained bundle (No import map needed)
|
|
20
|
-
// import { MoneyBar } from 'https://cdn.jsdelivr.net/npm/@moneybar.online/moneybar
|
|
38
|
+
// import { MoneyBar } from 'https://cdn.jsdelivr.net/npm/@moneybar.online/moneybar/dist/index.bundle.js';
|
|
21
39
|
|
|
22
40
|
// Option 3: NPM install usage (for projects with bundlers)
|
|
23
41
|
// import { MoneyBar } from '@moneybar.online/moneybar';
|
|
24
42
|
|
|
25
|
-
//
|
|
43
|
+
// ========================================
|
|
44
|
+
// CONFIGURATION EXAMPLES BY USE CASE
|
|
45
|
+
// ========================================
|
|
46
|
+
|
|
47
|
+
// 🎯 USE CASE 1: VALUE-FIRST DEMO (Problem #1 Solution)
|
|
48
|
+
// Perfect for: PDF generators, image tools, converters
|
|
49
|
+
const VALUE_FIRST_CONFIG = {
|
|
50
|
+
actionFunction: 'generatePDF',
|
|
51
|
+
appId: 'pdf-generator',
|
|
52
|
+
freeAttemptLimit: 3, // Give enough attempts to prove value
|
|
53
|
+
supabase: {
|
|
54
|
+
url: 'your-supabase-url',
|
|
55
|
+
anonKey: 'your-anon-key'
|
|
56
|
+
},
|
|
57
|
+
payment: [{
|
|
58
|
+
provider: 'dodo',
|
|
59
|
+
productId: 'your-product-id',
|
|
60
|
+
mode: 'test'
|
|
61
|
+
}],
|
|
62
|
+
theme: {
|
|
63
|
+
name: 'emerald', // Trustworthy, fresh
|
|
64
|
+
primaryColor: '#059669'
|
|
65
|
+
},
|
|
66
|
+
titleBar: {
|
|
67
|
+
title: '💰 PDF Generator',
|
|
68
|
+
links: [
|
|
69
|
+
{ text: 'How it Works', url: '#how', target: '_self' },
|
|
70
|
+
{ text: 'Examples', url: '#examples', target: '_self' }
|
|
71
|
+
]
|
|
72
|
+
},
|
|
73
|
+
successMessage: {
|
|
74
|
+
enabled: true,
|
|
75
|
+
title: 'PDF Generated!',
|
|
76
|
+
message: 'Your PDF has been created successfully. Try more examples!'
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// 🎯 USE CASE 2: FEEDBACK INTELLIGENCE (Problem #2 Solution)
|
|
81
|
+
// Perfect for: SaaS trials, B2B tools, complex products
|
|
82
|
+
const FEEDBACK_INTELLIGENCE_CONFIG = {
|
|
83
|
+
actionFunction: 'runAnalysis',
|
|
84
|
+
appId: 'saas-analytics',
|
|
85
|
+
freeAttemptLimit: 3,
|
|
86
|
+
supabase: {
|
|
87
|
+
url: 'your-supabase-url',
|
|
88
|
+
anonKey: 'your-anon-key'
|
|
89
|
+
},
|
|
90
|
+
payment: [{
|
|
91
|
+
provider: 'dodo',
|
|
92
|
+
productId: 'your-product-id',
|
|
93
|
+
mode: 'test'
|
|
94
|
+
}],
|
|
95
|
+
// KEY FEATURE: Feedback collection on cancel/exit
|
|
96
|
+
feedback: {
|
|
97
|
+
form: {
|
|
98
|
+
title: 'Quick Feedback',
|
|
99
|
+
description: 'What stopped you from upgrading?',
|
|
100
|
+
option1: 'Too complex to implement',
|
|
101
|
+
option2: 'Not enough ROI for my team',
|
|
102
|
+
option3: 'Need more features first'
|
|
103
|
+
},
|
|
104
|
+
email: [
|
|
105
|
+
{
|
|
106
|
+
provider: 'resend',
|
|
107
|
+
apiKey: 'your-resend-api-key',
|
|
108
|
+
fromEmail: 'feedback@yourapp.com'
|
|
109
|
+
}
|
|
110
|
+
// Future providers can be added:
|
|
111
|
+
// {
|
|
112
|
+
// provider: 'sendgrid',
|
|
113
|
+
// apiKey: 'your-sendgrid-api-key',
|
|
114
|
+
// fromEmail: 'feedback@yourapp.com'
|
|
115
|
+
// }
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
theme: {
|
|
119
|
+
name: 'corporate', // Professional B2B
|
|
120
|
+
primaryColor: '#0066cc'
|
|
121
|
+
},
|
|
122
|
+
titleBar: {
|
|
123
|
+
title: '📈 Analytics Tool',
|
|
124
|
+
links: [
|
|
125
|
+
{ text: 'Features', url: '#features', target: '_self' },
|
|
126
|
+
{ text: 'ROI Calculator', url: '#roi', target: '_self' }
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
};
|
|
130
|
+
|
|
131
|
+
// 🎯 USE CASE 3: INSTANT PAYMENT FLOW (Problem #3 Solution)
|
|
132
|
+
// Perfect for: Templates, premium features, instant upgrades
|
|
133
|
+
const INSTANT_PAYMENT_CONFIG = {
|
|
134
|
+
actionFunction: 'createTemplate',
|
|
135
|
+
appId: 'template-creator',
|
|
136
|
+
freeAttemptLimit: 5, // Lower to trigger payment faster
|
|
137
|
+
supabase: {
|
|
138
|
+
url: 'your-supabase-url',
|
|
139
|
+
anonKey: 'your-anon-key'
|
|
140
|
+
},
|
|
141
|
+
payment: [{
|
|
142
|
+
provider: 'dodo',
|
|
143
|
+
productId: 'your-product-id',
|
|
144
|
+
mode: 'test'
|
|
145
|
+
}],
|
|
146
|
+
theme: {
|
|
147
|
+
name: 'dark', // Modern, premium feel
|
|
148
|
+
primaryColor: '#7c3aed'
|
|
149
|
+
},
|
|
150
|
+
titleBar: {
|
|
151
|
+
title: '⚡ Template Creator',
|
|
152
|
+
links: [
|
|
153
|
+
{ text: 'Templates', url: '#templates', target: '_self' },
|
|
154
|
+
{ text: 'Pricing', url: '#pricing', target: '_self' }
|
|
155
|
+
]
|
|
156
|
+
},
|
|
157
|
+
successMessage: {
|
|
158
|
+
enabled: true,
|
|
159
|
+
title: 'Template Created!',
|
|
160
|
+
message: 'Your professional template is ready. Download and customize!'
|
|
161
|
+
}
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
// ========================================
|
|
165
|
+
// CHOOSE YOUR CONFIGURATION
|
|
166
|
+
// ========================================
|
|
167
|
+
|
|
168
|
+
// Pick one of the configs above or create your own:
|
|
169
|
+
window.APP_CONFIG = FEEDBACK_INTELLIGENCE_CONFIG; // Change this to your preferred config
|
|
170
|
+
|
|
171
|
+
// Or create a custom configuration:
|
|
172
|
+
/*
|
|
26
173
|
window.APP_CONFIG = {
|
|
27
174
|
// REQUIRED: Function name that gets called
|
|
28
175
|
actionFunction: 'myAction',
|
|
@@ -31,7 +178,7 @@ window.APP_CONFIG = {
|
|
|
31
178
|
appId: 'my-app',
|
|
32
179
|
|
|
33
180
|
// REQUIRED: Number of free attempts before paywall
|
|
34
|
-
|
|
181
|
+
freeAttemptLimit: 3,
|
|
35
182
|
|
|
36
183
|
// REQUIRED: Supabase configuration
|
|
37
184
|
supabase: {
|
|
@@ -40,10 +187,11 @@ window.APP_CONFIG = {
|
|
|
40
187
|
},
|
|
41
188
|
|
|
42
189
|
// REQUIRED: Payment configuration
|
|
43
|
-
payment: {
|
|
190
|
+
payment: [{
|
|
191
|
+
provider: 'dodo',
|
|
44
192
|
productId: 'your-dodo-payments-product-id',
|
|
45
193
|
mode: 'test' // Change to 'live' for production
|
|
46
|
-
},
|
|
194
|
+
}],
|
|
47
195
|
|
|
48
196
|
// OPTIONAL: UI Theme (29 themes available)
|
|
49
197
|
theme: {
|
|
@@ -68,7 +216,7 @@ window.APP_CONFIG = {
|
|
|
68
216
|
message: 'Your action completed successfully!'
|
|
69
217
|
},
|
|
70
218
|
|
|
71
|
-
// OPTIONAL: Feedback collection
|
|
219
|
+
// OPTIONAL: Feedback collection (Problem #2 solution)
|
|
72
220
|
feedback: {
|
|
73
221
|
form: {
|
|
74
222
|
title: 'Quick Feedback',
|
|
@@ -77,12 +225,20 @@ window.APP_CONFIG = {
|
|
|
77
225
|
option2: 'Need more features',
|
|
78
226
|
option3: 'Just testing'
|
|
79
227
|
},
|
|
80
|
-
email:
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
228
|
+
email: [
|
|
229
|
+
{
|
|
230
|
+
provider: 'resend',
|
|
231
|
+
apiKey: 'your-resend-api-key',
|
|
232
|
+
fromEmail: 'hello@yourapp.com'
|
|
233
|
+
}
|
|
234
|
+
]
|
|
84
235
|
}
|
|
85
236
|
};
|
|
237
|
+
*/
|
|
238
|
+
|
|
239
|
+
// ========================================
|
|
240
|
+
// INITIALIZE MONEYBAR
|
|
241
|
+
// ========================================
|
|
86
242
|
|
|
87
243
|
// Initialize MoneyBar with the configuration
|
|
88
244
|
const moneyBar = new MoneyBar(window.APP_CONFIG);
|
|
@@ -98,36 +254,74 @@ moneyBar.attachToButton('#action-btn', (userContext) => {
|
|
|
98
254
|
}
|
|
99
255
|
});
|
|
100
256
|
|
|
101
|
-
//
|
|
102
|
-
|
|
103
|
-
|
|
257
|
+
// ========================================
|
|
258
|
+
// ACTION FUNCTIONS BY USE CASE
|
|
259
|
+
// ========================================
|
|
260
|
+
|
|
261
|
+
// 🎯 USE CASE 1: Value-First Demo Actions
|
|
262
|
+
window.generatePDF = function(userContext) {
|
|
263
|
+
console.log('🎯 VALUE-FIRST: Generating PDF...');
|
|
104
264
|
|
|
105
265
|
if (userContext.isPremium) {
|
|
106
|
-
|
|
107
|
-
|
|
266
|
+
console.log('✅ Premium PDF with all features');
|
|
267
|
+
alert('Premium PDF generated with watermark removal, custom fonts, and high quality!');
|
|
268
|
+
// Your premium PDF generation logic here
|
|
108
269
|
} else {
|
|
109
|
-
|
|
110
|
-
|
|
270
|
+
console.log(`📄 Basic PDF generated. ${userContext.remaining} attempts remaining`);
|
|
271
|
+
alert(`Basic PDF generated! ${userContext.remaining} free attempts left.`);
|
|
272
|
+
// Your basic PDF generation logic here
|
|
273
|
+
}
|
|
274
|
+
};
|
|
275
|
+
|
|
276
|
+
// 🎯 USE CASE 2: Feedback Intelligence Actions
|
|
277
|
+
window.runAnalysis = function(userContext) {
|
|
278
|
+
console.log('🎯 FEEDBACK INTELLIGENCE: Running analysis...');
|
|
279
|
+
|
|
280
|
+
if (userContext.isPremium) {
|
|
281
|
+
console.log('✅ Full analytics suite access');
|
|
282
|
+
alert('Complete analysis ready! Access to all metrics, exports, and AI insights.');
|
|
283
|
+
// Your premium analytics logic here
|
|
284
|
+
} else {
|
|
285
|
+
console.log(`📊 Basic analysis complete. ${userContext.remaining} attempts remaining`);
|
|
286
|
+
alert(`Analysis complete! Limited data shown. ${userContext.remaining} attempts left.`);
|
|
287
|
+
// Your basic analytics logic here
|
|
111
288
|
}
|
|
112
289
|
};
|
|
113
290
|
|
|
114
|
-
//
|
|
291
|
+
// 🎯 USE CASE 3: Instant Payment Actions
|
|
115
292
|
window.createTemplate = function(userContext) {
|
|
293
|
+
console.log('🎯 INSTANT PAYMENT: Creating template...');
|
|
294
|
+
|
|
116
295
|
if (userContext.isPremium) {
|
|
117
|
-
console.log('
|
|
118
|
-
alert('Premium template created!');
|
|
296
|
+
console.log('✅ Premium template with full customization');
|
|
297
|
+
alert('Premium template created! Full customization, commercial license, and PSD files included.');
|
|
298
|
+
// Your premium template logic here
|
|
119
299
|
} else {
|
|
120
|
-
console.log(
|
|
121
|
-
alert(`
|
|
300
|
+
console.log(`🎨 Basic template created. ${userContext.remaining} attempts remaining`);
|
|
301
|
+
alert(`Template created! Basic version only. ${userContext.remaining} attempts left.`);
|
|
302
|
+
// Your basic template logic here
|
|
122
303
|
}
|
|
123
304
|
};
|
|
124
305
|
|
|
125
|
-
|
|
306
|
+
// 🎯 DEFAULT: Fallback Action
|
|
307
|
+
window.myAction = function(userContext) {
|
|
308
|
+
console.log('User context:', userContext);
|
|
309
|
+
|
|
126
310
|
if (userContext.isPremium) {
|
|
127
|
-
|
|
128
|
-
//
|
|
311
|
+
alert('Premium features unlocked!');
|
|
312
|
+
// Your premium functionality here
|
|
129
313
|
} else {
|
|
130
|
-
|
|
131
|
-
//
|
|
314
|
+
alert(`Free trial: ${userContext.remaining} uses left`);
|
|
315
|
+
// Your free tier functionality here
|
|
132
316
|
}
|
|
133
|
-
};
|
|
317
|
+
};
|
|
318
|
+
|
|
319
|
+
// ========================================
|
|
320
|
+
// QUICK REFERENCE: Available Themes
|
|
321
|
+
// ========================================
|
|
322
|
+
|
|
323
|
+
// Light themes: light, cupcake, bumblebee, emerald, corporate, garden
|
|
324
|
+
// Dark themes: dark, synthwave, retro, cyberpunk, valentine, halloween
|
|
325
|
+
// Professional: corporate, business, luxury
|
|
326
|
+
// Creative: fantasy, cyberpunk, synthwave
|
|
327
|
+
// And 20+ more themes available!
|
package/package.json
CHANGED
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@moneybar.online/moneybar",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.4.0",
|
|
4
4
|
"description": "The navbar of monetization. Fix the 3 money-blocking stages: forced sign-ins, silent drop-offs, and broken payment flows. Turn browsers into buyers.",
|
|
5
|
-
"main": "dist/index.
|
|
5
|
+
"main": "dist/index.esm.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
7
7
|
"browser": "dist/index.browser.js",
|
|
8
|
-
"unpkg": "dist/index.
|
|
8
|
+
"unpkg": "dist/index.bundle.js",
|
|
9
9
|
"types": "dist/index.d.ts",
|
|
10
10
|
"type": "module",
|
|
11
11
|
"exports": {
|
|
12
12
|
".": {
|
|
13
13
|
"import": "./dist/index.esm.js",
|
|
14
|
-
"require": "./dist/index.cjs.js",
|
|
15
14
|
"browser": "./dist/index.browser.js",
|
|
16
15
|
"types": "./dist/index.d.ts"
|
|
17
16
|
}
|
package/src/index.ts
CHANGED
|
@@ -23,13 +23,13 @@ import { createClient } from '@supabase/supabase-js';
|
|
|
23
23
|
*
|
|
24
24
|
* const moneyBar = new MoneyBar({
|
|
25
25
|
* appId: 'my-pdf-app',
|
|
26
|
-
*
|
|
26
|
+
* freeAttemptLimit: 3,
|
|
27
27
|
* supabase: { url: 'https://xyz.supabase.co', anonKey: 'anon_key' },
|
|
28
28
|
* payment: { productId: 'prod_xyz' }
|
|
29
29
|
* });
|
|
30
30
|
*
|
|
31
31
|
* // Single button - handles all monetization automatically
|
|
32
|
-
* moneyBar.attachToButton('#
|
|
32
|
+
* moneyBar.attachToButton('#action-btn', (userContext) => {
|
|
33
33
|
* // Your action logic here - with user context for personalization
|
|
34
34
|
* if (userContext.isPremium) {
|
|
35
35
|
* generatePremiumPDF();
|
|
@@ -243,10 +243,10 @@ export class MoneyBar {
|
|
|
243
243
|
|
|
244
244
|
const status: DownloadStatus = {
|
|
245
245
|
currentCount: count,
|
|
246
|
-
limit: this.config.
|
|
246
|
+
limit: this.config.freeAttemptLimit,
|
|
247
247
|
isPremium,
|
|
248
248
|
isAuthenticated: !!this.currentUser,
|
|
249
|
-
remaining: Math.max(0, this.config.
|
|
249
|
+
remaining: Math.max(0, this.config.freeAttemptLimit - count)
|
|
250
250
|
};
|
|
251
251
|
|
|
252
252
|
// Cache the status
|
|
@@ -259,10 +259,10 @@ export class MoneyBar {
|
|
|
259
259
|
// Return safe defaults on error
|
|
260
260
|
const errorStatus: DownloadStatus = {
|
|
261
261
|
currentCount: 0,
|
|
262
|
-
limit: this.config.
|
|
262
|
+
limit: this.config.freeAttemptLimit,
|
|
263
263
|
isPremium: false,
|
|
264
264
|
isAuthenticated: false,
|
|
265
|
-
remaining: this.config.
|
|
265
|
+
remaining: this.config.freeAttemptLimit
|
|
266
266
|
};
|
|
267
267
|
|
|
268
268
|
// Cache error status for short time to avoid repeated failures
|
|
@@ -333,26 +333,37 @@ export class MoneyBar {
|
|
|
333
333
|
throw new Error('Payment configuration not provided');
|
|
334
334
|
}
|
|
335
335
|
|
|
336
|
+
const payment = this.config.payment?.find(p => p.provider === 'dodo');
|
|
337
|
+
if (!payment) {
|
|
338
|
+
throw new Error('No dodo payment provider configured');
|
|
339
|
+
}
|
|
340
|
+
|
|
336
341
|
const requestBody = {
|
|
337
342
|
email: this.currentUser.email,
|
|
338
|
-
product_id:
|
|
339
|
-
mode:
|
|
343
|
+
product_id: payment.productId,
|
|
344
|
+
mode: payment.mode || 'test',
|
|
340
345
|
app_id: this.config.appId,
|
|
341
346
|
return_url: `${window.location.origin}${window.location.pathname}?payment=success`
|
|
342
347
|
};
|
|
343
348
|
|
|
344
|
-
console.log(`🔥 [
|
|
349
|
+
console.log(`🔥 [PAYMENT API] createPayment called for provider: ${payment.provider}, email: ${this.currentUser.email} | Time: ${new Date().toISOString()}`);
|
|
345
350
|
|
|
346
351
|
try {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
'
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
352
|
+
// Route to appropriate payment API based on provider
|
|
353
|
+
let response;
|
|
354
|
+
if (payment.provider === 'dodo') {
|
|
355
|
+
response = await fetch(`${this.config.supabase.url}/functions/v1/create-payment`, {
|
|
356
|
+
method: 'POST',
|
|
357
|
+
headers: {
|
|
358
|
+
'Content-Type': 'application/json',
|
|
359
|
+
'Authorization': `Bearer ${this.config.supabase.anonKey}`
|
|
360
|
+
},
|
|
361
|
+
body: JSON.stringify(requestBody)
|
|
362
|
+
});
|
|
363
|
+
} else {
|
|
364
|
+
throw new Error(`Payment provider '${payment.provider}' is not yet supported`);
|
|
365
|
+
}
|
|
366
|
+
console.log(`🔥 [PAYMENT API] createPayment response for ${payment.provider}: ${response.status}`);
|
|
356
367
|
|
|
357
368
|
if (this.config.options?.debug) {
|
|
358
369
|
//console.log('🔍 DEBUG: createPayment response status:', response.status);
|
|
@@ -595,8 +606,8 @@ export class MoneyBar {
|
|
|
595
606
|
const newCount = await this.incrementDownloadCount();
|
|
596
607
|
|
|
597
608
|
// Double-check: if server returned count exceeding limit, something went wrong
|
|
598
|
-
if (newCount > this.config.
|
|
599
|
-
console.error(`⚠️ Server returned count (${newCount}) exceeding limit (${this.config.
|
|
609
|
+
if (newCount > this.config.freeAttemptLimit) {
|
|
610
|
+
console.error(`⚠️ Server returned count (${newCount}) exceeding limit (${this.config.freeAttemptLimit})`);
|
|
600
611
|
// Don't update UI with invalid state
|
|
601
612
|
return;
|
|
602
613
|
}
|
|
@@ -2441,7 +2452,25 @@ export class MoneyBar {
|
|
|
2441
2452
|
}
|
|
2442
2453
|
|
|
2443
2454
|
private async sendFeedbackEmail(feedbackData: any): Promise<void> {
|
|
2444
|
-
|
|
2455
|
+
// Get email config - handle both new array format and legacy format
|
|
2456
|
+
let emailConfig;
|
|
2457
|
+
if (this.config.feedback?.email) {
|
|
2458
|
+
// New array format - use first provider (typically resend)
|
|
2459
|
+
if (Array.isArray(this.config.feedback.email)) {
|
|
2460
|
+
emailConfig = this.config.feedback.email[0];
|
|
2461
|
+
} else {
|
|
2462
|
+
// Legacy format fallback
|
|
2463
|
+
emailConfig = this.config.feedback.email as any;
|
|
2464
|
+
}
|
|
2465
|
+
} else if (this.config.email) {
|
|
2466
|
+
// Deprecated legacy email config
|
|
2467
|
+
emailConfig = {
|
|
2468
|
+
provider: 'resend',
|
|
2469
|
+
apiKey: (this.config.email as any).resendApiKey,
|
|
2470
|
+
fromEmail: (this.config.email as any).fromEmail
|
|
2471
|
+
};
|
|
2472
|
+
}
|
|
2473
|
+
|
|
2445
2474
|
if (!emailConfig) {
|
|
2446
2475
|
throw new Error('Email configuration not available');
|
|
2447
2476
|
}
|
|
@@ -2456,19 +2485,25 @@ Timestamp: ${feedbackData.timestamp}
|
|
|
2456
2485
|
User Agent: ${feedbackData.userAgent}
|
|
2457
2486
|
`.trim();
|
|
2458
2487
|
|
|
2459
|
-
|
|
2460
|
-
|
|
2461
|
-
|
|
2462
|
-
|
|
2463
|
-
'
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2488
|
+
// Handle different email providers
|
|
2489
|
+
let response;
|
|
2490
|
+
if (emailConfig.provider === 'resend' || !emailConfig.provider) {
|
|
2491
|
+
response = await fetch('https://api.resend.com/emails', {
|
|
2492
|
+
method: 'POST',
|
|
2493
|
+
headers: {
|
|
2494
|
+
'Content-Type': 'application/json',
|
|
2495
|
+
'Authorization': `Bearer ${emailConfig.apiKey || (emailConfig as any).resendApiKey}`
|
|
2496
|
+
},
|
|
2497
|
+
body: JSON.stringify({
|
|
2498
|
+
from: emailConfig.fromEmail,
|
|
2499
|
+
to: [emailConfig.fromEmail], // Send feedback to yourself
|
|
2500
|
+
subject: `Feedback from ${this.config.appId}`,
|
|
2501
|
+
text: emailBody
|
|
2502
|
+
})
|
|
2503
|
+
});
|
|
2504
|
+
} else {
|
|
2505
|
+
throw new Error(`Unsupported email provider: ${emailConfig.provider}`);
|
|
2506
|
+
}
|
|
2472
2507
|
|
|
2473
2508
|
if (!response.ok) {
|
|
2474
2509
|
throw new Error(`Email API error: ${response.status}`);
|
|
@@ -2959,8 +2994,8 @@ User Agent: ${feedbackData.userAgent}
|
|
|
2959
2994
|
if (!this.config.appId) throw new Error('appId is required');
|
|
2960
2995
|
if (!this.config.supabase?.url) throw new Error('supabase.url is required');
|
|
2961
2996
|
if (!this.config.supabase?.anonKey) throw new Error('supabase.anonKey is required');
|
|
2962
|
-
if (typeof this.config.
|
|
2963
|
-
throw new Error('
|
|
2997
|
+
if (typeof this.config.freeAttemptLimit !== 'number' || this.config.freeAttemptLimit < 0) {
|
|
2998
|
+
throw new Error('freeAttemptLimit must be a non-negative number');
|
|
2964
2999
|
}
|
|
2965
3000
|
}
|
|
2966
3001
|
|
|
@@ -2986,7 +3021,15 @@ User Agent: ${feedbackData.userAgent}
|
|
|
2986
3021
|
}
|
|
2987
3022
|
|
|
2988
3023
|
// Validate product ID format
|
|
2989
|
-
const
|
|
3024
|
+
const payment = this.config.payment?.find(p => p.provider === 'dodo');
|
|
3025
|
+
if (!payment) {
|
|
3026
|
+
this.paymentConnectionFailed = true;
|
|
3027
|
+
if (this.config.options?.debug) {
|
|
3028
|
+
console.warn('No dodo payment provider configured');
|
|
3029
|
+
}
|
|
3030
|
+
return;
|
|
3031
|
+
}
|
|
3032
|
+
const productId = payment.productId;
|
|
2990
3033
|
if (!productId || !productId.startsWith('pdt_') || productId.length < 10) {
|
|
2991
3034
|
this.paymentConnectionFailed = true;
|
|
2992
3035
|
if (this.config.options?.debug) {
|
package/src/types.ts
CHANGED
|
@@ -3,7 +3,7 @@ export interface MoneyBarConfig {
|
|
|
3
3
|
appId: string;
|
|
4
4
|
|
|
5
5
|
/** Number of free attempts allowed before paywall */
|
|
6
|
-
|
|
6
|
+
freeAttemptLimit: number;
|
|
7
7
|
|
|
8
8
|
/** Supabase configuration */
|
|
9
9
|
supabase: {
|
|
@@ -11,11 +11,14 @@ export interface MoneyBarConfig {
|
|
|
11
11
|
anonKey: string;
|
|
12
12
|
};
|
|
13
13
|
|
|
14
|
-
/**
|
|
15
|
-
payment?: {
|
|
14
|
+
/** Payment configuration - extensible for multiple providers */
|
|
15
|
+
payment?: Array<{
|
|
16
|
+
provider: 'dodo' | 'stripe' | 'paypal' | 'square' | 'paddle'; // Extensible for future providers
|
|
16
17
|
productId: string;
|
|
17
18
|
mode?: 'test' | 'live';
|
|
18
|
-
|
|
19
|
+
apiKey?: string; // For providers that need API keys
|
|
20
|
+
publishableKey?: string; // For client-side keys (Stripe, etc.)
|
|
21
|
+
}>;
|
|
19
22
|
|
|
20
23
|
/** Optional: Feedback form configuration */
|
|
21
24
|
feedback?: {
|
|
@@ -26,10 +29,11 @@ export interface MoneyBarConfig {
|
|
|
26
29
|
option2: string;
|
|
27
30
|
option3: string;
|
|
28
31
|
};
|
|
29
|
-
email: {
|
|
30
|
-
|
|
32
|
+
email: Array<{
|
|
33
|
+
provider: 'resend' | 'sendgrid' | 'mailgun' | 'ses'; // Extensible for future providers
|
|
34
|
+
apiKey: string;
|
|
31
35
|
fromEmail: string;
|
|
32
|
-
}
|
|
36
|
+
}>;
|
|
33
37
|
};
|
|
34
38
|
|
|
35
39
|
/** @deprecated Use feedback.email instead - Email service configuration (for feedback and notifications) */
|