@wopr-network/platform-core 0.1.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/biome.json +61 -0
- package/dist/admin/admin-audit-log-repository.d.ts +33 -0
- package/dist/admin/admin-audit-log-repository.js +102 -0
- package/dist/admin/audit-log.d.ts +49 -0
- package/dist/admin/audit-log.js +63 -0
- package/dist/admin/index.d.ts +6 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/role-store.d.ts +37 -0
- package/dist/admin/role-store.js +106 -0
- package/dist/auth/api-key-repository.d.ts +11 -0
- package/dist/auth/api-key-repository.js +33 -0
- package/dist/auth/api-key-repository.test.d.ts +1 -0
- package/dist/auth/api-key-repository.test.js +46 -0
- package/dist/auth/auth.test.d.ts +1 -0
- package/dist/auth/auth.test.js +140 -0
- package/dist/auth/better-auth.d.ts +42 -0
- package/dist/auth/better-auth.js +196 -0
- package/dist/auth/index.d.ts +186 -0
- package/dist/auth/index.js +422 -0
- package/dist/auth/login-history-repository.d.ts +14 -0
- package/dist/auth/login-history-repository.js +15 -0
- package/dist/auth/login-history-repository.test.d.ts +1 -0
- package/dist/auth/login-history-repository.test.js +47 -0
- package/dist/auth/middleware.d.ts +55 -0
- package/dist/auth/middleware.js +101 -0
- package/dist/auth/middleware.test.d.ts +1 -0
- package/dist/auth/middleware.test.js +213 -0
- package/dist/auth/scoped-tokens.test.d.ts +1 -0
- package/dist/auth/scoped-tokens.test.js +306 -0
- package/dist/auth/tenant-access.test.d.ts +1 -0
- package/dist/auth/tenant-access.test.js +62 -0
- package/dist/auth/user-creator.d.ts +9 -0
- package/dist/auth/user-creator.js +47 -0
- package/dist/auth/user-creator.test.d.ts +1 -0
- package/dist/auth/user-creator.test.js +78 -0
- package/dist/auth/user-role-repository.d.ts +31 -0
- package/dist/auth/user-role-repository.js +53 -0
- package/dist/auth/user-role-repository.test.d.ts +1 -0
- package/dist/auth/user-role-repository.test.js +122 -0
- package/dist/billing/drizzle-webhook-seen-repository.d.ts +10 -0
- package/dist/billing/drizzle-webhook-seen-repository.js +28 -0
- package/dist/billing/index.d.ts +7 -0
- package/dist/billing/index.js +7 -0
- package/dist/billing/payment-processor.d.ts +127 -0
- package/dist/billing/payment-processor.js +8 -0
- package/dist/billing/payment-processor.test.d.ts +1 -0
- package/dist/billing/payment-processor.test.js +71 -0
- package/dist/billing/payram/cents-credits-boundary.test.d.ts +1 -0
- package/dist/billing/payram/cents-credits-boundary.test.js +75 -0
- package/dist/billing/payram/charge-store.d.ts +41 -0
- package/dist/billing/payram/charge-store.js +72 -0
- package/dist/billing/payram/charge-store.test.d.ts +1 -0
- package/dist/billing/payram/charge-store.test.js +64 -0
- package/dist/billing/payram/checkout.d.ts +15 -0
- package/dist/billing/payram/checkout.js +24 -0
- package/dist/billing/payram/checkout.test.d.ts +1 -0
- package/dist/billing/payram/checkout.test.js +74 -0
- package/dist/billing/payram/client.d.ts +7 -0
- package/dist/billing/payram/client.js +15 -0
- package/dist/billing/payram/client.test.d.ts +1 -0
- package/dist/billing/payram/client.test.js +52 -0
- package/dist/billing/payram/index.d.ts +8 -0
- package/dist/billing/payram/index.js +4 -0
- package/dist/billing/payram/types.d.ts +40 -0
- package/dist/billing/payram/types.js +1 -0
- package/dist/billing/payram/webhook.d.ts +19 -0
- package/dist/billing/payram/webhook.js +67 -0
- package/dist/billing/payram/webhook.test.d.ts +7 -0
- package/dist/billing/payram/webhook.test.js +248 -0
- package/dist/billing/stripe/cents-credits-boundary.test.d.ts +1 -0
- package/dist/billing/stripe/cents-credits-boundary.test.js +62 -0
- package/dist/billing/stripe/checkout.d.ts +20 -0
- package/dist/billing/stripe/checkout.js +63 -0
- package/dist/billing/stripe/checkout.test.d.ts +1 -0
- package/dist/billing/stripe/checkout.test.js +148 -0
- package/dist/billing/stripe/client.d.ts +14 -0
- package/dist/billing/stripe/client.js +33 -0
- package/dist/billing/stripe/client.test.d.ts +1 -0
- package/dist/billing/stripe/client.test.js +58 -0
- package/dist/billing/stripe/credit-prices.d.ts +63 -0
- package/dist/billing/stripe/credit-prices.js +81 -0
- package/dist/billing/stripe/credit-prices.test.d.ts +1 -0
- package/dist/billing/stripe/credit-prices.test.js +87 -0
- package/dist/billing/stripe/index.d.ts +14 -0
- package/dist/billing/stripe/index.js +8 -0
- package/dist/billing/stripe/payment-methods-detach-all.test.d.ts +1 -0
- package/dist/billing/stripe/payment-methods-detach-all.test.js +40 -0
- package/dist/billing/stripe/payment-methods.d.ts +25 -0
- package/dist/billing/stripe/payment-methods.js +53 -0
- package/dist/billing/stripe/payment-methods.test.d.ts +1 -0
- package/dist/billing/stripe/payment-methods.test.js +122 -0
- package/dist/billing/stripe/portal.d.ts +10 -0
- package/dist/billing/stripe/portal.js +16 -0
- package/dist/billing/stripe/portal.test.d.ts +1 -0
- package/dist/billing/stripe/portal.test.js +48 -0
- package/dist/billing/stripe/setup-intent.d.ts +16 -0
- package/dist/billing/stripe/setup-intent.js +22 -0
- package/dist/billing/stripe/setup-intent.test.d.ts +1 -0
- package/dist/billing/stripe/setup-intent.test.js +58 -0
- package/dist/billing/stripe/stripe-payment-processor.d.ts +49 -0
- package/dist/billing/stripe/stripe-payment-processor.js +166 -0
- package/dist/billing/stripe/stripe-payment-processor.test.d.ts +1 -0
- package/dist/billing/stripe/stripe-payment-processor.test.js +413 -0
- package/dist/billing/stripe/tenant-store.d.ts +56 -0
- package/dist/billing/stripe/tenant-store.js +119 -0
- package/dist/billing/stripe/tenant-store.test.d.ts +1 -0
- package/dist/billing/stripe/tenant-store.test.js +97 -0
- package/dist/billing/stripe/types.d.ts +49 -0
- package/dist/billing/stripe/types.js +1 -0
- package/dist/billing/webhook-seen-repository.d.ts +14 -0
- package/dist/billing/webhook-seen-repository.js +13 -0
- package/dist/config/billing-env.test.d.ts +1 -0
- package/dist/config/billing-env.test.js +48 -0
- package/dist/config/index.d.ts +46 -0
- package/dist/config/index.js +38 -0
- package/dist/config/logger.d.ts +2 -0
- package/dist/config/logger.js +11 -0
- package/dist/config/provider-endpoints.d.ts +6 -0
- package/dist/config/provider-endpoints.js +12 -0
- package/dist/credits/auto-topup-charge.d.ts +27 -0
- package/dist/credits/auto-topup-charge.js +139 -0
- package/dist/credits/auto-topup-charge.test.d.ts +1 -0
- package/dist/credits/auto-topup-charge.test.js +242 -0
- package/dist/credits/auto-topup-event-log-repository.d.ts +16 -0
- package/dist/credits/auto-topup-event-log-repository.js +18 -0
- package/dist/credits/auto-topup-event-log-repository.test.d.ts +1 -0
- package/dist/credits/auto-topup-event-log-repository.test.js +83 -0
- package/dist/credits/auto-topup-schedule.d.ts +27 -0
- package/dist/credits/auto-topup-schedule.js +66 -0
- package/dist/credits/auto-topup-schedule.test.d.ts +1 -0
- package/dist/credits/auto-topup-schedule.test.js +145 -0
- package/dist/credits/auto-topup-settings-repository.d.ts +54 -0
- package/dist/credits/auto-topup-settings-repository.js +184 -0
- package/dist/credits/auto-topup-settings-repository.test.d.ts +1 -0
- package/dist/credits/auto-topup-settings-repository.test.js +104 -0
- package/dist/credits/auto-topup-usage.d.ts +22 -0
- package/dist/credits/auto-topup-usage.js +56 -0
- package/dist/credits/auto-topup-usage.test.d.ts +1 -0
- package/dist/credits/auto-topup-usage.test.js +181 -0
- package/dist/credits/credit-expiry-cron.d.ts +19 -0
- package/dist/credits/credit-expiry-cron.js +50 -0
- package/dist/credits/credit-expiry-cron.test.d.ts +1 -0
- package/dist/credits/credit-expiry-cron.test.js +67 -0
- package/dist/credits/credit-ledger-extra.test.d.ts +1 -0
- package/dist/credits/credit-ledger-extra.test.js +40 -0
- package/dist/credits/credit-ledger.bench.d.ts +1 -0
- package/dist/credits/credit-ledger.bench.js +33 -0
- package/dist/credits/credit-ledger.d.ts +130 -0
- package/dist/credits/credit-ledger.js +293 -0
- package/dist/credits/credit-ledger.test.d.ts +4 -0
- package/dist/credits/credit-ledger.test.js +203 -0
- package/dist/credits/credit-transaction-repository.d.ts +17 -0
- package/dist/credits/credit-transaction-repository.js +35 -0
- package/dist/credits/credit-transaction-repository.test.d.ts +1 -0
- package/dist/credits/credit-transaction-repository.test.js +232 -0
- package/dist/credits/credit.d.ts +75 -0
- package/dist/credits/credit.js +139 -0
- package/dist/credits/credit.test.d.ts +1 -0
- package/dist/credits/credit.test.js +196 -0
- package/dist/credits/dividend-cron.d.ts +29 -0
- package/dist/credits/dividend-cron.js +88 -0
- package/dist/credits/dividend-cron.test.d.ts +1 -0
- package/dist/credits/dividend-cron.test.js +128 -0
- package/dist/credits/dividend-repository.d.ts +29 -0
- package/dist/credits/dividend-repository.js +126 -0
- package/dist/credits/dividend-repository.test.d.ts +1 -0
- package/dist/credits/dividend-repository.test.js +176 -0
- package/dist/credits/index.d.ts +9 -0
- package/dist/credits/index.js +5 -0
- package/dist/credits/repository-types.d.ts +29 -0
- package/dist/credits/repository-types.js +1 -0
- package/dist/credits/signup-grant.d.ts +12 -0
- package/dist/credits/signup-grant.js +35 -0
- package/dist/credits/signup-grant.test.d.ts +1 -0
- package/dist/credits/signup-grant.test.js +51 -0
- package/dist/credits/tenant-customer-repository.d.ts +30 -0
- package/dist/credits/tenant-customer-repository.js +5 -0
- package/dist/db/auth-user-repository.d.ts +46 -0
- package/dist/db/auth-user-repository.js +90 -0
- package/dist/db/credit-column.d.ts +27 -0
- package/dist/db/credit-column.js +13 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.js +8 -0
- package/dist/db/schema/account-deletion-requests.d.ts +203 -0
- package/dist/db/schema/account-deletion-requests.js +36 -0
- package/dist/db/schema/account-export-requests.d.ts +148 -0
- package/dist/db/schema/account-export-requests.js +19 -0
- package/dist/db/schema/admin-audit.d.ts +194 -0
- package/dist/db/schema/admin-audit.js +21 -0
- package/dist/db/schema/admin-users.d.ts +177 -0
- package/dist/db/schema/admin-users.js +23 -0
- package/dist/db/schema/affiliate-fraud.d.ts +160 -0
- package/dist/db/schema/affiliate-fraud.js +18 -0
- package/dist/db/schema/affiliate.d.ts +277 -0
- package/dist/db/schema/affiliate.js +32 -0
- package/dist/db/schema/coupon-codes.d.ts +143 -0
- package/dist/db/schema/coupon-codes.js +17 -0
- package/dist/db/schema/credit-auto-topup-settings.d.ts +232 -0
- package/dist/db/schema/credit-auto-topup-settings.js +27 -0
- package/dist/db/schema/credit-auto-topup.d.ts +130 -0
- package/dist/db/schema/credit-auto-topup.js +21 -0
- package/dist/db/schema/credits.d.ts +283 -0
- package/dist/db/schema/credits.js +38 -0
- package/dist/db/schema/dividend-distributions.d.ts +130 -0
- package/dist/db/schema/dividend-distributions.js +19 -0
- package/dist/db/schema/email-notifications.d.ts +99 -0
- package/dist/db/schema/email-notifications.js +21 -0
- package/dist/db/schema/index.d.ts +33 -0
- package/dist/db/schema/index.js +33 -0
- package/dist/db/schema/meter-events.d.ts +599 -0
- package/dist/db/schema/meter-events.js +55 -0
- package/dist/db/schema/notification-preferences.d.ts +165 -0
- package/dist/db/schema/notification-preferences.js +18 -0
- package/dist/db/schema/notification-queue.d.ts +236 -0
- package/dist/db/schema/notification-queue.js +40 -0
- package/dist/db/schema/org-memberships.d.ts +63 -0
- package/dist/db/schema/org-memberships.js +15 -0
- package/dist/db/schema/organization-members.d.ts +235 -0
- package/dist/db/schema/organization-members.js +27 -0
- package/dist/db/schema/payram.d.ts +164 -0
- package/dist/db/schema/payram.js +21 -0
- package/dist/db/schema/platform-api-keys.d.ts +143 -0
- package/dist/db/schema/platform-api-keys.js +20 -0
- package/dist/db/schema/promotion-redemptions.d.ts +143 -0
- package/dist/db/schema/promotion-redemptions.js +18 -0
- package/dist/db/schema/promotions.d.ts +445 -0
- package/dist/db/schema/promotions.js +48 -0
- package/dist/db/schema/provider-credentials.d.ts +201 -0
- package/dist/db/schema/provider-credentials.js +36 -0
- package/dist/db/schema/rate-limit-entries.d.ts +75 -0
- package/dist/db/schema/rate-limit-entries.js +7 -0
- package/dist/db/schema/secret-audit-log.d.ts +109 -0
- package/dist/db/schema/secret-audit-log.js +15 -0
- package/dist/db/schema/session-usage.d.ts +194 -0
- package/dist/db/schema/session-usage.js +19 -0
- package/dist/db/schema/spending-limits.d.ts +92 -0
- package/dist/db/schema/spending-limits.js +8 -0
- package/dist/db/schema/tenant-addons.d.ts +58 -0
- package/dist/db/schema/tenant-addons.js +9 -0
- package/dist/db/schema/tenant-api-keys.d.ts +131 -0
- package/dist/db/schema/tenant-api-keys.js +21 -0
- package/dist/db/schema/tenant-capability-settings.d.ts +79 -0
- package/dist/db/schema/tenant-capability-settings.js +12 -0
- package/dist/db/schema/tenant-customers.d.ts +303 -0
- package/dist/db/schema/tenant-customers.js +25 -0
- package/dist/db/schema/tenants.d.ts +126 -0
- package/dist/db/schema/tenants.js +18 -0
- package/dist/db/schema/user-roles.d.ts +98 -0
- package/dist/db/schema/user-roles.js +18 -0
- package/dist/db/schema/webhook-seen-events.d.ts +58 -0
- package/dist/db/schema/webhook-seen-events.js +9 -0
- package/dist/email/billing-emails.d.ts +51 -0
- package/dist/email/billing-emails.js +163 -0
- package/dist/email/billing-emails.test.d.ts +1 -0
- package/dist/email/billing-emails.test.js +162 -0
- package/dist/email/client.d.ts +51 -0
- package/dist/email/client.js +102 -0
- package/dist/email/client.test.d.ts +1 -0
- package/dist/email/client.test.js +120 -0
- package/dist/email/drizzle-billing-email-repository.d.ts +21 -0
- package/dist/email/drizzle-billing-email-repository.js +36 -0
- package/dist/email/drizzle-billing-email-repository.test.d.ts +1 -0
- package/dist/email/drizzle-billing-email-repository.test.js +42 -0
- package/dist/email/index.d.ts +33 -0
- package/dist/email/index.js +22 -0
- package/dist/email/notification-preferences-store.d.ts +12 -0
- package/dist/email/notification-preferences-store.js +82 -0
- package/dist/email/notification-preferences-store.test.d.ts +1 -0
- package/dist/email/notification-preferences-store.test.js +86 -0
- package/dist/email/notification-queue-store.d.ts +25 -0
- package/dist/email/notification-queue-store.js +97 -0
- package/dist/email/notification-queue-store.test.d.ts +1 -0
- package/dist/email/notification-queue-store.test.js +177 -0
- package/dist/email/notification-repository-types.d.ts +70 -0
- package/dist/email/notification-repository-types.js +6 -0
- package/dist/email/notification-service.d.ts +41 -0
- package/dist/email/notification-service.js +196 -0
- package/dist/email/notification-service.test.d.ts +1 -0
- package/dist/email/notification-service.test.js +160 -0
- package/dist/email/notification-templates.d.ts +18 -0
- package/dist/email/notification-templates.js +574 -0
- package/dist/email/notification-templates.test.d.ts +1 -0
- package/dist/email/notification-templates.test.js +238 -0
- package/dist/email/notification-worker.d.ts +24 -0
- package/dist/email/notification-worker.js +109 -0
- package/dist/email/notification-worker.test.d.ts +1 -0
- package/dist/email/notification-worker.test.js +153 -0
- package/dist/email/require-verified.d.ts +25 -0
- package/dist/email/require-verified.js +52 -0
- package/dist/email/require-verified.test.d.ts +1 -0
- package/dist/email/require-verified.test.js +62 -0
- package/dist/email/resend-adapter.d.ts +47 -0
- package/dist/email/resend-adapter.js +137 -0
- package/dist/email/resend-adapter.test.d.ts +1 -0
- package/dist/email/resend-adapter.test.js +190 -0
- package/dist/email/templates.d.ts +22 -0
- package/dist/email/templates.js +359 -0
- package/dist/email/templates.test.d.ts +1 -0
- package/dist/email/templates.test.js +170 -0
- package/dist/email/verification.d.ts +42 -0
- package/dist/email/verification.js +83 -0
- package/dist/email/verification.test.d.ts +1 -0
- package/dist/email/verification.test.js +141 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +23 -0
- package/dist/metering/aggregator.d.ts +54 -0
- package/dist/metering/aggregator.js +123 -0
- package/dist/metering/aggregator.test.d.ts +1 -0
- package/dist/metering/aggregator.test.js +179 -0
- package/dist/metering/dlq.d.ts +31 -0
- package/dist/metering/dlq.js +82 -0
- package/dist/metering/dlq.test.d.ts +1 -0
- package/dist/metering/dlq.test.js +117 -0
- package/dist/metering/drizzle-usage-summary-repository.d.ts +67 -0
- package/dist/metering/drizzle-usage-summary-repository.js +98 -0
- package/dist/metering/emitter.d.ts +66 -0
- package/dist/metering/emitter.js +185 -0
- package/dist/metering/emitter.test.d.ts +1 -0
- package/dist/metering/emitter.test.js +171 -0
- package/dist/metering/index.d.ts +11 -0
- package/dist/metering/index.js +5 -0
- package/dist/metering/load-test.bench.d.ts +1 -0
- package/dist/metering/load-test.bench.js +103 -0
- package/dist/metering/meter-event-repository.d.ts +33 -0
- package/dist/metering/meter-event-repository.js +58 -0
- package/dist/metering/meter-repositories.test.d.ts +1 -0
- package/dist/metering/meter-repositories.test.js +419 -0
- package/dist/metering/metering.test.d.ts +1 -0
- package/dist/metering/metering.test.js +1046 -0
- package/dist/metering/reconciliation-cron.d.ts +37 -0
- package/dist/metering/reconciliation-cron.js +85 -0
- package/dist/metering/reconciliation-cron.test.d.ts +1 -0
- package/dist/metering/reconciliation-cron.test.js +162 -0
- package/dist/metering/reconciliation-repository.d.ts +27 -0
- package/dist/metering/reconciliation-repository.js +43 -0
- package/dist/metering/reconciliation-repository.test.d.ts +1 -0
- package/dist/metering/reconciliation-repository.test.js +160 -0
- package/dist/metering/types.d.ts +88 -0
- package/dist/metering/types.js +1 -0
- package/dist/metering/wal.d.ts +49 -0
- package/dist/metering/wal.js +124 -0
- package/dist/metering/wal.test.d.ts +1 -0
- package/dist/metering/wal.test.js +175 -0
- package/dist/middleware/csrf.d.ts +24 -0
- package/dist/middleware/csrf.js +80 -0
- package/dist/middleware/csrf.test.d.ts +1 -0
- package/dist/middleware/csrf.test.js +152 -0
- package/dist/middleware/drizzle-rate-limit-repository.d.ts +9 -0
- package/dist/middleware/drizzle-rate-limit-repository.js +52 -0
- package/dist/middleware/drizzle-rate-limit-repository.test.d.ts +1 -0
- package/dist/middleware/drizzle-rate-limit-repository.test.js +74 -0
- package/dist/middleware/get-client-ip.d.ts +22 -0
- package/dist/middleware/get-client-ip.js +51 -0
- package/dist/middleware/get-client-ip.test.d.ts +1 -0
- package/dist/middleware/get-client-ip.test.js +40 -0
- package/dist/middleware/index.d.ts +5 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware/rate-limit-repository.d.ts +19 -0
- package/dist/middleware/rate-limit-repository.js +1 -0
- package/dist/middleware/rate-limit.d.ts +57 -0
- package/dist/middleware/rate-limit.js +109 -0
- package/dist/middleware/rate-limit.test.d.ts +1 -0
- package/dist/middleware/rate-limit.test.js +247 -0
- package/dist/security/credential-vault/audit-repository.d.ts +27 -0
- package/dist/security/credential-vault/audit-repository.js +42 -0
- package/dist/security/credential-vault/audit-repository.test.d.ts +1 -0
- package/dist/security/credential-vault/audit-repository.test.js +78 -0
- package/dist/security/credential-vault/credential-repository.d.ts +94 -0
- package/dist/security/credential-vault/credential-repository.js +145 -0
- package/dist/security/credential-vault/credential-repository.test.d.ts +1 -0
- package/dist/security/credential-vault/credential-repository.test.js +206 -0
- package/dist/security/credential-vault/index.d.ts +12 -0
- package/dist/security/credential-vault/index.js +6 -0
- package/dist/security/credential-vault/key-rotation.d.ts +18 -0
- package/dist/security/credential-vault/key-rotation.js +52 -0
- package/dist/security/credential-vault/key-rotation.test.d.ts +1 -0
- package/dist/security/credential-vault/key-rotation.test.js +95 -0
- package/dist/security/credential-vault/migrate-plaintext.d.ts +15 -0
- package/dist/security/credential-vault/migrate-plaintext.js +80 -0
- package/dist/security/credential-vault/migrate-plaintext.test.d.ts +1 -0
- package/dist/security/credential-vault/migrate-plaintext.test.js +111 -0
- package/dist/security/credential-vault/migration-check.d.ts +15 -0
- package/dist/security/credential-vault/migration-check.js +71 -0
- package/dist/security/credential-vault/migration-check.test.d.ts +1 -0
- package/dist/security/credential-vault/migration-check.test.js +457 -0
- package/dist/security/credential-vault/store.d.ts +106 -0
- package/dist/security/credential-vault/store.js +181 -0
- package/dist/security/credential-vault/store.test.d.ts +1 -0
- package/dist/security/credential-vault/store.test.js +482 -0
- package/dist/security/encryption.d.ts +22 -0
- package/dist/security/encryption.js +53 -0
- package/dist/security/encryption.test.d.ts +1 -0
- package/dist/security/encryption.test.js +95 -0
- package/dist/security/host-validation.d.ts +11 -0
- package/dist/security/host-validation.js +108 -0
- package/dist/security/host-validation.test.d.ts +1 -0
- package/dist/security/host-validation.test.js +106 -0
- package/dist/security/index.d.ts +11 -0
- package/dist/security/index.js +11 -0
- package/dist/security/key-audit.d.ts +16 -0
- package/dist/security/key-audit.js +35 -0
- package/dist/security/key-audit.test.d.ts +1 -0
- package/dist/security/key-audit.test.js +50 -0
- package/dist/security/key-injection.d.ts +28 -0
- package/dist/security/key-injection.js +57 -0
- package/dist/security/key-injection.test.d.ts +1 -0
- package/dist/security/key-injection.test.js +97 -0
- package/dist/security/key-validation.d.ts +16 -0
- package/dist/security/key-validation.js +78 -0
- package/dist/security/key-validation.test.d.ts +1 -0
- package/dist/security/key-validation.test.js +87 -0
- package/dist/security/redirect-allowlist.d.ts +6 -0
- package/dist/security/redirect-allowlist.js +36 -0
- package/dist/security/redirect-allowlist.test.d.ts +1 -0
- package/dist/security/redirect-allowlist.test.js +55 -0
- package/dist/security/tenant-keys/capability-settings-store.d.ts +22 -0
- package/dist/security/tenant-keys/capability-settings-store.js +33 -0
- package/dist/security/tenant-keys/capability-settings-store.test.d.ts +1 -0
- package/dist/security/tenant-keys/capability-settings-store.test.js +77 -0
- package/dist/security/tenant-keys/index.d.ts +10 -0
- package/dist/security/tenant-keys/index.js +5 -0
- package/dist/security/tenant-keys/key-resolution-repository.d.ts +15 -0
- package/dist/security/tenant-keys/key-resolution-repository.js +18 -0
- package/dist/security/tenant-keys/key-resolution-repository.test.d.ts +1 -0
- package/dist/security/tenant-keys/key-resolution-repository.test.js +72 -0
- package/dist/security/tenant-keys/key-resolution.d.ts +39 -0
- package/dist/security/tenant-keys/key-resolution.js +59 -0
- package/dist/security/tenant-keys/key-resolution.test.d.ts +1 -0
- package/dist/security/tenant-keys/key-resolution.test.js +97 -0
- package/dist/security/tenant-keys/org-key-resolution.d.ts +30 -0
- package/dist/security/tenant-keys/org-key-resolution.js +50 -0
- package/dist/security/tenant-keys/org-key-resolution.test.d.ts +1 -0
- package/dist/security/tenant-keys/org-key-resolution.test.js +103 -0
- package/dist/security/tenant-keys/tenant-key-repository.d.ts +36 -0
- package/dist/security/tenant-keys/tenant-key-repository.js +96 -0
- package/dist/security/tenant-keys/tenant-key-repository.test.d.ts +1 -0
- package/dist/security/tenant-keys/tenant-key-repository.test.js +114 -0
- package/dist/security/types.d.ts +35 -0
- package/dist/security/types.js +15 -0
- package/dist/tenancy/drizzle-org-repository.d.ts +40 -0
- package/dist/tenancy/drizzle-org-repository.js +126 -0
- package/dist/tenancy/index.d.ts +6 -0
- package/dist/tenancy/index.js +3 -0
- package/dist/tenancy/org-member-repository.d.ts +57 -0
- package/dist/tenancy/org-member-repository.js +99 -0
- package/dist/tenancy/org-repository.test.d.ts +1 -0
- package/dist/tenancy/org-repository.test.js +143 -0
- package/dist/tenancy/org-service.d.ts +70 -0
- package/dist/tenancy/org-service.js +223 -0
- package/dist/tenancy/org-service.test.d.ts +1 -0
- package/dist/tenancy/org-service.test.js +550 -0
- package/dist/test/db.d.ts +33 -0
- package/dist/test/db.js +65 -0
- package/dist/trpc/index.d.ts +1 -0
- package/dist/trpc/index.js +1 -0
- package/dist/trpc/init.d.ts +49 -0
- package/dist/trpc/init.js +108 -0
- package/dist/trpc/init.test.d.ts +1 -0
- package/dist/trpc/init.test.js +154 -0
- package/drizzle/migrations/0000_slippery_mandrill.sql +559 -0
- package/drizzle/migrations/meta/0000_snapshot.json +4374 -0
- package/drizzle/migrations/meta/_journal.json +13 -0
- package/drizzle.config.ts +41 -0
- package/package.json +64 -0
- package/src/admin/admin-audit-log-repository.ts +135 -0
- package/src/admin/audit-log.ts +111 -0
- package/src/admin/index.ts +6 -0
- package/src/admin/role-store.ts +134 -0
- package/src/auth/api-key-repository.test.ts +63 -0
- package/src/auth/api-key-repository.ts +46 -0
- package/src/auth/auth.test.ts +166 -0
- package/src/auth/better-auth.ts +216 -0
- package/src/auth/index.ts +520 -0
- package/src/auth/login-history-repository.test.ts +54 -0
- package/src/auth/login-history-repository.ts +28 -0
- package/src/auth/middleware.test.ts +264 -0
- package/src/auth/middleware.ts +117 -0
- package/src/auth/scoped-tokens.test.ts +362 -0
- package/src/auth/tenant-access.test.ts +69 -0
- package/src/auth/user-creator.test.ts +98 -0
- package/src/auth/user-creator.ts +54 -0
- package/src/auth/user-role-repository.test.ts +149 -0
- package/src/auth/user-role-repository.ts +67 -0
- package/src/billing/drizzle-webhook-seen-repository.ts +34 -0
- package/src/billing/index.ts +22 -0
- package/src/billing/payment-processor.test.ts +93 -0
- package/src/billing/payment-processor.ts +150 -0
- package/src/billing/payram/cents-credits-boundary.test.ts +84 -0
- package/src/billing/payram/charge-store.test.ts +84 -0
- package/src/billing/payram/charge-store.ts +109 -0
- package/src/billing/payram/checkout.test.ts +99 -0
- package/src/billing/payram/checkout.ts +40 -0
- package/src/billing/payram/client.test.ts +62 -0
- package/src/billing/payram/client.ts +21 -0
- package/src/billing/payram/index.ts +14 -0
- package/src/billing/payram/types.ts +44 -0
- package/src/billing/payram/webhook.test.ts +318 -0
- package/src/billing/payram/webhook.ts +97 -0
- package/src/billing/stripe/cents-credits-boundary.test.ts +70 -0
- package/src/billing/stripe/checkout.test.ts +186 -0
- package/src/billing/stripe/checkout.ts +82 -0
- package/src/billing/stripe/client.test.ts +64 -0
- package/src/billing/stripe/client.ts +39 -0
- package/src/billing/stripe/credit-prices.test.ts +114 -0
- package/src/billing/stripe/credit-prices.ts +113 -0
- package/src/billing/stripe/index.ts +14 -0
- package/src/billing/stripe/payment-methods-detach-all.test.ts +53 -0
- package/src/billing/stripe/payment-methods.test.ts +157 -0
- package/src/billing/stripe/payment-methods.ts +76 -0
- package/src/billing/stripe/portal.test.ts +63 -0
- package/src/billing/stripe/portal.ts +25 -0
- package/src/billing/stripe/setup-intent.test.ts +78 -0
- package/src/billing/stripe/setup-intent.ts +34 -0
- package/src/billing/stripe/stripe-payment-processor.test.ts +517 -0
- package/src/billing/stripe/stripe-payment-processor.ts +255 -0
- package/src/billing/stripe/tenant-store.test.ts +124 -0
- package/src/billing/stripe/tenant-store.ts +151 -0
- package/src/billing/stripe/types.ts +53 -0
- package/src/billing/webhook-seen-repository.ts +24 -0
- package/src/config/billing-env.test.ts +54 -0
- package/src/config/index.ts +44 -0
- package/src/config/logger.ts +12 -0
- package/src/config/provider-endpoints.ts +14 -0
- package/src/credits/auto-topup-charge.test.ts +292 -0
- package/src/credits/auto-topup-charge.ts +171 -0
- package/src/credits/auto-topup-event-log-repository.test.ts +99 -0
- package/src/credits/auto-topup-event-log-repository.ts +30 -0
- package/src/credits/auto-topup-schedule.test.ts +179 -0
- package/src/credits/auto-topup-schedule.ts +93 -0
- package/src/credits/auto-topup-settings-repository.test.ts +123 -0
- package/src/credits/auto-topup-settings-repository.ts +245 -0
- package/src/credits/auto-topup-usage.test.ts +220 -0
- package/src/credits/auto-topup-usage.ts +68 -0
- package/src/credits/credit-expiry-cron.test.ts +125 -0
- package/src/credits/credit-expiry-cron.ts +76 -0
- package/src/credits/credit-ledger-extra.test.ts +57 -0
- package/src/credits/credit-ledger.bench.ts +56 -0
- package/src/credits/credit-ledger.test.ts +276 -0
- package/src/credits/credit-ledger.ts +450 -0
- package/src/credits/credit-transaction-repository.test.ts +274 -0
- package/src/credits/credit-transaction-repository.ts +62 -0
- package/src/credits/credit.test.ts +234 -0
- package/src/credits/credit.ts +160 -0
- package/src/credits/dividend-cron.test.ts +158 -0
- package/src/credits/dividend-cron.ts +127 -0
- package/src/credits/dividend-repository.test.ts +223 -0
- package/src/credits/dividend-repository.ts +182 -0
- package/src/credits/index.ts +25 -0
- package/src/credits/repository-types.ts +33 -0
- package/src/credits/signup-grant.test.ts +63 -0
- package/src/credits/signup-grant.ts +44 -0
- package/src/credits/tenant-customer-repository.ts +28 -0
- package/src/db/auth-user-repository.ts +124 -0
- package/src/db/credit-column.ts +17 -0
- package/src/db/index.ts +21 -0
- package/src/db/schema/account-deletion-requests.ts +41 -0
- package/src/db/schema/account-export-requests.ts +24 -0
- package/src/db/schema/admin-audit.ts +26 -0
- package/src/db/schema/admin-users.ts +31 -0
- package/src/db/schema/affiliate-fraud.ts +23 -0
- package/src/db/schema/affiliate.ts +38 -0
- package/src/db/schema/coupon-codes.ts +22 -0
- package/src/db/schema/credit-auto-topup-settings.ts +32 -0
- package/src/db/schema/credit-auto-topup.ts +26 -0
- package/src/db/schema/credits.ts +44 -0
- package/src/db/schema/dividend-distributions.ts +24 -0
- package/src/db/schema/email-notifications.ts +26 -0
- package/src/db/schema/index.ts +33 -0
- package/src/db/schema/meter-events.ts +70 -0
- package/src/db/schema/notification-preferences.ts +19 -0
- package/src/db/schema/notification-queue.ts +45 -0
- package/src/db/schema/org-memberships.ts +20 -0
- package/src/db/schema/organization-members.ts +37 -0
- package/src/db/schema/payram.ts +26 -0
- package/src/db/schema/platform-api-keys.ts +25 -0
- package/src/db/schema/promotion-redemptions.ts +23 -0
- package/src/db/schema/promotions.ts +57 -0
- package/src/db/schema/provider-credentials.ts +41 -0
- package/src/db/schema/rate-limit-entries.ts +12 -0
- package/src/db/schema/secret-audit-log.ts +20 -0
- package/src/db/schema/session-usage.ts +24 -0
- package/src/db/schema/spending-limits.ts +9 -0
- package/src/db/schema/tenant-addons.ts +14 -0
- package/src/db/schema/tenant-api-keys.ts +26 -0
- package/src/db/schema/tenant-capability-settings.ts +17 -0
- package/src/db/schema/tenant-customers.ts +35 -0
- package/src/db/schema/tenants.ts +23 -0
- package/src/db/schema/user-roles.ts +23 -0
- package/src/db/schema/webhook-seen-events.ts +14 -0
- package/src/email/billing-emails.test.ts +198 -0
- package/src/email/billing-emails.ts +211 -0
- package/src/email/client.test.ts +149 -0
- package/src/email/client.ts +137 -0
- package/src/email/drizzle-billing-email-repository.test.ts +52 -0
- package/src/email/drizzle-billing-email-repository.ts +59 -0
- package/src/email/index.ts +57 -0
- package/src/email/notification-preferences-store.test.ts +102 -0
- package/src/email/notification-preferences-store.ts +90 -0
- package/src/email/notification-queue-store.test.ts +215 -0
- package/src/email/notification-queue-store.ts +127 -0
- package/src/email/notification-repository-types.ts +101 -0
- package/src/email/notification-service.test.ts +178 -0
- package/src/email/notification-service.ts +265 -0
- package/src/email/notification-templates.test.ts +261 -0
- package/src/email/notification-templates.ts +727 -0
- package/src/email/notification-worker.test.ts +189 -0
- package/src/email/notification-worker.ts +133 -0
- package/src/email/require-verified.ts +65 -0
- package/src/email/resend-adapter.test.ts +253 -0
- package/src/email/resend-adapter.ts +157 -0
- package/src/email/templates.test.ts +217 -0
- package/src/email/templates.ts +469 -0
- package/src/email/verification.test.ts +185 -0
- package/src/email/verification.ts +110 -0
- package/src/index.ts +51 -0
- package/src/metering/aggregator.test.ts +239 -0
- package/src/metering/aggregator.ts +160 -0
- package/src/metering/dlq.test.ts +134 -0
- package/src/metering/dlq.ts +102 -0
- package/src/metering/drizzle-usage-summary-repository.ts +167 -0
- package/src/metering/emitter.test.ts +202 -0
- package/src/metering/emitter.ts +227 -0
- package/src/metering/index.ts +21 -0
- package/src/metering/load-test.bench.ts +130 -0
- package/src/metering/meter-event-repository.ts +87 -0
- package/src/metering/meter-repositories.test.ts +491 -0
- package/src/metering/metering.test.ts +1317 -0
- package/src/metering/reconciliation-cron.test.ts +202 -0
- package/src/metering/reconciliation-cron.ts +134 -0
- package/src/metering/reconciliation-repository.test.ts +196 -0
- package/src/metering/reconciliation-repository.ts +83 -0
- package/src/metering/types.ts +93 -0
- package/src/metering/wal.test.ts +222 -0
- package/src/metering/wal.ts +139 -0
- package/src/middleware/csrf.test.ts +178 -0
- package/src/middleware/csrf.ts +101 -0
- package/src/middleware/drizzle-rate-limit-repository.test.ts +97 -0
- package/src/middleware/drizzle-rate-limit-repository.ts +57 -0
- package/src/middleware/get-client-ip.test.ts +49 -0
- package/src/middleware/get-client-ip.ts +62 -0
- package/src/middleware/index.ts +12 -0
- package/src/middleware/rate-limit-repository.ts +22 -0
- package/src/middleware/rate-limit.test.ts +338 -0
- package/src/middleware/rate-limit.ts +169 -0
- package/src/security/credential-vault/audit-repository.test.ts +91 -0
- package/src/security/credential-vault/audit-repository.ts +64 -0
- package/src/security/credential-vault/credential-repository.test.ts +264 -0
- package/src/security/credential-vault/credential-repository.ts +233 -0
- package/src/security/credential-vault/index.ts +26 -0
- package/src/security/credential-vault/key-rotation.test.ts +139 -0
- package/src/security/credential-vault/key-rotation.ts +70 -0
- package/src/security/credential-vault/migrate-plaintext.test.ts +138 -0
- package/src/security/credential-vault/migrate-plaintext.ts +101 -0
- package/src/security/credential-vault/migration-check.test.ts +533 -0
- package/src/security/credential-vault/migration-check.ts +88 -0
- package/src/security/credential-vault/store.test.ts +569 -0
- package/src/security/credential-vault/store.ts +284 -0
- package/src/security/encryption.test.ts +114 -0
- package/src/security/encryption.ts +65 -0
- package/src/security/host-validation.test.ts +136 -0
- package/src/security/host-validation.ts +116 -0
- package/src/security/index.ts +59 -0
- package/src/security/key-audit.test.ts +57 -0
- package/src/security/key-audit.ts +45 -0
- package/src/security/key-injection.test.ts +131 -0
- package/src/security/key-injection.ts +71 -0
- package/src/security/key-validation.test.ts +111 -0
- package/src/security/key-validation.ts +84 -0
- package/src/security/redirect-allowlist.test.ts +70 -0
- package/src/security/redirect-allowlist.ts +35 -0
- package/src/security/tenant-keys/capability-settings-store.test.ts +98 -0
- package/src/security/tenant-keys/capability-settings-store.ts +53 -0
- package/src/security/tenant-keys/index.ts +10 -0
- package/src/security/tenant-keys/key-resolution-repository.test.ts +95 -0
- package/src/security/tenant-keys/key-resolution-repository.ts +31 -0
- package/src/security/tenant-keys/key-resolution.test.ts +173 -0
- package/src/security/tenant-keys/key-resolution.ts +87 -0
- package/src/security/tenant-keys/org-key-resolution.test.ts +217 -0
- package/src/security/tenant-keys/org-key-resolution.ts +76 -0
- package/src/security/tenant-keys/tenant-key-repository.test.ts +143 -0
- package/src/security/tenant-keys/tenant-key-repository.ts +130 -0
- package/src/security/types.ts +43 -0
- package/src/tenancy/drizzle-org-repository.ts +169 -0
- package/src/tenancy/index.ts +6 -0
- package/src/tenancy/org-member-repository.ts +159 -0
- package/src/tenancy/org-repository.test.ts +172 -0
- package/src/tenancy/org-service.test.ts +634 -0
- package/src/tenancy/org-service.ts +290 -0
- package/src/test/db.ts +97 -0
- package/src/trpc/index.ts +11 -0
- package/src/trpc/init.test.ts +196 -0
- package/src/trpc/init.ts +138 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,727 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Notification Templates — renders all system notification emails.
|
|
3
|
+
*
|
|
4
|
+
* Separate from templates.ts (which handles billing/auth emails) to keep
|
|
5
|
+
* each file focused. Imports shared layout helpers from templates.ts.
|
|
6
|
+
*
|
|
7
|
+
* Export: renderNotificationTemplate(template, data) → TemplateResult
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { escapeHtml } from "./resend-adapter.js";
|
|
11
|
+
import type { TemplateResult } from "./templates.js";
|
|
12
|
+
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Re-export TemplateName extended with notification templates
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
|
|
17
|
+
export type NotificationTemplateName =
|
|
18
|
+
| "credits-depleted"
|
|
19
|
+
| "grace-period-start"
|
|
20
|
+
| "grace-period-warning"
|
|
21
|
+
| "auto-suspended"
|
|
22
|
+
| "auto-topup-success"
|
|
23
|
+
| "auto-topup-failed"
|
|
24
|
+
| "crypto-payment-confirmed"
|
|
25
|
+
| "admin-suspended"
|
|
26
|
+
| "admin-reactivated"
|
|
27
|
+
| "credits-granted"
|
|
28
|
+
| "role-changed"
|
|
29
|
+
| "team-invite"
|
|
30
|
+
| "agent-created"
|
|
31
|
+
| "channel-connected"
|
|
32
|
+
| "channel-disconnected"
|
|
33
|
+
| "agent-suspended"
|
|
34
|
+
| "custom"
|
|
35
|
+
// Account deletion lifecycle
|
|
36
|
+
| "account-deletion-requested"
|
|
37
|
+
| "account-deletion-cancelled"
|
|
38
|
+
| "account-deletion-completed"
|
|
39
|
+
| "dividend-weekly-digest"
|
|
40
|
+
| "affiliate-credit-match"
|
|
41
|
+
| "spend-alert"
|
|
42
|
+
// Passthrough to existing templates
|
|
43
|
+
| "low-balance"
|
|
44
|
+
| "credit-purchase-receipt"
|
|
45
|
+
| "welcome"
|
|
46
|
+
| "password-reset";
|
|
47
|
+
|
|
48
|
+
export type TemplateName = NotificationTemplateName;
|
|
49
|
+
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
// Shared layout helpers (duplicated locally so this file is self-contained)
|
|
52
|
+
// ---------------------------------------------------------------------------
|
|
53
|
+
|
|
54
|
+
function wrapHtml(title: string, bodyContent: string): string {
|
|
55
|
+
return `<!DOCTYPE html>
|
|
56
|
+
<html>
|
|
57
|
+
<head>
|
|
58
|
+
<meta charset="utf-8">
|
|
59
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
60
|
+
<title>${escapeHtml(title)}</title>
|
|
61
|
+
</head>
|
|
62
|
+
<body style="margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; background-color: #f4f4f4;">
|
|
63
|
+
<table role="presentation" style="width: 100%; border-collapse: collapse;">
|
|
64
|
+
<tr>
|
|
65
|
+
<td style="padding: 40px 0; text-align: center;">
|
|
66
|
+
<table role="presentation" style="width: 600px; margin: 0 auto; background-color: #ffffff; border-radius: 8px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
|
|
67
|
+
${bodyContent}
|
|
68
|
+
</table>
|
|
69
|
+
<p style="margin-top: 20px; color: #a0aec0; font-size: 12px;">© ${new Date().getFullYear()} WOPR Network. All rights reserved.</p>
|
|
70
|
+
</td>
|
|
71
|
+
</tr>
|
|
72
|
+
</table>
|
|
73
|
+
</body>
|
|
74
|
+
</html>`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function heading(text: string): string {
|
|
78
|
+
return `<tr>
|
|
79
|
+
<td style="padding: 40px 40px 20px 40px; text-align: center;">
|
|
80
|
+
<h1 style="margin: 0; font-size: 24px; font-weight: 600; color: #1a1a1a;">${escapeHtml(text)}</h1>
|
|
81
|
+
</td>
|
|
82
|
+
</tr>`;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function paragraph(html: string): string {
|
|
86
|
+
return `<tr>
|
|
87
|
+
<td style="padding: 0 40px 20px 40px; color: #4a5568; font-size: 16px; line-height: 24px;">
|
|
88
|
+
${html}
|
|
89
|
+
</td>
|
|
90
|
+
</tr>`;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
function button(url: string, label: string, color = "#2563eb"): string {
|
|
94
|
+
return `<tr>
|
|
95
|
+
<td style="padding: 0 40px 30px 40px; text-align: center;">
|
|
96
|
+
<a href="${escapeHtml(url)}" style="display: inline-block; padding: 12px 32px; background-color: ${color}; color: #ffffff; text-decoration: none; font-weight: 600; border-radius: 6px; font-size: 16px;">${escapeHtml(label)}</a>
|
|
97
|
+
</td>
|
|
98
|
+
</tr>`;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
function footer(text: string): string {
|
|
102
|
+
return `<tr>
|
|
103
|
+
<td style="padding: 0 40px 40px 40px; color: #718096; font-size: 14px; line-height: 20px; border-top: 1px solid #e2e8f0;">
|
|
104
|
+
<p style="margin-top: 20px;">${text}</p>
|
|
105
|
+
</td>
|
|
106
|
+
</tr>`;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function copyright(): string {
|
|
110
|
+
return `\n\n(c) ${new Date().getFullYear()} WOPR Network. All rights reserved.`;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// ---------------------------------------------------------------------------
|
|
114
|
+
// Individual template renderers
|
|
115
|
+
// ---------------------------------------------------------------------------
|
|
116
|
+
|
|
117
|
+
function creditsDepletedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
118
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
119
|
+
const parts = [
|
|
120
|
+
heading("Your WOPR Credits Are Depleted"),
|
|
121
|
+
paragraph(
|
|
122
|
+
"<p>Your WOPR credit balance has reached $0. All agent capabilities have been paused.</p>" +
|
|
123
|
+
"<p>Add credits now to resume service immediately.</p>",
|
|
124
|
+
),
|
|
125
|
+
];
|
|
126
|
+
if (creditsUrl) parts.push(button(creditsUrl, "Add Credits"));
|
|
127
|
+
parts.push(footer("Your data is preserved. Add credits to reactivate."));
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
subject: "Your WOPR credits are depleted — capabilities paused",
|
|
131
|
+
html: wrapHtml("Credits Depleted", parts.join("\n")),
|
|
132
|
+
text: `Your WOPR Credits Are Depleted\n\nYour WOPR credit balance has reached $0. All agent capabilities have been paused.\n\nAdd credits now to resume service immediately.\n${creditsUrl ? `\nAdd credits: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function gracePeriodStartTemplate(data: Record<string, unknown>): TemplateResult {
|
|
137
|
+
const balanceDollars = escapeHtml((data.balanceDollars as string) || "$0.00");
|
|
138
|
+
const graceDays = Number(data.graceDays) || 7;
|
|
139
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
140
|
+
const parts = [
|
|
141
|
+
heading("Action Needed: Top Up to Keep Your WOPRs Running"),
|
|
142
|
+
paragraph(
|
|
143
|
+
`<p>Your current balance is <strong>${balanceDollars}</strong> and the monthly deduction could not be processed.</p>` +
|
|
144
|
+
`<p>You have a <strong>${graceDays}-day grace period</strong> to add credits before your account is suspended.</p>`,
|
|
145
|
+
),
|
|
146
|
+
];
|
|
147
|
+
if (creditsUrl) parts.push(button(creditsUrl, "Add Credits Now"));
|
|
148
|
+
parts.push(footer("This is a critical notification about your account status."));
|
|
149
|
+
|
|
150
|
+
return {
|
|
151
|
+
subject: "Action needed: top up to keep your WOPRs running",
|
|
152
|
+
html: wrapHtml("Grace Period Started", parts.join("\n")),
|
|
153
|
+
text: `Action Needed: Top Up to Keep Your WOPRs Running\n\nYour current balance is ${data.balanceDollars} and the monthly deduction could not be processed.\n\nYou have a ${graceDays}-day grace period to add credits before your account is suspended.\n${creditsUrl ? `\nAdd credits: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function gracePeriodWarningTemplate(data: Record<string, unknown>): TemplateResult {
|
|
158
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
159
|
+
const parts = [
|
|
160
|
+
heading("Last Chance: Your WOPRs Will Be Suspended Tomorrow"),
|
|
161
|
+
paragraph(
|
|
162
|
+
"<p>Your grace period expires tomorrow. If you do not add credits, your account will be suspended.</p>" +
|
|
163
|
+
"<p>Add credits now to keep your agents running.</p>",
|
|
164
|
+
),
|
|
165
|
+
];
|
|
166
|
+
if (creditsUrl) parts.push(button(creditsUrl, "Add Credits Now", "#dc2626"));
|
|
167
|
+
parts.push(footer("This is a critical notification about your account status."));
|
|
168
|
+
|
|
169
|
+
return {
|
|
170
|
+
subject: "Last chance: your WOPRs will be suspended tomorrow",
|
|
171
|
+
html: wrapHtml("Grace Period Warning", parts.join("\n")),
|
|
172
|
+
text: `Last Chance: Your WOPRs Will Be Suspended Tomorrow\n\nYour grace period expires tomorrow. If you do not add credits, your account will be suspended.\n${creditsUrl ? `\nAdd credits: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
173
|
+
};
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function autoSuspendedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
177
|
+
const reason = escapeHtml((data.reason as string) || "Grace period expired");
|
|
178
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
179
|
+
const parts = [
|
|
180
|
+
heading("Your Account Has Been Suspended"),
|
|
181
|
+
paragraph(
|
|
182
|
+
`<p>Your WOPR account has been automatically suspended.</p>` +
|
|
183
|
+
`<p><strong>Reason:</strong> ${reason}</p>` +
|
|
184
|
+
`<p>Add credits to reactivate your account immediately.</p>`,
|
|
185
|
+
),
|
|
186
|
+
];
|
|
187
|
+
if (creditsUrl) parts.push(button(creditsUrl, "Add Credits to Reactivate"));
|
|
188
|
+
parts.push(footer("Your data is preserved for 30 days."));
|
|
189
|
+
|
|
190
|
+
return {
|
|
191
|
+
subject: "Your account has been suspended",
|
|
192
|
+
html: wrapHtml("Account Suspended", parts.join("\n")),
|
|
193
|
+
text: `Your Account Has Been Suspended\n\nReason: ${data.reason}\n\nAdd credits to reactivate your account immediately.\n${creditsUrl ? `\nAdd credits: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
194
|
+
};
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
function autoTopupSuccessTemplate(data: Record<string, unknown>): TemplateResult {
|
|
198
|
+
const amountDollars = escapeHtml((data.amountDollars as string) || "$0.00");
|
|
199
|
+
const newBalanceDollars = escapeHtml((data.newBalanceDollars as string) || "$0.00");
|
|
200
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
201
|
+
const parts = [
|
|
202
|
+
heading(`Auto Top-Up: ${amountDollars} Credits Added`),
|
|
203
|
+
paragraph(
|
|
204
|
+
`<p>Your auto top-up was successful. <strong>${amountDollars}</strong> in credits has been added.</p>` +
|
|
205
|
+
`<p>Your new balance is <strong>${newBalanceDollars}</strong>.</p>`,
|
|
206
|
+
),
|
|
207
|
+
];
|
|
208
|
+
if (creditsUrl) parts.push(button(creditsUrl, "View Credits"));
|
|
209
|
+
parts.push(footer("Auto top-up keeps your agents running without interruption."));
|
|
210
|
+
|
|
211
|
+
return {
|
|
212
|
+
subject: `Auto top-up: ${data.amountDollars} credits added`,
|
|
213
|
+
html: wrapHtml("Auto Top-Up Successful", parts.join("\n")),
|
|
214
|
+
text: `Auto Top-Up: ${data.amountDollars} Credits Added\n\nYour auto top-up was successful. ${data.amountDollars} in credits has been added.\n\nYour new balance is ${data.newBalanceDollars}.\n${creditsUrl ? `\nView credits: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
function autoTopupFailedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
219
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
220
|
+
const parts = [
|
|
221
|
+
heading("Auto Top-Up Failed"),
|
|
222
|
+
paragraph(
|
|
223
|
+
"<p>Your auto top-up failed. We were unable to charge your payment method.</p>" +
|
|
224
|
+
"<p>Please update your payment method or add credits manually to avoid service interruption.</p>",
|
|
225
|
+
),
|
|
226
|
+
];
|
|
227
|
+
if (creditsUrl) parts.push(button(creditsUrl, "Add Credits"));
|
|
228
|
+
parts.push(footer("If you need help, contact support@wopr.bot."));
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
subject: "Auto top-up failed — update your payment method",
|
|
232
|
+
html: wrapHtml("Auto Top-Up Failed", parts.join("\n")),
|
|
233
|
+
text: `Auto Top-Up Failed\n\nYour auto top-up failed. We were unable to charge your payment method.\n\nPlease update your payment method or add credits manually to avoid service interruption.\n${creditsUrl ? `\nAdd credits: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
234
|
+
};
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function cryptoPaymentConfirmedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
238
|
+
const amountDollars = escapeHtml((data.amountDollars as string) || "$0.00");
|
|
239
|
+
const newBalanceDollars = escapeHtml((data.newBalanceDollars as string) || "$0.00");
|
|
240
|
+
const parts = [
|
|
241
|
+
heading(`Crypto Payment Confirmed: ${amountDollars} Credits Added`),
|
|
242
|
+
paragraph(
|
|
243
|
+
`<p>Your crypto payment has been confirmed. <strong>${amountDollars}</strong> in credits has been added to your account.</p>` +
|
|
244
|
+
`<p>Your new balance is <strong>${newBalanceDollars}</strong>.</p>`,
|
|
245
|
+
),
|
|
246
|
+
];
|
|
247
|
+
parts.push(footer("Thank you for supporting WOPR!"));
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
subject: `Crypto payment confirmed: ${data.amountDollars} credits added`,
|
|
251
|
+
html: wrapHtml("Crypto Payment Confirmed", parts.join("\n")),
|
|
252
|
+
text: `Crypto Payment Confirmed: ${data.amountDollars} Credits Added\n\nYour crypto payment has been confirmed. ${data.amountDollars} in credits has been added.\n\nYour new balance is ${data.newBalanceDollars}.\n${copyright()}`,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
function adminSuspendedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
257
|
+
const reason = escapeHtml((data.reason as string) || "Policy violation");
|
|
258
|
+
const parts = [
|
|
259
|
+
heading("Your Account Has Been Suspended"),
|
|
260
|
+
paragraph(
|
|
261
|
+
`<p>Your WOPR account has been suspended by an administrator.</p>` +
|
|
262
|
+
`<p><strong>Reason:</strong> ${reason}</p>` +
|
|
263
|
+
`<p>If you believe this is an error, please contact support@wopr.bot.</p>`,
|
|
264
|
+
),
|
|
265
|
+
];
|
|
266
|
+
parts.push(footer("Contact support@wopr.bot if you have questions."));
|
|
267
|
+
|
|
268
|
+
return {
|
|
269
|
+
subject: "Your account has been suspended",
|
|
270
|
+
html: wrapHtml("Account Suspended", parts.join("\n")),
|
|
271
|
+
text: `Your Account Has Been Suspended\n\nReason: ${data.reason}\n\nIf you believe this is an error, please contact support@wopr.bot.\n${copyright()}`,
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
function adminReactivatedTemplate(_data: Record<string, unknown>): TemplateResult {
|
|
276
|
+
const parts = [
|
|
277
|
+
heading("Your Account Has Been Reactivated"),
|
|
278
|
+
paragraph(
|
|
279
|
+
"<p>Your WOPR account has been reactivated. You now have full access to all services.</p>" +
|
|
280
|
+
"<p>Your agents and channels are ready to use.</p>",
|
|
281
|
+
),
|
|
282
|
+
];
|
|
283
|
+
parts.push(footer("Welcome back!"));
|
|
284
|
+
|
|
285
|
+
return {
|
|
286
|
+
subject: "Your account has been reactivated",
|
|
287
|
+
html: wrapHtml("Account Reactivated", parts.join("\n")),
|
|
288
|
+
text: `Your Account Has Been Reactivated\n\nYour WOPR account has been reactivated. You now have full access to all services.\n${copyright()}`,
|
|
289
|
+
};
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
function creditsGrantedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
293
|
+
const amountDollars = escapeHtml((data.amountDollars as string) || "$0.00");
|
|
294
|
+
const reason = escapeHtml((data.reason as string) || "");
|
|
295
|
+
const parts = [
|
|
296
|
+
heading(`You Received ${amountDollars} in Credits`),
|
|
297
|
+
paragraph(
|
|
298
|
+
`<p><strong>${amountDollars}</strong> in credits has been added to your WOPR account.</p>` +
|
|
299
|
+
(reason ? `<p><strong>Note:</strong> ${reason}</p>` : ""),
|
|
300
|
+
),
|
|
301
|
+
];
|
|
302
|
+
parts.push(footer("Thank you for using WOPR!"));
|
|
303
|
+
|
|
304
|
+
return {
|
|
305
|
+
subject: `You received ${data.amountDollars} in credits`,
|
|
306
|
+
html: wrapHtml("Credits Granted", parts.join("\n")),
|
|
307
|
+
text: `You Received ${data.amountDollars} in Credits\n\n${data.amountDollars} has been added to your account.${reason ? `\n\nNote: ${data.reason}` : ""}\n${copyright()}`,
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function roleChangedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
312
|
+
const newRole = escapeHtml((data.newRole as string) || "");
|
|
313
|
+
const parts = [
|
|
314
|
+
heading("Your Role Has Been Updated"),
|
|
315
|
+
paragraph(
|
|
316
|
+
`<p>Your role on the WOPR platform has been updated to <strong>${newRole}</strong>.</p>` +
|
|
317
|
+
"<p>Your new permissions are now active.</p>",
|
|
318
|
+
),
|
|
319
|
+
];
|
|
320
|
+
parts.push(footer("If you did not expect this change, contact support@wopr.bot."));
|
|
321
|
+
|
|
322
|
+
return {
|
|
323
|
+
subject: "Your role has been updated",
|
|
324
|
+
html: wrapHtml("Role Changed", parts.join("\n")),
|
|
325
|
+
text: `Your Role Has Been Updated\n\nYour role has been updated to ${data.newRole}.\n${copyright()}`,
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function teamInviteTemplate(data: Record<string, unknown>): TemplateResult {
|
|
330
|
+
const tenantName = escapeHtml((data.tenantName as string) || "a tenant");
|
|
331
|
+
const inviteUrl = (data.inviteUrl as string) || "";
|
|
332
|
+
const parts = [
|
|
333
|
+
heading(`You've Been Invited to Join ${tenantName}`),
|
|
334
|
+
paragraph(
|
|
335
|
+
`<p>You've been invited to join <strong>${tenantName}</strong> on the WOPR platform.</p>` +
|
|
336
|
+
"<p>Click below to accept the invitation.</p>",
|
|
337
|
+
),
|
|
338
|
+
];
|
|
339
|
+
if (inviteUrl) parts.push(button(inviteUrl, "Accept Invitation"));
|
|
340
|
+
parts.push(footer("If you did not expect this invitation, you can ignore this email."));
|
|
341
|
+
|
|
342
|
+
return {
|
|
343
|
+
subject: `You've been invited to join ${data.tenantName}`,
|
|
344
|
+
html: wrapHtml("Team Invite", parts.join("\n")),
|
|
345
|
+
text: `You've Been Invited to Join ${data.tenantName}\n\n${inviteUrl ? `Accept: ${inviteUrl}\n` : ""}${copyright()}`,
|
|
346
|
+
};
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
function agentCreatedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
350
|
+
const agentName = escapeHtml((data.agentName as string) || "your agent");
|
|
351
|
+
const parts = [
|
|
352
|
+
heading(`Your WOPR ${agentName} Is Ready`),
|
|
353
|
+
paragraph(
|
|
354
|
+
`<p>Your new agent <strong>${agentName}</strong> has been created and is ready to use.</p>` +
|
|
355
|
+
"<p>Connect it to a channel to start receiving and sending messages.</p>",
|
|
356
|
+
),
|
|
357
|
+
];
|
|
358
|
+
parts.push(footer("Happy building!"));
|
|
359
|
+
|
|
360
|
+
return {
|
|
361
|
+
subject: `Your WOPR ${data.agentName} is ready`,
|
|
362
|
+
html: wrapHtml("Agent Created", parts.join("\n")),
|
|
363
|
+
text: `Your WOPR ${data.agentName} Is Ready\n\nYour new agent has been created and is ready to use.\n${copyright()}`,
|
|
364
|
+
};
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
function channelConnectedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
368
|
+
const channelName = escapeHtml((data.channelName as string) || "A channel");
|
|
369
|
+
const agentName = escapeHtml((data.agentName as string) || "your agent");
|
|
370
|
+
const parts = [
|
|
371
|
+
heading(`${channelName} Connected to ${agentName}`),
|
|
372
|
+
paragraph(
|
|
373
|
+
`<p><strong>${channelName}</strong> has been successfully connected to <strong>${agentName}</strong>.</p>` +
|
|
374
|
+
"<p>Your agent is now active on this channel.</p>",
|
|
375
|
+
),
|
|
376
|
+
];
|
|
377
|
+
parts.push(footer("Your agent is live!"));
|
|
378
|
+
|
|
379
|
+
return {
|
|
380
|
+
subject: `${data.channelName} connected to ${data.agentName}`,
|
|
381
|
+
html: wrapHtml("Channel Connected", parts.join("\n")),
|
|
382
|
+
text: `${data.channelName} Connected to ${data.agentName}\n\n${data.channelName} has been successfully connected to ${data.agentName}.\n${copyright()}`,
|
|
383
|
+
};
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
function channelDisconnectedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
387
|
+
const channelName = escapeHtml((data.channelName as string) || "A channel");
|
|
388
|
+
const agentName = escapeHtml((data.agentName as string) || "your agent");
|
|
389
|
+
const reason = escapeHtml((data.reason as string) || "");
|
|
390
|
+
const parts = [
|
|
391
|
+
heading(`${channelName} Disconnected from ${agentName}`),
|
|
392
|
+
paragraph(
|
|
393
|
+
`<p><strong>${channelName}</strong> has been disconnected from <strong>${agentName}</strong>.</p>` +
|
|
394
|
+
(reason ? `<p><strong>Reason:</strong> ${reason}</p>` : "") +
|
|
395
|
+
"<p>Reconnect the channel from your dashboard to restore service.</p>",
|
|
396
|
+
),
|
|
397
|
+
];
|
|
398
|
+
parts.push(footer("Your agent data is preserved."));
|
|
399
|
+
|
|
400
|
+
return {
|
|
401
|
+
subject: `${data.channelName} disconnected from ${data.agentName}`,
|
|
402
|
+
html: wrapHtml("Channel Disconnected", parts.join("\n")),
|
|
403
|
+
text: `${data.channelName} Disconnected from ${data.agentName}\n\n${reason ? `Reason: ${data.reason}\n\n` : ""}Reconnect from your dashboard to restore service.\n${copyright()}`,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
function agentSuspendedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
408
|
+
const agentName = escapeHtml((data.agentName as string) || "Your agent");
|
|
409
|
+
const reason = escapeHtml((data.reason as string) || "");
|
|
410
|
+
const parts = [
|
|
411
|
+
heading(`${agentName} Has Been Paused`),
|
|
412
|
+
paragraph(
|
|
413
|
+
`<p>Your agent <strong>${agentName}</strong> has been paused.</p>` +
|
|
414
|
+
(reason ? `<p><strong>Reason:</strong> ${reason}</p>` : ""),
|
|
415
|
+
),
|
|
416
|
+
];
|
|
417
|
+
parts.push(footer("Contact support@wopr.bot if you have questions."));
|
|
418
|
+
|
|
419
|
+
return {
|
|
420
|
+
subject: `${data.agentName} has been paused`,
|
|
421
|
+
html: wrapHtml("Agent Paused", parts.join("\n")),
|
|
422
|
+
text: `${data.agentName} Has Been Paused\n\n${reason ? `Reason: ${data.reason}\n` : ""}${copyright()}`,
|
|
423
|
+
};
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
function accountDeletionRequestedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
427
|
+
const email = escapeHtml((data.email as string) || "");
|
|
428
|
+
const deleteAfterDate = escapeHtml((data.deleteAfterDate as string) || "");
|
|
429
|
+
const cancelUrl = (data.cancelUrl as string) || "";
|
|
430
|
+
|
|
431
|
+
const parts = [
|
|
432
|
+
heading("Account Deletion Requested"),
|
|
433
|
+
paragraph(
|
|
434
|
+
`<p>Hi <strong>${email}</strong>,</p>` +
|
|
435
|
+
`<p>We've received your request to delete your WOPR account and all associated data.</p>` +
|
|
436
|
+
`<p>Your account will be permanently deleted on <strong>${deleteAfterDate}</strong>. Until then, you can cancel this request and keep your account.</p>` +
|
|
437
|
+
`<p>After that date, all your data will be permanently and irreversibly removed, including bots, conversation history, credit records, and plugin configurations.</p>`,
|
|
438
|
+
),
|
|
439
|
+
];
|
|
440
|
+
if (cancelUrl) parts.push(button(cancelUrl, "Cancel Deletion", "#22c55e"));
|
|
441
|
+
parts.push(footer("If you did not request this, please contact support@wopr.bot immediately."));
|
|
442
|
+
|
|
443
|
+
return {
|
|
444
|
+
subject: "Your WOPR account deletion request",
|
|
445
|
+
html: wrapHtml("Account Deletion Requested", parts.join("\n")),
|
|
446
|
+
text: `Account Deletion Requested\n\nHi ${data.email as string},\n\nWe've received your request to delete your WOPR account and all associated data.\n\nYour account will be permanently deleted on ${data.deleteAfterDate as string}. Until then, you can cancel this request.\n\nAfter that date, all your data will be permanently and irreversibly removed.\n${cancelUrl ? `\nCancel deletion: ${cancelUrl}\n` : ""}If you did not request this, please contact support@wopr.bot immediately.${copyright()}`,
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
function accountDeletionCancelledTemplate(data: Record<string, unknown>): TemplateResult {
|
|
451
|
+
const email = escapeHtml((data.email as string) || "");
|
|
452
|
+
|
|
453
|
+
const parts = [
|
|
454
|
+
heading("Account Deletion Cancelled"),
|
|
455
|
+
paragraph(
|
|
456
|
+
`<p>Hi <strong>${email}</strong>,</p>` +
|
|
457
|
+
`<p>Your account deletion request has been cancelled. Your account and all data remain intact.</p>` +
|
|
458
|
+
`<p>No further action is needed.</p>`,
|
|
459
|
+
),
|
|
460
|
+
footer("If you didn't cancel this, please contact support@wopr.bot."),
|
|
461
|
+
];
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
subject: "Your WOPR account deletion has been cancelled",
|
|
465
|
+
html: wrapHtml("Account Deletion Cancelled", parts.join("\n")),
|
|
466
|
+
text: `Account Deletion Cancelled\n\nHi ${data.email as string},\n\nYour account deletion request has been cancelled. Your account and all data remain intact.\n\nNo further action is needed.${copyright()}`,
|
|
467
|
+
};
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function accountDeletionCompletedTemplate(data: Record<string, unknown>): TemplateResult {
|
|
471
|
+
const email = escapeHtml((data.email as string) || "");
|
|
472
|
+
|
|
473
|
+
const parts = [
|
|
474
|
+
heading("Your Account Has Been Deleted"),
|
|
475
|
+
paragraph(
|
|
476
|
+
`<p>Hi <strong>${email}</strong>,</p>` +
|
|
477
|
+
`<p>Your WOPR account and all associated data have been permanently deleted as requested.</p>` +
|
|
478
|
+
`<p>This includes all bots, conversation history, credit records, billing data, and plugin configurations.</p>` +
|
|
479
|
+
`<p>If you'd like to use WOPR again in the future, you're welcome to create a new account.</p>`,
|
|
480
|
+
),
|
|
481
|
+
footer("Thank you for using WOPR. We're sorry to see you go."),
|
|
482
|
+
];
|
|
483
|
+
|
|
484
|
+
return {
|
|
485
|
+
subject: "Your WOPR account has been deleted",
|
|
486
|
+
html: wrapHtml("Account Deleted", parts.join("\n")),
|
|
487
|
+
text: `Your Account Has Been Deleted\n\nHi ${data.email as string},\n\nYour WOPR account and all associated data have been permanently deleted as requested.\n\nThis includes all bots, conversation history, credit records, billing data, and plugin configurations.\n\nIf you'd like to use WOPR again in the future, you're welcome to create a new account.${copyright()}`,
|
|
488
|
+
};
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
function dividendWeeklyDigestTemplate(data: Record<string, unknown>): TemplateResult {
|
|
492
|
+
const weeklyTotal = escapeHtml((data.weeklyTotalDollars as string) || "$0.00");
|
|
493
|
+
const lifetimeTotal = escapeHtml((data.lifetimeTotalDollars as string) || "$0.00");
|
|
494
|
+
const distributionCount = Number(data.distributionCount) || 0;
|
|
495
|
+
const poolAvgCents = Number(data.poolAvgCents) || 0;
|
|
496
|
+
const activeUsersAvg = Number(data.activeUsersAvg) || 0;
|
|
497
|
+
const nextDividendDate = escapeHtml((data.nextDividendDate as string) || "");
|
|
498
|
+
const weekStart = escapeHtml((data.weekStartDate as string) || "");
|
|
499
|
+
const weekEnd = escapeHtml((data.weekEndDate as string) || "");
|
|
500
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
501
|
+
const unsubscribeUrl = (data.unsubscribeUrl as string) || "";
|
|
502
|
+
const poolAvgDollars = `$${(poolAvgCents / 100).toFixed(2)}`;
|
|
503
|
+
|
|
504
|
+
const parts = [
|
|
505
|
+
heading(`WOPR Paid You ${weeklyTotal} This Week`),
|
|
506
|
+
paragraph(
|
|
507
|
+
`<p>Here's your weekly dividend summary for <strong>${weekStart} – ${weekEnd}</strong>.</p>` +
|
|
508
|
+
`<table style="width: 100%; border-collapse: collapse; margin: 16px 0;">` +
|
|
509
|
+
`<tr><td style="padding: 8px 0; color: #4a5568;">This week's dividends</td><td style="padding: 8px 0; text-align: right; font-weight: 600; color: #1a1a1a;">${weeklyTotal}</td></tr>` +
|
|
510
|
+
`<tr><td style="padding: 8px 0; color: #4a5568;">Days with distributions</td><td style="padding: 8px 0; text-align: right; font-weight: 600; color: #1a1a1a;">${distributionCount} of 7</td></tr>` +
|
|
511
|
+
`<tr><td style="padding: 8px 0; color: #4a5568;">Avg. daily pool</td><td style="padding: 8px 0; text-align: right; font-weight: 600; color: #1a1a1a;">${escapeHtml(poolAvgDollars)}</td></tr>` +
|
|
512
|
+
`<tr><td style="padding: 8px 0; color: #4a5568;">Avg. active users</td><td style="padding: 8px 0; text-align: right; font-weight: 600; color: #1a1a1a;">${activeUsersAvg}</td></tr>` +
|
|
513
|
+
`<tr style="border-top: 2px solid #e2e8f0;"><td style="padding: 12px 0; color: #4a5568; font-weight: 600;">Lifetime total</td><td style="padding: 12px 0; text-align: right; font-weight: 700; color: #1a1a1a; font-size: 18px;">${lifetimeTotal}</td></tr>` +
|
|
514
|
+
`</table>` +
|
|
515
|
+
(nextDividendDate
|
|
516
|
+
? `<p style="color: #718096; font-size: 14px;">Next dividend: <strong>${nextDividendDate}</strong></p>`
|
|
517
|
+
: ""),
|
|
518
|
+
),
|
|
519
|
+
];
|
|
520
|
+
if (creditsUrl) parts.push(button(creditsUrl, "View Your Credits"));
|
|
521
|
+
parts.push(
|
|
522
|
+
footer(
|
|
523
|
+
"Community dividends are distributed daily from platform revenue. Keep your credits active to stay eligible.",
|
|
524
|
+
),
|
|
525
|
+
);
|
|
526
|
+
if (unsubscribeUrl) {
|
|
527
|
+
parts.push(
|
|
528
|
+
`<tr><td style="padding: 0 40px 20px 40px; text-align: center; color: #a0aec0; font-size: 12px;"><a href="${escapeHtml(unsubscribeUrl)}" style="color: #a0aec0; text-decoration: underline;">Unsubscribe from dividend digests</a></td></tr>`,
|
|
529
|
+
);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
return {
|
|
533
|
+
subject: `WOPR paid you ${data.weeklyTotalDollars as string} this week`,
|
|
534
|
+
html: wrapHtml("Weekly Dividend Digest", parts.join("\n")),
|
|
535
|
+
text:
|
|
536
|
+
`WOPR Paid You ${data.weeklyTotalDollars as string} This Week\n\n` +
|
|
537
|
+
`Weekly summary for ${data.weekStartDate as string} – ${data.weekEndDate as string}:\n\n` +
|
|
538
|
+
`This week's dividends: ${data.weeklyTotalDollars as string}\n` +
|
|
539
|
+
`Days with distributions: ${distributionCount} of 7\n` +
|
|
540
|
+
`Avg. daily pool: ${poolAvgDollars}\n` +
|
|
541
|
+
`Avg. active users: ${activeUsersAvg}\n` +
|
|
542
|
+
`Lifetime total: ${data.lifetimeTotalDollars as string}\n\n` +
|
|
543
|
+
`Next dividend: ${data.nextDividendDate as string}\n\n` +
|
|
544
|
+
`Community dividends are distributed daily from platform revenue.` +
|
|
545
|
+
(unsubscribeUrl ? `\n\nUnsubscribe: ${unsubscribeUrl}` : "") +
|
|
546
|
+
copyright(),
|
|
547
|
+
};
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
function customTemplate(data: Record<string, unknown>): TemplateResult {
|
|
551
|
+
const subject = (data.subject as string) || "Message from WOPR";
|
|
552
|
+
const rawBody = (data.bodyText as string) || "";
|
|
553
|
+
const escapedBody = escapeHtml(rawBody).replace(/\n/g, "<br>\n");
|
|
554
|
+
|
|
555
|
+
const parts = [heading("Message from WOPR"), paragraph(`<p>${escapedBody}</p>`)];
|
|
556
|
+
parts.push(footer("This is an administrative message from WOPR Network."));
|
|
557
|
+
|
|
558
|
+
return {
|
|
559
|
+
subject,
|
|
560
|
+
html: wrapHtml(escapeHtml(subject), parts.join("\n")),
|
|
561
|
+
text: `${rawBody}\n${copyright()}`,
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
|
|
565
|
+
// ---------------------------------------------------------------------------
|
|
566
|
+
// Dispatcher
|
|
567
|
+
// ---------------------------------------------------------------------------
|
|
568
|
+
|
|
569
|
+
/**
|
|
570
|
+
* Render a notification template by name.
|
|
571
|
+
*
|
|
572
|
+
* All new templates are dispatched here. Legacy templates (verify-email,
|
|
573
|
+
* welcome, password-reset, etc.) are handled by templates.ts directly.
|
|
574
|
+
*/
|
|
575
|
+
export function renderNotificationTemplate(template: TemplateName, data: Record<string, unknown>): TemplateResult {
|
|
576
|
+
switch (template) {
|
|
577
|
+
case "credits-depleted":
|
|
578
|
+
return creditsDepletedTemplate(data);
|
|
579
|
+
case "grace-period-start":
|
|
580
|
+
return gracePeriodStartTemplate(data);
|
|
581
|
+
case "grace-period-warning":
|
|
582
|
+
return gracePeriodWarningTemplate(data);
|
|
583
|
+
case "auto-suspended":
|
|
584
|
+
return autoSuspendedTemplate(data);
|
|
585
|
+
case "auto-topup-success":
|
|
586
|
+
return autoTopupSuccessTemplate(data);
|
|
587
|
+
case "auto-topup-failed":
|
|
588
|
+
return autoTopupFailedTemplate(data);
|
|
589
|
+
case "crypto-payment-confirmed":
|
|
590
|
+
return cryptoPaymentConfirmedTemplate(data);
|
|
591
|
+
case "admin-suspended":
|
|
592
|
+
return adminSuspendedTemplate(data);
|
|
593
|
+
case "admin-reactivated":
|
|
594
|
+
return adminReactivatedTemplate(data);
|
|
595
|
+
case "credits-granted":
|
|
596
|
+
return creditsGrantedTemplate(data);
|
|
597
|
+
case "role-changed":
|
|
598
|
+
return roleChangedTemplate(data);
|
|
599
|
+
case "team-invite":
|
|
600
|
+
return teamInviteTemplate(data);
|
|
601
|
+
case "agent-created":
|
|
602
|
+
return agentCreatedTemplate(data);
|
|
603
|
+
case "channel-connected":
|
|
604
|
+
return channelConnectedTemplate(data);
|
|
605
|
+
case "channel-disconnected":
|
|
606
|
+
return channelDisconnectedTemplate(data);
|
|
607
|
+
case "agent-suspended":
|
|
608
|
+
return agentSuspendedTemplate(data);
|
|
609
|
+
case "affiliate-credit-match": {
|
|
610
|
+
const amountDollars = escapeHtml((data.amountDollars as string) || "$0.00");
|
|
611
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
612
|
+
const parts = [
|
|
613
|
+
heading("You Earned Affiliate Credits!"),
|
|
614
|
+
paragraph(
|
|
615
|
+
`<p>Great news! A user you referred just made their first purchase, and you've been credited <strong>${amountDollars}</strong>.</p>`,
|
|
616
|
+
),
|
|
617
|
+
];
|
|
618
|
+
if (creditsUrl) parts.push(button(creditsUrl, "View Credit Balance"));
|
|
619
|
+
parts.push(footer("Thank you for spreading the word about WOPR!"));
|
|
620
|
+
return {
|
|
621
|
+
subject: `You earned ${data.amountDollars as string} in affiliate credits!`,
|
|
622
|
+
html: wrapHtml("Affiliate Credits Earned", parts.join("\n")),
|
|
623
|
+
text: `You Earned Affiliate Credits!\n\nA user you referred just made their first purchase, and you've been credited ${data.amountDollars as string}.\n${creditsUrl ? `\nView your balance: ${creditsUrl}\n` : ""}${copyright()}`,
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
case "spend-alert": {
|
|
627
|
+
const currentSpend = escapeHtml(String(data.currentSpendDollars ?? "$0.00"));
|
|
628
|
+
const alertAt = escapeHtml(String(data.alertAtDollars ?? "$0.00"));
|
|
629
|
+
const creditsUrl = (data.creditsUrl as string) || "";
|
|
630
|
+
const parts = [
|
|
631
|
+
heading("Spending Alert: Threshold Reached"),
|
|
632
|
+
paragraph(
|
|
633
|
+
`<p>Your monthly spend has reached <strong>${currentSpend}</strong>, ` +
|
|
634
|
+
`crossing your alert threshold of <strong>${alertAt}</strong>.</p>` +
|
|
635
|
+
`<p>Review your spending to stay within your budget.</p>`,
|
|
636
|
+
),
|
|
637
|
+
];
|
|
638
|
+
if (creditsUrl) parts.push(button(creditsUrl, "Review Spending"));
|
|
639
|
+
parts.push(footer("This alert fires once per day when your spend exceeds your configured threshold."));
|
|
640
|
+
return {
|
|
641
|
+
subject: `Spending alert: you've reached your ${data.alertAtDollars as string} threshold`,
|
|
642
|
+
html: wrapHtml("Spending Alert", parts.join("\n")),
|
|
643
|
+
text:
|
|
644
|
+
`Spending Alert: Threshold Reached\n\nYour monthly spend has reached ${data.currentSpendDollars as string}, ` +
|
|
645
|
+
`crossing your alert threshold of ${data.alertAtDollars as string}.\n` +
|
|
646
|
+
(creditsUrl ? `\nReview spending: ${creditsUrl}\n` : "") +
|
|
647
|
+
copyright(),
|
|
648
|
+
};
|
|
649
|
+
}
|
|
650
|
+
case "custom":
|
|
651
|
+
return customTemplate(data);
|
|
652
|
+
case "dividend-weekly-digest":
|
|
653
|
+
return dividendWeeklyDigestTemplate(data);
|
|
654
|
+
case "account-deletion-requested":
|
|
655
|
+
return accountDeletionRequestedTemplate(data);
|
|
656
|
+
case "account-deletion-cancelled":
|
|
657
|
+
return accountDeletionCancelledTemplate(data);
|
|
658
|
+
case "account-deletion-completed":
|
|
659
|
+
return accountDeletionCompletedTemplate(data);
|
|
660
|
+
case "low-balance":
|
|
661
|
+
return {
|
|
662
|
+
subject: "Your WOPR credits are running low",
|
|
663
|
+
html: wrapHtml(
|
|
664
|
+
"Low Balance",
|
|
665
|
+
[
|
|
666
|
+
heading("Your WOPR Credits Are Running Low"),
|
|
667
|
+
paragraph(
|
|
668
|
+
`<p>Your balance is <strong>${escapeHtml((data.balanceDollars as string) || "$0.00")}</strong>. Top up to keep your agents running.</p>`,
|
|
669
|
+
),
|
|
670
|
+
...(data.creditsUrl ? [button(data.creditsUrl as string, "Buy Credits")] : []),
|
|
671
|
+
footer("This is an automated billing notification."),
|
|
672
|
+
].join("\n"),
|
|
673
|
+
),
|
|
674
|
+
text: `Your WOPR Credits Are Running Low\n\nBalance: ${data.balanceDollars}\n${data.creditsUrl ? `\nBuy credits: ${data.creditsUrl}\n` : ""}${copyright()}`,
|
|
675
|
+
};
|
|
676
|
+
case "credit-purchase-receipt":
|
|
677
|
+
return {
|
|
678
|
+
subject: "Credits added to your account",
|
|
679
|
+
html: wrapHtml(
|
|
680
|
+
"Credits Added",
|
|
681
|
+
[
|
|
682
|
+
heading("Credits Added to Your Account"),
|
|
683
|
+
paragraph(
|
|
684
|
+
`<p><strong>${escapeHtml((data.amountDollars as string) || "$0.00")}</strong> in credits has been added.</p>` +
|
|
685
|
+
(data.newBalanceDollars
|
|
686
|
+
? `<p>New balance: <strong>${escapeHtml(data.newBalanceDollars as string)}</strong></p>`
|
|
687
|
+
: ""),
|
|
688
|
+
),
|
|
689
|
+
footer("Thank you for supporting WOPR!"),
|
|
690
|
+
].join("\n"),
|
|
691
|
+
),
|
|
692
|
+
text: `Credits Added\n\n${data.amountDollars} added.\n${copyright()}`,
|
|
693
|
+
};
|
|
694
|
+
case "welcome":
|
|
695
|
+
return {
|
|
696
|
+
subject: "Welcome to WOPR",
|
|
697
|
+
html: wrapHtml(
|
|
698
|
+
"Welcome",
|
|
699
|
+
[
|
|
700
|
+
heading("Welcome to WOPR!"),
|
|
701
|
+
paragraph("<p>Your account is now active. Start building!</p>"),
|
|
702
|
+
footer("Happy building!"),
|
|
703
|
+
].join("\n"),
|
|
704
|
+
),
|
|
705
|
+
text: `Welcome to WOPR!\n\nYour account is now active.\n${copyright()}`,
|
|
706
|
+
};
|
|
707
|
+
case "password-reset":
|
|
708
|
+
return {
|
|
709
|
+
subject: "Reset your WOPR password",
|
|
710
|
+
html: wrapHtml(
|
|
711
|
+
"Reset Password",
|
|
712
|
+
[
|
|
713
|
+
heading("Reset Your Password"),
|
|
714
|
+
paragraph("<p>Click below to reset your password.</p>"),
|
|
715
|
+
...(data.resetUrl ? [button(data.resetUrl as string, "Reset Password")] : []),
|
|
716
|
+
footer("If you did not request this, ignore this email."),
|
|
717
|
+
].join("\n"),
|
|
718
|
+
),
|
|
719
|
+
text: `Reset Your Password\n\n${data.resetUrl ? `${data.resetUrl}\n` : ""}${copyright()}`,
|
|
720
|
+
};
|
|
721
|
+
default: {
|
|
722
|
+
// Exhaustiveness check
|
|
723
|
+
const _exhaustive: never = template;
|
|
724
|
+
throw new Error(`Unknown notification template: ${String(_exhaustive)}`);
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
}
|