@drawbridge/drawbridge-utils 0.0.102 → 0.0.104
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/ai.cjs +4 -0
- package/dist/ai.js +4 -0
- package/dist/billing.cjs +16 -0
- package/dist/billing.d.cts +7 -1
- package/dist/billing.d.ts +7 -1
- package/dist/billing.js +10 -0
- package/dist/features.cjs +5 -0
- package/dist/features.d.cts +5 -0
- package/dist/features.d.ts +5 -0
- package/dist/features.js +5 -0
- package/dist/fields-validate.cjs +121 -0
- package/dist/fields-validate.d.cts +116 -0
- package/dist/fields-validate.d.ts +116 -0
- package/dist/fields-validate.js +94 -0
- package/dist/plans.cjs +40 -8
- package/dist/plans.d.cts +58 -8
- package/dist/plans.d.ts +58 -8
- package/dist/plans.js +38 -7
- package/dist/pricing.cjs +807 -0
- package/dist/pricing.d.cts +72 -0
- package/dist/pricing.d.ts +72 -0
- package/dist/pricing.js +757 -0
- package/package.json +14 -3
package/dist/plans.cjs
CHANGED
|
@@ -32,7 +32,8 @@ __export(plans_exports, {
|
|
|
32
32
|
conversionRate: () => conversionRate,
|
|
33
33
|
free: () => free,
|
|
34
34
|
plans: () => plans,
|
|
35
|
-
resolvePlan: () => resolvePlan
|
|
35
|
+
resolvePlan: () => resolvePlan,
|
|
36
|
+
unitAmountDecimal: () => unitAmountDecimal
|
|
36
37
|
});
|
|
37
38
|
module.exports = __toCommonJS(plans_exports);
|
|
38
39
|
|
|
@@ -109,6 +110,11 @@ var connection = {
|
|
|
109
110
|
error: "Plan does not include Mailchimp connection",
|
|
110
111
|
feature: "Mailchimp connection"
|
|
111
112
|
},
|
|
113
|
+
sender: {
|
|
114
|
+
key: "organization:connection:sender",
|
|
115
|
+
error: "Plan does not include a verified sending domain",
|
|
116
|
+
feature: "Sending domain connection"
|
|
117
|
+
},
|
|
112
118
|
sendgrid: {
|
|
113
119
|
key: "organization:connection:sendgrid",
|
|
114
120
|
error: "Plan does not include SendGrid connection",
|
|
@@ -262,6 +268,15 @@ var featuresFor = (array = []) => Object.values({
|
|
|
262
268
|
},
|
|
263
269
|
{ denied: {}, granted: {} }
|
|
264
270
|
);
|
|
271
|
+
var overage = (actionCents) => ({
|
|
272
|
+
actionCents,
|
|
273
|
+
overages: { actions: String(actionCents) }
|
|
274
|
+
});
|
|
275
|
+
var unitAmountDecimal = (cents) => {
|
|
276
|
+
const value = Number(cents);
|
|
277
|
+
if (cents == null || !Number.isFinite(value)) throw new Error(`Invalid overage rate: ${cents}`);
|
|
278
|
+
return String(value);
|
|
279
|
+
};
|
|
265
280
|
var all = {
|
|
266
281
|
features: (array = []) => featuresFor([
|
|
267
282
|
connection.mailchimp.key,
|
|
@@ -322,7 +337,11 @@ var free = {
|
|
|
322
337
|
};
|
|
323
338
|
var plans = {
|
|
324
339
|
DB00002: {
|
|
325
|
-
|
|
340
|
+
// A verified sending domain is a PAID capability: free plans cannot send
|
|
341
|
+
// lead-facing email at all (the send path gates on an active
|
|
342
|
+
// subscription), so granting it there would offer a domain that can
|
|
343
|
+
// never send from.
|
|
344
|
+
features: all.features([connection.sender.key, organization.members.key]),
|
|
326
345
|
limits: all.limits({ actions: 5e3, members: 3, storage: gigabyte * 10 }),
|
|
327
346
|
marketing: {
|
|
328
347
|
description: "Tools to fine-tune campaigns and improve lead quality.",
|
|
@@ -337,12 +356,13 @@ var plans = {
|
|
|
337
356
|
["Storage", "10GB"]
|
|
338
357
|
]
|
|
339
358
|
},
|
|
340
|
-
|
|
359
|
+
...overage(2.5),
|
|
341
360
|
title: "Starter",
|
|
342
361
|
conversion: 2
|
|
343
362
|
},
|
|
344
363
|
DB00003: {
|
|
345
364
|
features: all.features([
|
|
365
|
+
connection.sender.key,
|
|
346
366
|
organization.advertisements.key,
|
|
347
367
|
organization.analytics.key,
|
|
348
368
|
organization.members.key,
|
|
@@ -367,12 +387,13 @@ var plans = {
|
|
|
367
387
|
["Storage", "20GB"]
|
|
368
388
|
]
|
|
369
389
|
},
|
|
370
|
-
|
|
390
|
+
...overage(2),
|
|
371
391
|
title: "Pro",
|
|
372
392
|
conversion: 1.5
|
|
373
393
|
},
|
|
374
394
|
DB00004: {
|
|
375
395
|
features: all.features([
|
|
396
|
+
connection.sender.key,
|
|
376
397
|
organization.advertisements.key,
|
|
377
398
|
organization.analytics.key,
|
|
378
399
|
organization.members.key,
|
|
@@ -397,12 +418,13 @@ var plans = {
|
|
|
397
418
|
["Storage", "50GB"]
|
|
398
419
|
]
|
|
399
420
|
},
|
|
400
|
-
|
|
421
|
+
...overage(1.85),
|
|
401
422
|
title: "Premium",
|
|
402
423
|
conversion: 1
|
|
403
424
|
},
|
|
404
425
|
DB00005: {
|
|
405
426
|
features: all.features([
|
|
427
|
+
connection.sender.key,
|
|
406
428
|
organization.advertisements.key,
|
|
407
429
|
organization.analytics.key,
|
|
408
430
|
organization.members.key,
|
|
@@ -427,7 +449,7 @@ var plans = {
|
|
|
427
449
|
["Storage", "100GB"]
|
|
428
450
|
]
|
|
429
451
|
},
|
|
430
|
-
|
|
452
|
+
...overage(1.5),
|
|
431
453
|
title: "Elite",
|
|
432
454
|
conversion: 0.5
|
|
433
455
|
}
|
|
@@ -443,8 +465,17 @@ var resolvePlan = (subscription) => {
|
|
|
443
465
|
// infinite when a deal does not name it.
|
|
444
466
|
conversion: custom.conversion ?? free.conversion,
|
|
445
467
|
custom: true,
|
|
446
|
-
|
|
468
|
+
// A custom plan is a negotiated PAID deal, so it carries the paid-tier
|
|
469
|
+
// baseline whether or not the deal thought to name it. Today that is the
|
|
470
|
+
// sending domain: every catalog paid tier grants it, and a custom plan
|
|
471
|
+
// silently lacking it would be a support ticket, not a pricing decision.
|
|
472
|
+
features: all.features([connection.sender.key, ...((_a = custom.features) == null ? void 0 : _a.granted) || []]),
|
|
447
473
|
limits: all.limits(((_b = custom.limits) == null ? void 0 : _b.organization) || {}),
|
|
474
|
+
// A custom plan stores its overage BARE on `custom.overages` — a different
|
|
475
|
+
// shape from the catalog's nested one. Number() so a deal stored as a string
|
|
476
|
+
// still resolves to cents-per-action; an unnamed overage stays undefined
|
|
477
|
+
// (it bills nothing) rather than becoming NaN.
|
|
478
|
+
actionCents: custom.overages == null ? void 0 : Number(custom.overages),
|
|
448
479
|
overages: { actions: custom.overages },
|
|
449
480
|
title: custom.title || "Custom"
|
|
450
481
|
};
|
|
@@ -458,5 +489,6 @@ var conversionRate = (subscription) => {
|
|
|
458
489
|
conversionRate,
|
|
459
490
|
free,
|
|
460
491
|
plans,
|
|
461
|
-
resolvePlan
|
|
492
|
+
resolvePlan,
|
|
493
|
+
unitAmountDecimal
|
|
462
494
|
});
|
package/dist/plans.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { organization, page,
|
|
1
|
+
import { connection, organization, page, fields, field } from './features.cjs';
|
|
2
2
|
import { infinite, gigabyte } from './index.cjs';
|
|
3
3
|
import 'currency-codes';
|
|
4
4
|
import 'nanoid';
|
|
@@ -31,6 +31,40 @@ const featuresFor = ( array = [] ) => Object.values({
|
|
|
31
31
|
{ denied : {}, granted : {} }
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
+
// Overage pricing, unit-explicit.
|
|
35
|
+
//
|
|
36
|
+
// `actionCents` is CENTS PER ACTION, as a number: 2.5 = $0.025. Before
|
|
37
|
+
// 2026-05-31 the same rate was encoded as dollars-per-1,000-actions, Stripe read
|
|
38
|
+
// it as per-action, and every paid tier billed 10x. `overages.actions` — the
|
|
39
|
+
// string this used to be the only name for — is kept as a byte-identical alias
|
|
40
|
+
// so consumers can be pin-bumped in any order; drop it once they all read
|
|
41
|
+
// `actionCents`.
|
|
42
|
+
//
|
|
43
|
+
// Sub-cent precision is deliberate: Premium's 1.85¢ does not fit integer cents
|
|
44
|
+
// (2¢ is +8%, 1¢ is −46%).
|
|
45
|
+
const overage = ( actionCents ) => ({
|
|
46
|
+
actionCents,
|
|
47
|
+
overages : { actions : String( actionCents ) }
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Cents → Stripe's `unit_amount_decimal`.
|
|
51
|
+
//
|
|
52
|
+
// The Stripe boundary MUST use `unit_amount_decimal`, not `unit_amount`:
|
|
53
|
+
// standalone invoice items reject a top-level `unit_amount` with "Received
|
|
54
|
+
// unknown parameter", which is what left invoice drafts stuck on 2026-08-06.
|
|
55
|
+
// It is a decimal string of CENTS, so 2.5 → '2.5' — no scaling, no rounding.
|
|
56
|
+
const unitAmountDecimal = ( cents ) => {
|
|
57
|
+
|
|
58
|
+
const value = Number( cents );
|
|
59
|
+
|
|
60
|
+
// `cents == null` is checked separately because Number( null ) is 0 — an
|
|
61
|
+
// unnamed rate must fail loudly, not silently bill nothing.
|
|
62
|
+
if( cents == null || ! Number.isFinite( value ) ) throw new Error( `Invalid overage rate: ${ cents }` );
|
|
63
|
+
|
|
64
|
+
return String( value );
|
|
65
|
+
|
|
66
|
+
};
|
|
67
|
+
|
|
34
68
|
const all = {
|
|
35
69
|
features : ( array = [] ) => featuresFor([
|
|
36
70
|
connection.mailchimp.key,
|
|
@@ -93,7 +127,11 @@ const free = {
|
|
|
93
127
|
|
|
94
128
|
const plans = {
|
|
95
129
|
DB00002 : {
|
|
96
|
-
|
|
130
|
+
// A verified sending domain is a PAID capability: free plans cannot send
|
|
131
|
+
// lead-facing email at all (the send path gates on an active
|
|
132
|
+
// subscription), so granting it there would offer a domain that can
|
|
133
|
+
// never send from.
|
|
134
|
+
features : all.features([ connection.sender.key, organization.members.key ]),
|
|
97
135
|
limits : all.limits({ actions : 5000, members : 3, storage : gigabyte * 10 }),
|
|
98
136
|
marketing : {
|
|
99
137
|
description : 'Tools to fine-tune campaigns and improve lead quality.',
|
|
@@ -108,12 +146,13 @@ const plans = {
|
|
|
108
146
|
[ 'Storage', '10GB' ]
|
|
109
147
|
]
|
|
110
148
|
},
|
|
111
|
-
|
|
149
|
+
...overage( 2.5 ),
|
|
112
150
|
title : 'Starter',
|
|
113
151
|
conversion : 2
|
|
114
152
|
},
|
|
115
153
|
DB00003 : {
|
|
116
154
|
features : all.features([
|
|
155
|
+
connection.sender.key,
|
|
117
156
|
organization.advertisements.key,
|
|
118
157
|
organization.analytics.key,
|
|
119
158
|
organization.members.key,
|
|
@@ -138,12 +177,13 @@ const plans = {
|
|
|
138
177
|
[ 'Storage', '20GB' ]
|
|
139
178
|
]
|
|
140
179
|
},
|
|
141
|
-
|
|
180
|
+
...overage( 2 ),
|
|
142
181
|
title : 'Pro',
|
|
143
182
|
conversion : 1.5
|
|
144
183
|
},
|
|
145
184
|
DB00004 : {
|
|
146
185
|
features : all.features([
|
|
186
|
+
connection.sender.key,
|
|
147
187
|
organization.advertisements.key,
|
|
148
188
|
organization.analytics.key,
|
|
149
189
|
organization.members.key,
|
|
@@ -168,12 +208,13 @@ const plans = {
|
|
|
168
208
|
[ 'Storage', '50GB' ]
|
|
169
209
|
]
|
|
170
210
|
},
|
|
171
|
-
|
|
211
|
+
...overage( 1.85 ),
|
|
172
212
|
title : 'Premium',
|
|
173
213
|
conversion : 1
|
|
174
214
|
},
|
|
175
215
|
DB00005 : {
|
|
176
216
|
features : all.features([
|
|
217
|
+
connection.sender.key,
|
|
177
218
|
organization.advertisements.key,
|
|
178
219
|
organization.analytics.key,
|
|
179
220
|
organization.members.key,
|
|
@@ -198,7 +239,7 @@ const plans = {
|
|
|
198
239
|
[ 'Storage', '100GB' ]
|
|
199
240
|
]
|
|
200
241
|
},
|
|
201
|
-
|
|
242
|
+
...overage( 1.5 ),
|
|
202
243
|
title : 'Elite',
|
|
203
244
|
conversion : 0.5
|
|
204
245
|
},
|
|
@@ -230,8 +271,17 @@ const resolvePlan = ( subscription ) => {
|
|
|
230
271
|
// infinite when a deal does not name it.
|
|
231
272
|
conversion : custom.conversion ?? free.conversion,
|
|
232
273
|
custom : true,
|
|
233
|
-
|
|
274
|
+
// A custom plan is a negotiated PAID deal, so it carries the paid-tier
|
|
275
|
+
// baseline whether or not the deal thought to name it. Today that is the
|
|
276
|
+
// sending domain: every catalog paid tier grants it, and a custom plan
|
|
277
|
+
// silently lacking it would be a support ticket, not a pricing decision.
|
|
278
|
+
features : all.features([ connection.sender.key, ...( custom.features?.granted || [] ) ]),
|
|
234
279
|
limits : all.limits( custom.limits?.organization || {} ),
|
|
280
|
+
// A custom plan stores its overage BARE on `custom.overages` — a different
|
|
281
|
+
// shape from the catalog's nested one. Number() so a deal stored as a string
|
|
282
|
+
// still resolves to cents-per-action; an unnamed overage stays undefined
|
|
283
|
+
// (it bills nothing) rather than becoming NaN.
|
|
284
|
+
actionCents : custom.overages == null ? undefined : Number( custom.overages ),
|
|
235
285
|
overages : { actions : custom.overages },
|
|
236
286
|
title : custom.title || 'Custom'
|
|
237
287
|
};
|
|
@@ -250,4 +300,4 @@ const conversionRate = ( subscription ) =>
|
|
|
250
300
|
resolvePlan( subscription )?.conversion
|
|
251
301
|
?? free.conversion;
|
|
252
302
|
|
|
253
|
-
export { conversionRate, free, plans, resolvePlan };
|
|
303
|
+
export { conversionRate, free, plans, resolvePlan, unitAmountDecimal };
|
package/dist/plans.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { organization, page,
|
|
1
|
+
import { connection, organization, page, fields, field } from './features.js';
|
|
2
2
|
import { infinite, gigabyte } from './index.js';
|
|
3
3
|
import 'currency-codes';
|
|
4
4
|
import 'nanoid';
|
|
@@ -31,6 +31,40 @@ const featuresFor = ( array = [] ) => Object.values({
|
|
|
31
31
|
{ denied : {}, granted : {} }
|
|
32
32
|
);
|
|
33
33
|
|
|
34
|
+
// Overage pricing, unit-explicit.
|
|
35
|
+
//
|
|
36
|
+
// `actionCents` is CENTS PER ACTION, as a number: 2.5 = $0.025. Before
|
|
37
|
+
// 2026-05-31 the same rate was encoded as dollars-per-1,000-actions, Stripe read
|
|
38
|
+
// it as per-action, and every paid tier billed 10x. `overages.actions` — the
|
|
39
|
+
// string this used to be the only name for — is kept as a byte-identical alias
|
|
40
|
+
// so consumers can be pin-bumped in any order; drop it once they all read
|
|
41
|
+
// `actionCents`.
|
|
42
|
+
//
|
|
43
|
+
// Sub-cent precision is deliberate: Premium's 1.85¢ does not fit integer cents
|
|
44
|
+
// (2¢ is +8%, 1¢ is −46%).
|
|
45
|
+
const overage = ( actionCents ) => ({
|
|
46
|
+
actionCents,
|
|
47
|
+
overages : { actions : String( actionCents ) }
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
// Cents → Stripe's `unit_amount_decimal`.
|
|
51
|
+
//
|
|
52
|
+
// The Stripe boundary MUST use `unit_amount_decimal`, not `unit_amount`:
|
|
53
|
+
// standalone invoice items reject a top-level `unit_amount` with "Received
|
|
54
|
+
// unknown parameter", which is what left invoice drafts stuck on 2026-08-06.
|
|
55
|
+
// It is a decimal string of CENTS, so 2.5 → '2.5' — no scaling, no rounding.
|
|
56
|
+
const unitAmountDecimal = ( cents ) => {
|
|
57
|
+
|
|
58
|
+
const value = Number( cents );
|
|
59
|
+
|
|
60
|
+
// `cents == null` is checked separately because Number( null ) is 0 — an
|
|
61
|
+
// unnamed rate must fail loudly, not silently bill nothing.
|
|
62
|
+
if( cents == null || ! Number.isFinite( value ) ) throw new Error( `Invalid overage rate: ${ cents }` );
|
|
63
|
+
|
|
64
|
+
return String( value );
|
|
65
|
+
|
|
66
|
+
};
|
|
67
|
+
|
|
34
68
|
const all = {
|
|
35
69
|
features : ( array = [] ) => featuresFor([
|
|
36
70
|
connection.mailchimp.key,
|
|
@@ -93,7 +127,11 @@ const free = {
|
|
|
93
127
|
|
|
94
128
|
const plans = {
|
|
95
129
|
DB00002 : {
|
|
96
|
-
|
|
130
|
+
// A verified sending domain is a PAID capability: free plans cannot send
|
|
131
|
+
// lead-facing email at all (the send path gates on an active
|
|
132
|
+
// subscription), so granting it there would offer a domain that can
|
|
133
|
+
// never send from.
|
|
134
|
+
features : all.features([ connection.sender.key, organization.members.key ]),
|
|
97
135
|
limits : all.limits({ actions : 5000, members : 3, storage : gigabyte * 10 }),
|
|
98
136
|
marketing : {
|
|
99
137
|
description : 'Tools to fine-tune campaigns and improve lead quality.',
|
|
@@ -108,12 +146,13 @@ const plans = {
|
|
|
108
146
|
[ 'Storage', '10GB' ]
|
|
109
147
|
]
|
|
110
148
|
},
|
|
111
|
-
|
|
149
|
+
...overage( 2.5 ),
|
|
112
150
|
title : 'Starter',
|
|
113
151
|
conversion : 2
|
|
114
152
|
},
|
|
115
153
|
DB00003 : {
|
|
116
154
|
features : all.features([
|
|
155
|
+
connection.sender.key,
|
|
117
156
|
organization.advertisements.key,
|
|
118
157
|
organization.analytics.key,
|
|
119
158
|
organization.members.key,
|
|
@@ -138,12 +177,13 @@ const plans = {
|
|
|
138
177
|
[ 'Storage', '20GB' ]
|
|
139
178
|
]
|
|
140
179
|
},
|
|
141
|
-
|
|
180
|
+
...overage( 2 ),
|
|
142
181
|
title : 'Pro',
|
|
143
182
|
conversion : 1.5
|
|
144
183
|
},
|
|
145
184
|
DB00004 : {
|
|
146
185
|
features : all.features([
|
|
186
|
+
connection.sender.key,
|
|
147
187
|
organization.advertisements.key,
|
|
148
188
|
organization.analytics.key,
|
|
149
189
|
organization.members.key,
|
|
@@ -168,12 +208,13 @@ const plans = {
|
|
|
168
208
|
[ 'Storage', '50GB' ]
|
|
169
209
|
]
|
|
170
210
|
},
|
|
171
|
-
|
|
211
|
+
...overage( 1.85 ),
|
|
172
212
|
title : 'Premium',
|
|
173
213
|
conversion : 1
|
|
174
214
|
},
|
|
175
215
|
DB00005 : {
|
|
176
216
|
features : all.features([
|
|
217
|
+
connection.sender.key,
|
|
177
218
|
organization.advertisements.key,
|
|
178
219
|
organization.analytics.key,
|
|
179
220
|
organization.members.key,
|
|
@@ -198,7 +239,7 @@ const plans = {
|
|
|
198
239
|
[ 'Storage', '100GB' ]
|
|
199
240
|
]
|
|
200
241
|
},
|
|
201
|
-
|
|
242
|
+
...overage( 1.5 ),
|
|
202
243
|
title : 'Elite',
|
|
203
244
|
conversion : 0.5
|
|
204
245
|
},
|
|
@@ -230,8 +271,17 @@ const resolvePlan = ( subscription ) => {
|
|
|
230
271
|
// infinite when a deal does not name it.
|
|
231
272
|
conversion : custom.conversion ?? free.conversion,
|
|
232
273
|
custom : true,
|
|
233
|
-
|
|
274
|
+
// A custom plan is a negotiated PAID deal, so it carries the paid-tier
|
|
275
|
+
// baseline whether or not the deal thought to name it. Today that is the
|
|
276
|
+
// sending domain: every catalog paid tier grants it, and a custom plan
|
|
277
|
+
// silently lacking it would be a support ticket, not a pricing decision.
|
|
278
|
+
features : all.features([ connection.sender.key, ...( custom.features?.granted || [] ) ]),
|
|
234
279
|
limits : all.limits( custom.limits?.organization || {} ),
|
|
280
|
+
// A custom plan stores its overage BARE on `custom.overages` — a different
|
|
281
|
+
// shape from the catalog's nested one. Number() so a deal stored as a string
|
|
282
|
+
// still resolves to cents-per-action; an unnamed overage stays undefined
|
|
283
|
+
// (it bills nothing) rather than becoming NaN.
|
|
284
|
+
actionCents : custom.overages == null ? undefined : Number( custom.overages ),
|
|
235
285
|
overages : { actions : custom.overages },
|
|
236
286
|
title : custom.title || 'Custom'
|
|
237
287
|
};
|
|
@@ -250,4 +300,4 @@ const conversionRate = ( subscription ) =>
|
|
|
250
300
|
resolvePlan( subscription )?.conversion
|
|
251
301
|
?? free.conversion;
|
|
252
302
|
|
|
253
|
-
export { conversionRate, free, plans, resolvePlan };
|
|
303
|
+
export { conversionRate, free, plans, resolvePlan, unitAmountDecimal };
|
package/dist/plans.js
CHANGED
|
@@ -71,6 +71,11 @@ var connection = {
|
|
|
71
71
|
error: "Plan does not include Mailchimp connection",
|
|
72
72
|
feature: "Mailchimp connection"
|
|
73
73
|
},
|
|
74
|
+
sender: {
|
|
75
|
+
key: "organization:connection:sender",
|
|
76
|
+
error: "Plan does not include a verified sending domain",
|
|
77
|
+
feature: "Sending domain connection"
|
|
78
|
+
},
|
|
74
79
|
sendgrid: {
|
|
75
80
|
key: "organization:connection:sendgrid",
|
|
76
81
|
error: "Plan does not include SendGrid connection",
|
|
@@ -224,6 +229,15 @@ var featuresFor = (array = []) => Object.values({
|
|
|
224
229
|
},
|
|
225
230
|
{ denied: {}, granted: {} }
|
|
226
231
|
);
|
|
232
|
+
var overage = (actionCents) => ({
|
|
233
|
+
actionCents,
|
|
234
|
+
overages: { actions: String(actionCents) }
|
|
235
|
+
});
|
|
236
|
+
var unitAmountDecimal = (cents) => {
|
|
237
|
+
const value = Number(cents);
|
|
238
|
+
if (cents == null || !Number.isFinite(value)) throw new Error(`Invalid overage rate: ${cents}`);
|
|
239
|
+
return String(value);
|
|
240
|
+
};
|
|
227
241
|
var all = {
|
|
228
242
|
features: (array = []) => featuresFor([
|
|
229
243
|
connection.mailchimp.key,
|
|
@@ -284,7 +298,11 @@ var free = {
|
|
|
284
298
|
};
|
|
285
299
|
var plans = {
|
|
286
300
|
DB00002: {
|
|
287
|
-
|
|
301
|
+
// A verified sending domain is a PAID capability: free plans cannot send
|
|
302
|
+
// lead-facing email at all (the send path gates on an active
|
|
303
|
+
// subscription), so granting it there would offer a domain that can
|
|
304
|
+
// never send from.
|
|
305
|
+
features: all.features([connection.sender.key, organization.members.key]),
|
|
288
306
|
limits: all.limits({ actions: 5e3, members: 3, storage: gigabyte * 10 }),
|
|
289
307
|
marketing: {
|
|
290
308
|
description: "Tools to fine-tune campaigns and improve lead quality.",
|
|
@@ -299,12 +317,13 @@ var plans = {
|
|
|
299
317
|
["Storage", "10GB"]
|
|
300
318
|
]
|
|
301
319
|
},
|
|
302
|
-
|
|
320
|
+
...overage(2.5),
|
|
303
321
|
title: "Starter",
|
|
304
322
|
conversion: 2
|
|
305
323
|
},
|
|
306
324
|
DB00003: {
|
|
307
325
|
features: all.features([
|
|
326
|
+
connection.sender.key,
|
|
308
327
|
organization.advertisements.key,
|
|
309
328
|
organization.analytics.key,
|
|
310
329
|
organization.members.key,
|
|
@@ -329,12 +348,13 @@ var plans = {
|
|
|
329
348
|
["Storage", "20GB"]
|
|
330
349
|
]
|
|
331
350
|
},
|
|
332
|
-
|
|
351
|
+
...overage(2),
|
|
333
352
|
title: "Pro",
|
|
334
353
|
conversion: 1.5
|
|
335
354
|
},
|
|
336
355
|
DB00004: {
|
|
337
356
|
features: all.features([
|
|
357
|
+
connection.sender.key,
|
|
338
358
|
organization.advertisements.key,
|
|
339
359
|
organization.analytics.key,
|
|
340
360
|
organization.members.key,
|
|
@@ -359,12 +379,13 @@ var plans = {
|
|
|
359
379
|
["Storage", "50GB"]
|
|
360
380
|
]
|
|
361
381
|
},
|
|
362
|
-
|
|
382
|
+
...overage(1.85),
|
|
363
383
|
title: "Premium",
|
|
364
384
|
conversion: 1
|
|
365
385
|
},
|
|
366
386
|
DB00005: {
|
|
367
387
|
features: all.features([
|
|
388
|
+
connection.sender.key,
|
|
368
389
|
organization.advertisements.key,
|
|
369
390
|
organization.analytics.key,
|
|
370
391
|
organization.members.key,
|
|
@@ -389,7 +410,7 @@ var plans = {
|
|
|
389
410
|
["Storage", "100GB"]
|
|
390
411
|
]
|
|
391
412
|
},
|
|
392
|
-
|
|
413
|
+
...overage(1.5),
|
|
393
414
|
title: "Elite",
|
|
394
415
|
conversion: 0.5
|
|
395
416
|
}
|
|
@@ -405,8 +426,17 @@ var resolvePlan = (subscription) => {
|
|
|
405
426
|
// infinite when a deal does not name it.
|
|
406
427
|
conversion: custom.conversion ?? free.conversion,
|
|
407
428
|
custom: true,
|
|
408
|
-
|
|
429
|
+
// A custom plan is a negotiated PAID deal, so it carries the paid-tier
|
|
430
|
+
// baseline whether or not the deal thought to name it. Today that is the
|
|
431
|
+
// sending domain: every catalog paid tier grants it, and a custom plan
|
|
432
|
+
// silently lacking it would be a support ticket, not a pricing decision.
|
|
433
|
+
features: all.features([connection.sender.key, ...((_a = custom.features) == null ? void 0 : _a.granted) || []]),
|
|
409
434
|
limits: all.limits(((_b = custom.limits) == null ? void 0 : _b.organization) || {}),
|
|
435
|
+
// A custom plan stores its overage BARE on `custom.overages` — a different
|
|
436
|
+
// shape from the catalog's nested one. Number() so a deal stored as a string
|
|
437
|
+
// still resolves to cents-per-action; an unnamed overage stays undefined
|
|
438
|
+
// (it bills nothing) rather than becoming NaN.
|
|
439
|
+
actionCents: custom.overages == null ? void 0 : Number(custom.overages),
|
|
410
440
|
overages: { actions: custom.overages },
|
|
411
441
|
title: custom.title || "Custom"
|
|
412
442
|
};
|
|
@@ -419,5 +449,6 @@ export {
|
|
|
419
449
|
conversionRate,
|
|
420
450
|
free,
|
|
421
451
|
plans,
|
|
422
|
-
resolvePlan
|
|
452
|
+
resolvePlan,
|
|
453
|
+
unitAmountDecimal
|
|
423
454
|
};
|