@soulbatical/tetra-core 0.10.4 → 0.11.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 +78 -38
- package/dist/core/createApp.d.ts +1 -1
- package/dist/core/createApp.d.ts.map +1 -1
- package/dist/core/createApp.js +77 -2
- package/dist/core/createApp.js.map +1 -1
- package/dist/core/dualWriteProxy.d.ts +7 -2
- package/dist/core/dualWriteProxy.d.ts.map +1 -1
- package/dist/core/dualWriteProxy.js +16 -5
- package/dist/core/dualWriteProxy.js.map +1 -1
- package/dist/core/routeContext.d.ts +24 -0
- package/dist/core/routeContext.d.ts.map +1 -1
- package/dist/core/routeContext.js +31 -4
- package/dist/core/routeContext.js.map +1 -1
- package/dist/core/systemDb.d.ts +2 -2
- package/dist/core/systemDb.js +2 -2
- package/dist/generators/rls-checker.d.ts +1 -1
- package/dist/generators/rls-checker.js +1 -1
- package/dist/generators/rls-exec-sql.d.ts +1 -1
- package/dist/generators/rls-exec-sql.js +1 -1
- package/dist/generators/rpc/index.d.ts +1 -1
- package/dist/generators/rpc/index.js +1 -1
- package/dist/index.d.ts +3 -31
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -32
- package/dist/index.js.map +1 -1
- package/dist/middleware/securityMiddleware.d.ts +1 -1
- package/dist/middleware/securityMiddleware.d.ts.map +1 -1
- package/dist/middleware/validateBody.d.ts.map +1 -1
- package/dist/middleware/validateBody.js +51 -8
- package/dist/middleware/validateBody.js.map +1 -1
- package/dist/shared/rfc7807ErrorResponse.d.ts +7 -0
- package/dist/shared/rfc7807ErrorResponse.d.ts.map +1 -1
- package/dist/shared/rfc7807ErrorResponse.js +19 -5
- package/dist/shared/rfc7807ErrorResponse.js.map +1 -1
- package/dist/utils/logger.d.ts.map +1 -1
- package/dist/utils/logger.js +16 -1
- package/dist/utils/logger.js.map +1 -1
- package/package.json +33 -77
- package/dist/affiliate.d.ts +0 -11
- package/dist/affiliate.d.ts.map +0 -1
- package/dist/affiliate.js +0 -10
- package/dist/affiliate.js.map +0 -1
- package/dist/billing.d.ts +0 -8
- package/dist/billing.d.ts.map +0 -1
- package/dist/billing.js +0 -7
- package/dist/billing.js.map +0 -1
- package/dist/email.d.ts +0 -9
- package/dist/email.d.ts.map +0 -1
- package/dist/email.js +0 -8
- package/dist/email.js.map +0 -1
- package/dist/generators/rls-exec-sql.sql +0 -57
- package/dist/generators.d.ts +0 -15
- package/dist/generators.d.ts.map +0 -1
- package/dist/generators.js +0 -12
- package/dist/generators.js.map +0 -1
- package/dist/mcp.d.ts +0 -8
- package/dist/mcp.d.ts.map +0 -1
- package/dist/mcp.js +0 -7
- package/dist/mcp.js.map +0 -1
- package/dist/planner.d.ts +0 -8
- package/dist/planner.d.ts.map +0 -1
- package/dist/planner.js +0 -7
- package/dist/planner.js.map +0 -1
- package/dist/shared/affiliate/AffiliateAttributionService.d.ts +0 -47
- package/dist/shared/affiliate/AffiliateAttributionService.d.ts.map +0 -1
- package/dist/shared/affiliate/AffiliateAttributionService.js +0 -308
- package/dist/shared/affiliate/AffiliateAttributionService.js.map +0 -1
- package/dist/shared/affiliate/AffiliateClickService.d.ts +0 -35
- package/dist/shared/affiliate/AffiliateClickService.d.ts.map +0 -1
- package/dist/shared/affiliate/AffiliateClickService.js +0 -87
- package/dist/shared/affiliate/AffiliateClickService.js.map +0 -1
- package/dist/shared/affiliate/affiliateFeatureConfig.d.ts +0 -11
- package/dist/shared/affiliate/affiliateFeatureConfig.d.ts.map +0 -1
- package/dist/shared/affiliate/affiliateFeatureConfig.js +0 -242
- package/dist/shared/affiliate/affiliateFeatureConfig.js.map +0 -1
- package/dist/shared/affiliate/index.d.ts +0 -11
- package/dist/shared/affiliate/index.d.ts.map +0 -1
- package/dist/shared/affiliate/index.js +0 -13
- package/dist/shared/affiliate/index.js.map +0 -1
- package/dist/shared/affiliate/routes.d.ts +0 -87
- package/dist/shared/affiliate/routes.d.ts.map +0 -1
- package/dist/shared/affiliate/routes.js +0 -404
- package/dist/shared/affiliate/routes.js.map +0 -1
- package/dist/shared/affiliate/types.d.ts +0 -170
- package/dist/shared/affiliate/types.d.ts.map +0 -1
- package/dist/shared/affiliate/types.js +0 -11
- package/dist/shared/affiliate/types.js.map +0 -1
- package/dist/shared/billing/BillingService.d.ts +0 -56
- package/dist/shared/billing/BillingService.d.ts.map +0 -1
- package/dist/shared/billing/BillingService.js +0 -588
- package/dist/shared/billing/BillingService.js.map +0 -1
- package/dist/shared/billing/SeatBillingService.d.ts +0 -106
- package/dist/shared/billing/SeatBillingService.d.ts.map +0 -1
- package/dist/shared/billing/SeatBillingService.js +0 -292
- package/dist/shared/billing/SeatBillingService.js.map +0 -1
- package/dist/shared/billing/index.d.ts +0 -30
- package/dist/shared/billing/index.d.ts.map +0 -1
- package/dist/shared/billing/index.js +0 -27
- package/dist/shared/billing/index.js.map +0 -1
- package/dist/shared/billing/routes.d.ts +0 -45
- package/dist/shared/billing/routes.d.ts.map +0 -1
- package/dist/shared/billing/routes.js +0 -184
- package/dist/shared/billing/routes.js.map +0 -1
- package/dist/shared/billing/seat-pricing.d.ts +0 -53
- package/dist/shared/billing/seat-pricing.d.ts.map +0 -1
- package/dist/shared/billing/seat-pricing.js +0 -81
- package/dist/shared/billing/seat-pricing.js.map +0 -1
- package/dist/shared/billing/types.d.ts +0 -109
- package/dist/shared/billing/types.d.ts.map +0 -1
- package/dist/shared/billing/types.js +0 -8
- package/dist/shared/billing/types.js.map +0 -1
- package/dist/shared/email/EmailService.d.ts +0 -64
- package/dist/shared/email/EmailService.d.ts.map +0 -1
- package/dist/shared/email/EmailService.js +0 -300
- package/dist/shared/email/EmailService.js.map +0 -1
- package/dist/shared/email/adminRoutes.d.ts +0 -30
- package/dist/shared/email/adminRoutes.d.ts.map +0 -1
- package/dist/shared/email/adminRoutes.js +0 -227
- package/dist/shared/email/adminRoutes.js.map +0 -1
- package/dist/shared/email/gmail.d.ts +0 -208
- package/dist/shared/email/gmail.d.ts.map +0 -1
- package/dist/shared/email/gmail.js +0 -626
- package/dist/shared/email/gmail.js.map +0 -1
- package/dist/shared/email/index.d.ts +0 -15
- package/dist/shared/email/index.d.ts.map +0 -1
- package/dist/shared/email/index.js +0 -18
- package/dist/shared/email/index.js.map +0 -1
- package/dist/shared/email/mailgun.d.ts +0 -18
- package/dist/shared/email/mailgun.d.ts.map +0 -1
- package/dist/shared/email/mailgun.js +0 -76
- package/dist/shared/email/mailgun.js.map +0 -1
- package/dist/shared/email/sanitize.d.ts +0 -25
- package/dist/shared/email/sanitize.d.ts.map +0 -1
- package/dist/shared/email/sanitize.js +0 -39
- package/dist/shared/email/sanitize.js.map +0 -1
- package/dist/shared/email/smtp.d.ts +0 -20
- package/dist/shared/email/smtp.d.ts.map +0 -1
- package/dist/shared/email/smtp.js +0 -53
- package/dist/shared/email/smtp.js.map +0 -1
- package/dist/shared/email/types.d.ts +0 -113
- package/dist/shared/email/types.d.ts.map +0 -1
- package/dist/shared/email/types.js +0 -7
- package/dist/shared/email/types.js.map +0 -1
- package/dist/shared/email/webhookRoutes.d.ts +0 -29
- package/dist/shared/email/webhookRoutes.d.ts.map +0 -1
- package/dist/shared/email/webhookRoutes.js +0 -125
- package/dist/shared/email/webhookRoutes.js.map +0 -1
- package/dist/shared/mcp/index.d.ts +0 -51
- package/dist/shared/mcp/index.d.ts.map +0 -1
- package/dist/shared/mcp/index.js +0 -51
- package/dist/shared/mcp/index.js.map +0 -1
- package/dist/shared/mcp/mcp-auth-routes.d.ts +0 -26
- package/dist/shared/mcp/mcp-auth-routes.d.ts.map +0 -1
- package/dist/shared/mcp/mcp-auth-routes.js +0 -141
- package/dist/shared/mcp/mcp-auth-routes.js.map +0 -1
- package/dist/shared/mcp/mcp-db.d.ts +0 -99
- package/dist/shared/mcp/mcp-db.d.ts.map +0 -1
- package/dist/shared/mcp/mcp-db.js +0 -106
- package/dist/shared/mcp/mcp-db.js.map +0 -1
- package/dist/shared/mcp/mcp-routes.d.ts +0 -29
- package/dist/shared/mcp/mcp-routes.d.ts.map +0 -1
- package/dist/shared/mcp/mcp-routes.js +0 -171
- package/dist/shared/mcp/mcp-routes.js.map +0 -1
- package/dist/shared/mcp/mcp-tokens-routes.d.ts +0 -35
- package/dist/shared/mcp/mcp-tokens-routes.d.ts.map +0 -1
- package/dist/shared/mcp/mcp-tokens-routes.js +0 -94
- package/dist/shared/mcp/mcp-tokens-routes.js.map +0 -1
- package/dist/shared/mcp/mcp-usage-routes.d.ts +0 -17
- package/dist/shared/mcp/mcp-usage-routes.d.ts.map +0 -1
- package/dist/shared/mcp/mcp-usage-routes.js +0 -81
- package/dist/shared/mcp/mcp-usage-routes.js.map +0 -1
- package/dist/shared/mcp/tenant-context.d.ts +0 -59
- package/dist/shared/mcp/tenant-context.d.ts.map +0 -1
- package/dist/shared/mcp/tenant-context.js +0 -136
- package/dist/shared/mcp/tenant-context.js.map +0 -1
- package/dist/shared/mcp/types.d.ts +0 -74
- package/dist/shared/mcp/types.d.ts.map +0 -1
- package/dist/shared/mcp/types.js +0 -7
- package/dist/shared/mcp/types.js.map +0 -1
- package/dist/shared/planner/GoogleCalendarService.d.ts +0 -137
- package/dist/shared/planner/GoogleCalendarService.d.ts.map +0 -1
- package/dist/shared/planner/GoogleCalendarService.js +0 -525
- package/dist/shared/planner/GoogleCalendarService.js.map +0 -1
- package/dist/shared/planner/PlannerService.d.ts +0 -264
- package/dist/shared/planner/PlannerService.d.ts.map +0 -1
- package/dist/shared/planner/PlannerService.js +0 -1393
- package/dist/shared/planner/PlannerService.js.map +0 -1
- package/dist/shared/planner/index.d.ts +0 -37
- package/dist/shared/planner/index.d.ts.map +0 -1
- package/dist/shared/planner/index.js +0 -35
- package/dist/shared/planner/index.js.map +0 -1
- package/dist/shared/planner/intervals.d.ts +0 -60
- package/dist/shared/planner/intervals.d.ts.map +0 -1
- package/dist/shared/planner/intervals.js +0 -141
- package/dist/shared/planner/intervals.js.map +0 -1
- package/dist/shared/planner/routes.d.ts +0 -69
- package/dist/shared/planner/routes.d.ts.map +0 -1
- package/dist/shared/planner/routes.js +0 -770
- package/dist/shared/planner/routes.js.map +0 -1
- package/dist/shared/planner/types.d.ts +0 -328
- package/dist/shared/planner/types.d.ts.map +0 -1
- package/dist/shared/planner/types.js +0 -9
- package/dist/shared/planner/types.js.map +0 -1
- package/dist/shared/storage/ImageProcessingService.d.ts +0 -32
- package/dist/shared/storage/ImageProcessingService.d.ts.map +0 -1
- package/dist/shared/storage/ImageProcessingService.js +0 -127
- package/dist/shared/storage/ImageProcessingService.js.map +0 -1
- package/dist/shared/storage/StorageProxyService.d.ts +0 -47
- package/dist/shared/storage/StorageProxyService.d.ts.map +0 -1
- package/dist/shared/storage/StorageProxyService.js +0 -196
- package/dist/shared/storage/StorageProxyService.js.map +0 -1
- package/dist/shared/storage/StorageUploadService.d.ts +0 -126
- package/dist/shared/storage/StorageUploadService.d.ts.map +0 -1
- package/dist/shared/storage/StorageUploadService.js +0 -206
- package/dist/shared/storage/StorageUploadService.js.map +0 -1
- package/dist/shared/storage/creative-urls.d.ts +0 -14
- package/dist/shared/storage/creative-urls.d.ts.map +0 -1
- package/dist/shared/storage/creative-urls.js +0 -30
- package/dist/shared/storage/creative-urls.js.map +0 -1
- package/dist/shared/storage/index.d.ts +0 -28
- package/dist/shared/storage/index.d.ts.map +0 -1
- package/dist/shared/storage/index.js +0 -27
- package/dist/shared/storage/index.js.map +0 -1
- package/dist/shared/storage/routes.d.ts +0 -42
- package/dist/shared/storage/routes.d.ts.map +0 -1
- package/dist/shared/storage/routes.js +0 -160
- package/dist/shared/storage/routes.js.map +0 -1
- package/dist/shared/storage/types.d.ts +0 -53
- package/dist/shared/storage/types.d.ts.map +0 -1
- package/dist/shared/storage/types.js +0 -2
- package/dist/shared/storage/types.js.map +0 -1
- package/dist/shared/telegram/index.d.ts +0 -4
- package/dist/shared/telegram/index.d.ts.map +0 -1
- package/dist/shared/telegram/index.js +0 -3
- package/dist/shared/telegram/index.js.map +0 -1
- package/dist/shared/telegram/routes.d.ts +0 -43
- package/dist/shared/telegram/routes.d.ts.map +0 -1
- package/dist/shared/telegram/routes.js +0 -868
- package/dist/shared/telegram/routes.js.map +0 -1
- package/dist/shared/telegram/types.d.ts +0 -168
- package/dist/shared/telegram/types.d.ts.map +0 -1
- package/dist/shared/telegram/types.js +0 -7
- package/dist/shared/telegram/types.js.map +0 -1
- package/dist/shared/telegram/utils.d.ts +0 -44
- package/dist/shared/telegram/utils.d.ts.map +0 -1
- package/dist/shared/telegram/utils.js +0 -121
- package/dist/shared/telegram/utils.js.map +0 -1
- package/dist/storage.d.ts +0 -9
- package/dist/storage.d.ts.map +0 -1
- package/dist/storage.js +0 -8
- package/dist/storage.js.map +0 -1
- package/dist/telemetry.d.ts +0 -9
- package/dist/telemetry.d.ts.map +0 -1
- package/dist/telemetry.js +0 -8
- package/dist/telemetry.js.map +0 -1
- package/scripts/postinstall.js +0 -79
- package/src/shared/affiliate/migrations/001_create_affiliates.sql +0 -49
- package/src/shared/affiliate/migrations/002_create_affiliate_commissions.sql +0 -31
- package/src/shared/affiliate/migrations/003_create_affiliate_clicks.sql +0 -26
- package/src/shared/affiliate/migrations/004_create_affiliate_payments.sql +0 -34
- package/src/shared/affiliate/migrations/005_create_affiliate_tier_history.sql +0 -19
- package/src/shared/affiliate/migrations/006_create_affiliate_rpc_functions.sql +0 -209
- package/src/shared/affiliate/migrations/007_create_affiliate_rls_policies.sql +0 -123
- package/src/shared/billing/migrations/00000000000001_billing.sql +0 -114
- package/src/shared/email/migrations/000_create_email_logs.sql +0 -27
- package/src/shared/email/migrations/001_create_email_templates.sql +0 -27
- package/src/shared/email/migrations/002_add_rls_baseline_policies.sql +0 -37
- package/src/shared/email/migrations/003_create_gmail_accounts.sql +0 -82
- package/src/shared/email/migrations/004_add_email_logs_tracking_columns.sql +0 -15
- package/src/shared/mcp/migrations/001_mcp_api_tokens.sql +0 -21
- package/src/shared/mcp/migrations/002_mcp_audit_log.sql +0 -16
|
@@ -1,184 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Billing Route Helpers — factory functions for standard billing endpoints
|
|
3
|
-
*
|
|
4
|
-
* Usage:
|
|
5
|
-
* ```typescript
|
|
6
|
-
* import { addBillingRoutes, addBillingWebhookRoutes } from '@soulbatical/tetra-core';
|
|
7
|
-
*
|
|
8
|
-
* // Authenticated routes (mount behind auth middleware)
|
|
9
|
-
* const billingRouter = Router();
|
|
10
|
-
* billingRouter.use(authenticateToken);
|
|
11
|
-
* addBillingRoutes(billingRouter, { config, getOrgId, getBillingStatus });
|
|
12
|
-
*
|
|
13
|
-
* // Webhook routes (no auth, raw body for Stripe)
|
|
14
|
-
* addBillingWebhookRoutes(app, { config, basePath: '/api/billing/webhook' });
|
|
15
|
-
* ```
|
|
16
|
-
*/
|
|
17
|
-
import { BillingService } from './BillingService.js';
|
|
18
|
-
import { RFC7807ErrorResponse } from '../rfc7807ErrorResponse.js';
|
|
19
|
-
import { createLogger } from '../../utils/logger.js';
|
|
20
|
-
const logger = createLogger('billing:routes');
|
|
21
|
-
const DEFAULT_MOLLIE_IPS = [
|
|
22
|
-
'87.233.217.240', '87.233.217.241', '87.233.217.242', '87.233.217.243',
|
|
23
|
-
'87.233.217.244', '87.233.217.245', '87.233.217.246', '87.233.217.247',
|
|
24
|
-
];
|
|
25
|
-
/**
|
|
26
|
-
* Add authenticated billing routes to a router.
|
|
27
|
-
*
|
|
28
|
-
* Adds:
|
|
29
|
-
* - POST /checkout — Stripe checkout
|
|
30
|
-
* - POST /checkout/mollie — Mollie/iDEAL checkout
|
|
31
|
-
* - POST /portal — Stripe customer portal
|
|
32
|
-
* - GET /status — Billing status
|
|
33
|
-
* - GET /invoices — Stripe invoices
|
|
34
|
-
*/
|
|
35
|
-
export function addBillingRoutes(router, options) {
|
|
36
|
-
const service = new BillingService(options.config);
|
|
37
|
-
// POST /checkout — Stripe
|
|
38
|
-
router.post('/checkout', async (req, res) => {
|
|
39
|
-
try {
|
|
40
|
-
const orgId = options.getOrgId(req);
|
|
41
|
-
if (!orgId) {
|
|
42
|
-
RFC7807ErrorResponse.badRequest(res, 'No active organization.');
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
const { plan, cycle = 'monthly' } = req.body;
|
|
46
|
-
if (!plan || !service.getPlan(plan)) {
|
|
47
|
-
RFC7807ErrorResponse.badRequest(res, 'Invalid plan.');
|
|
48
|
-
return;
|
|
49
|
-
}
|
|
50
|
-
const result = await service.createStripeCheckout(orgId, plan, cycle);
|
|
51
|
-
res.json({ success: true, data: result });
|
|
52
|
-
}
|
|
53
|
-
catch (err) {
|
|
54
|
-
logger.error({ error: err }, 'Stripe checkout error');
|
|
55
|
-
RFC7807ErrorResponse.internalError(res, err.message || 'Checkout failed.');
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
// POST /checkout/mollie — iDEAL
|
|
59
|
-
router.post('/checkout/mollie', async (req, res) => {
|
|
60
|
-
try {
|
|
61
|
-
const orgId = options.getOrgId(req);
|
|
62
|
-
if (!orgId) {
|
|
63
|
-
RFC7807ErrorResponse.badRequest(res, 'No active organization.');
|
|
64
|
-
return;
|
|
65
|
-
}
|
|
66
|
-
const { plan, cycle = 'monthly' } = req.body;
|
|
67
|
-
if (!plan || !service.getPlan(plan)) {
|
|
68
|
-
RFC7807ErrorResponse.badRequest(res, 'Invalid plan.');
|
|
69
|
-
return;
|
|
70
|
-
}
|
|
71
|
-
const result = await service.createMollieCheckout(orgId, plan, cycle);
|
|
72
|
-
res.json({ success: true, data: result });
|
|
73
|
-
}
|
|
74
|
-
catch (err) {
|
|
75
|
-
logger.error({ error: err }, 'Mollie checkout error');
|
|
76
|
-
RFC7807ErrorResponse.internalError(res, err.message || 'Checkout failed.');
|
|
77
|
-
}
|
|
78
|
-
});
|
|
79
|
-
// POST /portal — Stripe Customer Portal
|
|
80
|
-
router.post('/portal', async (req, res) => {
|
|
81
|
-
try {
|
|
82
|
-
const orgId = options.getOrgId(req);
|
|
83
|
-
if (!orgId) {
|
|
84
|
-
RFC7807ErrorResponse.badRequest(res, 'No active organization.');
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
const result = await service.createStripePortal(orgId);
|
|
88
|
-
res.json({ success: true, data: result });
|
|
89
|
-
}
|
|
90
|
-
catch (err) {
|
|
91
|
-
logger.error({ error: err }, 'Portal error');
|
|
92
|
-
RFC7807ErrorResponse.internalError(res, err.message || 'Portal failed.');
|
|
93
|
-
}
|
|
94
|
-
});
|
|
95
|
-
// GET /status — Billing status
|
|
96
|
-
router.get('/status', async (req, res) => {
|
|
97
|
-
try {
|
|
98
|
-
const orgId = options.getOrgId(req);
|
|
99
|
-
if (!orgId) {
|
|
100
|
-
RFC7807ErrorResponse.badRequest(res, 'No active organization.');
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
const status = await options.getBillingStatus(orgId);
|
|
104
|
-
res.json({ success: true, data: status });
|
|
105
|
-
}
|
|
106
|
-
catch (err) {
|
|
107
|
-
logger.error({ error: err }, 'Status error');
|
|
108
|
-
RFC7807ErrorResponse.internalError(res, err.message || 'Status failed.');
|
|
109
|
-
}
|
|
110
|
-
});
|
|
111
|
-
// GET /invoices — Stripe invoices
|
|
112
|
-
router.get('/invoices', async (req, res) => {
|
|
113
|
-
try {
|
|
114
|
-
const orgId = options.getOrgId(req);
|
|
115
|
-
if (!orgId) {
|
|
116
|
-
RFC7807ErrorResponse.badRequest(res, 'No active organization.');
|
|
117
|
-
return;
|
|
118
|
-
}
|
|
119
|
-
const invoices = await service.getInvoices(orgId);
|
|
120
|
-
res.json({ success: true, data: { invoices } });
|
|
121
|
-
}
|
|
122
|
-
catch (err) {
|
|
123
|
-
logger.error({ error: err }, 'Invoices error');
|
|
124
|
-
RFC7807ErrorResponse.internalError(res, err.message || 'Invoices failed.');
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
return service;
|
|
128
|
-
}
|
|
129
|
-
/**
|
|
130
|
-
* Add webhook routes for Stripe and Mollie.
|
|
131
|
-
*
|
|
132
|
-
* IMPORTANT: Stripe needs raw body. Configure express.raw() for the Stripe webhook path
|
|
133
|
-
* BEFORE mounting these routes.
|
|
134
|
-
*
|
|
135
|
-
* Adds:
|
|
136
|
-
* - POST {basePath}/stripe — Stripe webhook (signature verified)
|
|
137
|
-
* - POST {basePath}/mollie — Mollie webhook (IP whitelist in production)
|
|
138
|
-
*/
|
|
139
|
-
export function addBillingWebhookRoutes(router, options) {
|
|
140
|
-
const service = new BillingService(options.config);
|
|
141
|
-
const basePath = options.basePath || '/webhook';
|
|
142
|
-
const mollieIPs = options.config.mollieWebhookIPs || DEFAULT_MOLLIE_IPS;
|
|
143
|
-
// POST /webhook/stripe
|
|
144
|
-
router.post(`${basePath}/stripe`, async (req, res) => {
|
|
145
|
-
try {
|
|
146
|
-
const sig = req.headers['stripe-signature'];
|
|
147
|
-
if (!sig) {
|
|
148
|
-
RFC7807ErrorResponse.badRequest(res, 'Missing signature.');
|
|
149
|
-
return;
|
|
150
|
-
}
|
|
151
|
-
// Return 200 immediately, process async
|
|
152
|
-
res.json({ success: true, data: { received: true } });
|
|
153
|
-
await service.handleStripeWebhook(req.body, sig);
|
|
154
|
-
}
|
|
155
|
-
catch (err) {
|
|
156
|
-
logger.error({ error: err }, 'Stripe webhook error');
|
|
157
|
-
if (!res.headersSent) {
|
|
158
|
-
RFC7807ErrorResponse.badRequest(res, err.message || 'Webhook failed.');
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
});
|
|
162
|
-
// POST /webhook/mollie
|
|
163
|
-
router.post(`${basePath}/mollie`, async (req, res) => {
|
|
164
|
-
// IP whitelist (production only)
|
|
165
|
-
if (process.env.NODE_ENV === 'production') {
|
|
166
|
-
const clientIp = req.headers['x-forwarded-for']?.split(',')[0]?.trim() || req.ip;
|
|
167
|
-
if (!mollieIPs.includes(clientIp || '')) {
|
|
168
|
-
logger.warn({ clientIp }, 'Mollie webhook from unauthorized IP');
|
|
169
|
-
RFC7807ErrorResponse.forbidden(res, 'Not authorized.');
|
|
170
|
-
return;
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
// Return 200 immediately (Mollie requirement)
|
|
174
|
-
res.status(200).send('OK');
|
|
175
|
-
try {
|
|
176
|
-
await service.handleMollieWebhook(req.body?.id);
|
|
177
|
-
}
|
|
178
|
-
catch (err) {
|
|
179
|
-
logger.error({ error: err }, 'Mollie webhook error');
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
return service;
|
|
183
|
-
}
|
|
184
|
-
//# sourceMappingURL=routes.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"routes.js","sourceRoot":"","sources":["../../../src/shared/billing/routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Seat-based pricing calculator
|
|
3
|
-
*
|
|
4
|
-
* Shared logic for per-user pricing with volume discounts and tier minimums.
|
|
5
|
-
* Used by: website pricing calculator, SeatBillingService, license validation.
|
|
6
|
-
*
|
|
7
|
-
* @module @soulbatical/tetra-core/billing
|
|
8
|
-
*/
|
|
9
|
-
export interface SeatTier {
|
|
10
|
-
/** Minimum users for this tier (inclusive) */
|
|
11
|
-
min: number;
|
|
12
|
-
/** Maximum users for this tier (inclusive, Infinity for last tier) */
|
|
13
|
-
max: number;
|
|
14
|
-
/** Price per user per month in EUR */
|
|
15
|
-
pricePerUser: number;
|
|
16
|
-
/** Minimum monthly charge for this tier (prevents price dips at tier boundary) */
|
|
17
|
-
minimum: number;
|
|
18
|
-
}
|
|
19
|
-
/** Default Tetra seat pricing tiers */
|
|
20
|
-
export declare const DEFAULT_SEAT_TIERS: SeatTier[];
|
|
21
|
-
export interface SeatPriceResult {
|
|
22
|
-
/** Total monthly price in EUR */
|
|
23
|
-
monthlyPrice: number;
|
|
24
|
-
/** Total yearly price in EUR */
|
|
25
|
-
yearlyPrice: number;
|
|
26
|
-
/** Number of free users */
|
|
27
|
-
freeUsers: number;
|
|
28
|
-
/** Number of paid users */
|
|
29
|
-
paidUsers: number;
|
|
30
|
-
/** Effective price per user (total / users) */
|
|
31
|
-
effectivePricePerUser: number;
|
|
32
|
-
/** Which tier the user count falls in */
|
|
33
|
-
tierIndex: number;
|
|
34
|
-
/** The tier's listed price per user */
|
|
35
|
-
tierPricePerUser: number;
|
|
36
|
-
/** Whether the minimum was applied */
|
|
37
|
-
minimumApplied: boolean;
|
|
38
|
-
}
|
|
39
|
-
/**
|
|
40
|
-
* Calculate the monthly price for a given number of seat users.
|
|
41
|
-
*
|
|
42
|
-
* Rules:
|
|
43
|
-
* - First 10 users are free
|
|
44
|
-
* - Price per user decreases with volume
|
|
45
|
-
* - Each tier has a minimum monthly charge (prevents price dips at boundary)
|
|
46
|
-
* - For 1000+ users, the last tier rate applies
|
|
47
|
-
*/
|
|
48
|
-
export declare function calculateSeatPrice(users: number, tiers?: SeatTier[]): SeatPriceResult;
|
|
49
|
-
/**
|
|
50
|
-
* Convert seat price to Stripe-compatible amount in cents.
|
|
51
|
-
*/
|
|
52
|
-
export declare function seatPriceToCents(monthlyPrice: number): number;
|
|
53
|
-
//# sourceMappingURL=seat-pricing.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seat-pricing.d.ts","sourceRoot":"","sources":["../../../src/shared/billing/seat-pricing.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,MAAM,WAAW,QAAQ;IACvB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,sEAAsE;IACtE,GAAG,EAAE,MAAM,CAAC;IACZ,sCAAsC;IACtC,YAAY,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,uCAAuC;AACvC,eAAO,MAAM,kBAAkB,EAAE,QAAQ,EAMxC,CAAC;AAEF,MAAM,WAAW,eAAe;IAC9B,iCAAiC;IACjC,YAAY,EAAE,MAAM,CAAC;IACrB,gCAAgC;IAChC,WAAW,EAAE,MAAM,CAAC;IACpB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,2BAA2B;IAC3B,SAAS,EAAE,MAAM,CAAC;IAClB,+CAA+C;IAC/C,qBAAqB,EAAE,MAAM,CAAC;IAC9B,yCAAyC;IACzC,SAAS,EAAE,MAAM,CAAC;IAClB,uCAAuC;IACvC,gBAAgB,EAAE,MAAM,CAAC;IACzB,sCAAsC;IACtC,cAAc,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EACb,KAAK,GAAE,QAAQ,EAAuB,GACrC,eAAe,CAuDjB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,YAAY,EAAE,MAAM,GAAG,MAAM,CAE7D"}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Seat-based pricing calculator
|
|
3
|
-
*
|
|
4
|
-
* Shared logic for per-user pricing with volume discounts and tier minimums.
|
|
5
|
-
* Used by: website pricing calculator, SeatBillingService, license validation.
|
|
6
|
-
*
|
|
7
|
-
* @module @soulbatical/tetra-core/billing
|
|
8
|
-
*/
|
|
9
|
-
/** Default Tetra seat pricing tiers */
|
|
10
|
-
export const DEFAULT_SEAT_TIERS = [
|
|
11
|
-
{ min: 1, max: 10, pricePerUser: 0, minimum: 0 },
|
|
12
|
-
{ min: 11, max: 100, pricePerUser: 3.90, minimum: 0 },
|
|
13
|
-
{ min: 101, max: 250, pricePerUser: 2.90, minimum: 351 },
|
|
14
|
-
{ min: 251, max: 500, pricePerUser: 1.90, minimum: 725 },
|
|
15
|
-
{ min: 501, max: 1000, pricePerUser: 0.90, minimum: 950 },
|
|
16
|
-
];
|
|
17
|
-
/**
|
|
18
|
-
* Calculate the monthly price for a given number of seat users.
|
|
19
|
-
*
|
|
20
|
-
* Rules:
|
|
21
|
-
* - First 10 users are free
|
|
22
|
-
* - Price per user decreases with volume
|
|
23
|
-
* - Each tier has a minimum monthly charge (prevents price dips at boundary)
|
|
24
|
-
* - For 1000+ users, the last tier rate applies
|
|
25
|
-
*/
|
|
26
|
-
export function calculateSeatPrice(users, tiers = DEFAULT_SEAT_TIERS) {
|
|
27
|
-
if (users <= 0) {
|
|
28
|
-
return {
|
|
29
|
-
monthlyPrice: 0,
|
|
30
|
-
yearlyPrice: 0,
|
|
31
|
-
freeUsers: 0,
|
|
32
|
-
paidUsers: 0,
|
|
33
|
-
effectivePricePerUser: 0,
|
|
34
|
-
tierIndex: 0,
|
|
35
|
-
tierPricePerUser: 0,
|
|
36
|
-
minimumApplied: false,
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
// Find the tier
|
|
40
|
-
let tierIndex = 0;
|
|
41
|
-
let tierPricePerUser = 0;
|
|
42
|
-
for (let i = 0; i < tiers.length; i++) {
|
|
43
|
-
if (users >= tiers[i].min && users <= tiers[i].max) {
|
|
44
|
-
tierIndex = i;
|
|
45
|
-
tierPricePerUser = tiers[i].pricePerUser;
|
|
46
|
-
break;
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
// Beyond last tier: use last tier's rate
|
|
50
|
-
if (users > tiers[tiers.length - 1].max) {
|
|
51
|
-
const lastTier = tiers[tiers.length - 1];
|
|
52
|
-
tierIndex = tiers.length - 1;
|
|
53
|
-
tierPricePerUser = lastTier.pricePerUser;
|
|
54
|
-
}
|
|
55
|
-
const tier = tiers[tierIndex];
|
|
56
|
-
const freeUsers = Math.min(users, tiers[0].max);
|
|
57
|
-
const paidUsers = Math.max(0, users - tiers[0].max);
|
|
58
|
-
// Calculate raw price
|
|
59
|
-
const rawPrice = users * tierPricePerUser;
|
|
60
|
-
// Apply minimum
|
|
61
|
-
const minimum = tier?.minimum ?? 0;
|
|
62
|
-
const minimumApplied = rawPrice < minimum && minimum > 0;
|
|
63
|
-
const monthlyPrice = Math.max(rawPrice, minimum);
|
|
64
|
-
return {
|
|
65
|
-
monthlyPrice: Math.round(monthlyPrice * 100) / 100,
|
|
66
|
-
yearlyPrice: Math.round(monthlyPrice * 12 * 100) / 100,
|
|
67
|
-
freeUsers,
|
|
68
|
-
paidUsers,
|
|
69
|
-
effectivePricePerUser: users > 0 ? Math.round((monthlyPrice / users) * 100) / 100 : 0,
|
|
70
|
-
tierIndex,
|
|
71
|
-
tierPricePerUser,
|
|
72
|
-
minimumApplied,
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
/**
|
|
76
|
-
* Convert seat price to Stripe-compatible amount in cents.
|
|
77
|
-
*/
|
|
78
|
-
export function seatPriceToCents(monthlyPrice) {
|
|
79
|
-
return Math.round(monthlyPrice * 100);
|
|
80
|
-
}
|
|
81
|
-
//# sourceMappingURL=seat-pricing.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"seat-pricing.js","sourceRoot":"","sources":["../../../src/shared/billing/seat-pricing.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Billing types — shared across all Tetra projects
|
|
3
|
-
*
|
|
4
|
-
* Projects provide their own plan configs via BillingConfig.
|
|
5
|
-
* The billing module handles Stripe + Mollie checkout, webhooks, and subscription lifecycle.
|
|
6
|
-
*/
|
|
7
|
-
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
8
|
-
export interface PlanConfig {
|
|
9
|
-
/** Display name */
|
|
10
|
-
name: string;
|
|
11
|
-
/** Monthly price in EUR cents (1900 = €19.00) */
|
|
12
|
-
priceMonthCents: number;
|
|
13
|
-
/** Yearly price in EUR cents (19000 = €190.00) */
|
|
14
|
-
priceYearCents: number;
|
|
15
|
-
/** Stripe price ID for monthly billing */
|
|
16
|
-
stripePriceMonthly: string;
|
|
17
|
-
/** Stripe price ID for yearly billing */
|
|
18
|
-
stripePriceYearly: string;
|
|
19
|
-
/** Mollie amount string for monthly (e.g. "19.00") */
|
|
20
|
-
mollieAmountMonthly: string;
|
|
21
|
-
/** Mollie amount string for yearly (e.g. "190.00") */
|
|
22
|
-
mollieAmountYearly: string;
|
|
23
|
-
}
|
|
24
|
-
export type BillingCycle = 'monthly' | 'yearly';
|
|
25
|
-
export type SubscriptionStatus = 'trialing' | 'active' | 'past_due' | 'canceled' | 'unpaid';
|
|
26
|
-
export type BillingProvider = 'stripe' | 'mollie';
|
|
27
|
-
export interface BillingConfig {
|
|
28
|
-
/** Plan definitions keyed by plan slug (e.g. { starter: {...}, pro: {...} }) */
|
|
29
|
-
plans: Record<string, PlanConfig>;
|
|
30
|
-
/** Stripe configuration */
|
|
31
|
-
stripe: {
|
|
32
|
-
secretKey: string;
|
|
33
|
-
webhookSecret: string;
|
|
34
|
-
};
|
|
35
|
-
/** Mollie configuration */
|
|
36
|
-
mollie: {
|
|
37
|
-
apiKey: string;
|
|
38
|
-
webhookBaseUrl: string;
|
|
39
|
-
};
|
|
40
|
-
/** Frontend URL for redirect after checkout */
|
|
41
|
-
frontendUrl: string;
|
|
42
|
-
/** Number of trial days for Stripe subscriptions (0 = no trial) */
|
|
43
|
-
trialDays: number;
|
|
44
|
-
/** Success redirect path (appended to frontendUrl) */
|
|
45
|
-
successPath: string;
|
|
46
|
-
/** Cancel redirect path (appended to frontendUrl) */
|
|
47
|
-
cancelPath: string;
|
|
48
|
-
/** Metadata key prefix for org ID in Stripe/Mollie metadata (default: "org_id") */
|
|
49
|
-
orgIdMetadataKey?: string;
|
|
50
|
-
/** Product name for Mollie payment descriptions (e.g. "VinciFox", "Agentrook") */
|
|
51
|
-
productName: string;
|
|
52
|
-
/** Function to get a system-level DB client (bypasses RLS) */
|
|
53
|
-
getSystemDB: () => SupabaseClient;
|
|
54
|
-
/** Function to get a webhook-level DB client (bypasses RLS, for webhook handlers) */
|
|
55
|
-
getWebhookDB: (context: string) => SupabaseClient;
|
|
56
|
-
/** Optional: callback after successful subscription creation */
|
|
57
|
-
onSubscriptionCreated?: (orgId: string, plan: string, provider: BillingProvider) => Promise<void>;
|
|
58
|
-
/** Optional: callback after subscription canceled */
|
|
59
|
-
onSubscriptionCanceled?: (orgId: string) => Promise<void>;
|
|
60
|
-
/** Optional: callback after payment failed */
|
|
61
|
-
onPaymentFailed?: (orgId: string) => Promise<void>;
|
|
62
|
-
/** Mollie webhook IP whitelist (production only). Defaults to standard Mollie IPs. */
|
|
63
|
-
mollieWebhookIPs?: string[];
|
|
64
|
-
}
|
|
65
|
-
export interface SubscriptionRecord {
|
|
66
|
-
id: string;
|
|
67
|
-
organization_id: string;
|
|
68
|
-
provider: BillingProvider;
|
|
69
|
-
external_subscription_id: string | null;
|
|
70
|
-
external_customer_id: string | null;
|
|
71
|
-
plan: string;
|
|
72
|
-
billing_cycle: BillingCycle;
|
|
73
|
-
price_amount_cents: number;
|
|
74
|
-
status: SubscriptionStatus;
|
|
75
|
-
trial_end: string | null;
|
|
76
|
-
current_period_start: string;
|
|
77
|
-
current_period_end: string;
|
|
78
|
-
cancel_at: string | null;
|
|
79
|
-
canceled_at: string | null;
|
|
80
|
-
ended_at: string | null;
|
|
81
|
-
created_at: string;
|
|
82
|
-
updated_at: string;
|
|
83
|
-
}
|
|
84
|
-
export interface BillingStatusResponse {
|
|
85
|
-
plan: string;
|
|
86
|
-
limits: Record<string, unknown>;
|
|
87
|
-
usage: Record<string, number>;
|
|
88
|
-
subscription: {
|
|
89
|
-
id: string;
|
|
90
|
-
provider: BillingProvider;
|
|
91
|
-
status: SubscriptionStatus;
|
|
92
|
-
billing_cycle: BillingCycle;
|
|
93
|
-
trial_end: string | null;
|
|
94
|
-
current_period_start: string;
|
|
95
|
-
current_period_end: string;
|
|
96
|
-
cancel_at: string | null;
|
|
97
|
-
canceled_at: string | null;
|
|
98
|
-
} | null;
|
|
99
|
-
has_stripe: boolean;
|
|
100
|
-
}
|
|
101
|
-
export interface BillingRouteOptions {
|
|
102
|
-
/** The billing configuration */
|
|
103
|
-
config: BillingConfig;
|
|
104
|
-
/** Function to resolve orgId from authenticated request */
|
|
105
|
-
getOrgId: (req: any) => string | undefined;
|
|
106
|
-
/** Function to get billing status for an org (plan, limits, usage) */
|
|
107
|
-
getBillingStatus: (orgId: string) => Promise<BillingStatusResponse>;
|
|
108
|
-
}
|
|
109
|
-
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/shared/billing/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Billing types — shared across all Tetra projects
|
|
3
|
-
*
|
|
4
|
-
* Projects provide their own plan configs via BillingConfig.
|
|
5
|
-
* The billing module handles Stripe + Mollie checkout, webhooks, and subscription lifecycle.
|
|
6
|
-
*/
|
|
7
|
-
export {};
|
|
8
|
-
//# sourceMappingURL=types.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/shared/billing/types.ts"],"names":[],"mappings":"AAAA;;;;;GAKG"}
|
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* EmailService — Core service for sending templated emails.
|
|
3
|
-
*
|
|
4
|
-
* Template lookup with language + org fallback, Handlebars rendering,
|
|
5
|
-
* DB logging, and multi-transport delivery (Gmail, SMTP, Mailgun).
|
|
6
|
-
*
|
|
7
|
-
* @module @soulbatical/tetra-core/email
|
|
8
|
-
*/
|
|
9
|
-
import type { SupabaseClient } from '@supabase/supabase-js';
|
|
10
|
-
import type { EmailConfig, SendEmailOpts } from './types.js';
|
|
11
|
-
export declare class EmailService {
|
|
12
|
-
private supabase;
|
|
13
|
-
private config;
|
|
14
|
-
private templateCache;
|
|
15
|
-
constructor(supabase: SupabaseClient, config: EmailConfig);
|
|
16
|
-
/**
|
|
17
|
-
* Send a templated email.
|
|
18
|
-
*
|
|
19
|
-
* Template lookup order:
|
|
20
|
-
* 1. slug + language + organization_id (org-specific translation)
|
|
21
|
-
* 2. slug + language + org IS NULL (system default in requested language)
|
|
22
|
-
* 3. slug + 'en' + org IS NULL (English fallback)
|
|
23
|
-
* 4. fallbackSubject / fallbackHtml from code
|
|
24
|
-
*/
|
|
25
|
-
send(opts: SendEmailOpts): Promise<{
|
|
26
|
-
success: boolean;
|
|
27
|
-
logId?: string;
|
|
28
|
-
}>;
|
|
29
|
-
/**
|
|
30
|
-
* Clear template cache. Call after template is updated via admin UI.
|
|
31
|
-
*/
|
|
32
|
-
clearCache(slug?: string): void;
|
|
33
|
-
/**
|
|
34
|
-
* Resolve transport and send email.
|
|
35
|
-
* Priority: explicit config.transport > auto-detect (gmail > smtp > mailgun).
|
|
36
|
-
*/
|
|
37
|
-
private deliver;
|
|
38
|
-
/**
|
|
39
|
-
* Send via Gmail API using stored OAuth tokens.
|
|
40
|
-
*/
|
|
41
|
-
private deliverViaGmail;
|
|
42
|
-
private resolveTransport;
|
|
43
|
-
/**
|
|
44
|
-
* Template lookup with language + org fallback chain.
|
|
45
|
-
* Results are cached for 5 minutes.
|
|
46
|
-
*/
|
|
47
|
-
private loadTemplate;
|
|
48
|
-
private getCached;
|
|
49
|
-
private setCache;
|
|
50
|
-
/**
|
|
51
|
-
* Render a Handlebars template string with variables.
|
|
52
|
-
* Rejects templates with triple-brace {{{…}}} syntax to prevent escaping bypass.
|
|
53
|
-
*/
|
|
54
|
-
private render;
|
|
55
|
-
/**
|
|
56
|
-
* Create a pending email log entry.
|
|
57
|
-
*/
|
|
58
|
-
private createLog;
|
|
59
|
-
/**
|
|
60
|
-
* Update an email log entry after send attempt.
|
|
61
|
-
*/
|
|
62
|
-
private updateLog;
|
|
63
|
-
}
|
|
64
|
-
//# sourceMappingURL=EmailService.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"EmailService.d.ts","sourceRoot":"","sources":["../../../src/shared/email/EmailService.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE5D,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAqD,MAAM,YAAY,CAAC;AAahH,qBAAa,YAAY;IAIrB,OAAO,CAAC,QAAQ;IAChB,OAAO,CAAC,MAAM;IAJhB,OAAO,CAAC,aAAa,CAAiC;gBAG5C,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,WAAW;IAG7B;;;;;;;;OAQG;IACG,IAAI,CAAC,IAAI,EAAE,aAAa,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,OAAO,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAsD9E;;OAEG;IACH,UAAU,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI;IAa/B;;;OAGG;YACW,OAAO;IA6CrB;;OAEG;YACW,eAAe;IAmC7B,OAAO,CAAC,gBAAgB;IAOxB;;;OAGG;YACW,YAAY;IAqE1B,OAAO,CAAC,SAAS;IAUjB,OAAO,CAAC,QAAQ;IAIhB;;;OAGG;IACH,OAAO,CAAC,MAAM;IAQd;;OAEG;YACW,SAAS;IA0CvB;;OAEG;YACW,SAAS;CAkBxB"}
|