@baruk/core 0.1.0 → 0.2.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/CHANGELOG.md +59 -0
- package/dist/auth/password-reset.d.ts.map +1 -1
- package/dist/auth/password-reset.js +2 -4
- package/dist/auth/password-reset.js.map +1 -1
- package/dist/auth/password.d.ts +2 -18
- package/dist/auth/password.d.ts.map +1 -1
- package/dist/auth/password.js +12 -51
- package/dist/auth/password.js.map +1 -1
- package/dist/auth/service.d.ts +0 -12
- package/dist/auth/service.d.ts.map +1 -1
- package/dist/auth/service.js +3 -36
- package/dist/auth/service.js.map +1 -1
- package/dist/auth/session-token.d.ts +5 -2
- package/dist/auth/session-token.d.ts.map +1 -1
- package/dist/auth/session-token.js +7 -12
- package/dist/auth/session-token.js.map +1 -1
- package/dist/billing/dunning.d.ts +33 -0
- package/dist/billing/dunning.d.ts.map +1 -0
- package/dist/billing/dunning.js +49 -0
- package/dist/billing/dunning.js.map +1 -0
- package/dist/billing/provider/asaas.d.ts +15 -0
- package/dist/billing/provider/asaas.d.ts.map +1 -0
- package/dist/billing/provider/asaas.js +121 -0
- package/dist/billing/provider/asaas.js.map +1 -0
- package/dist/billing/provider/manual.d.ts +14 -0
- package/dist/billing/provider/manual.d.ts.map +1 -0
- package/dist/billing/provider/manual.js +24 -0
- package/dist/billing/provider/manual.js.map +1 -0
- package/dist/billing/provider/registry.d.ts +12 -0
- package/dist/billing/provider/registry.d.ts.map +1 -0
- package/dist/billing/provider/registry.js +22 -0
- package/dist/billing/provider/registry.js.map +1 -0
- package/dist/billing/provider/types.d.ts +76 -0
- package/dist/billing/provider/types.d.ts.map +1 -0
- package/dist/billing/provider/types.js +9 -0
- package/dist/billing/provider/types.js.map +1 -0
- package/dist/billing/receivable.d.ts +108 -0
- package/dist/billing/receivable.d.ts.map +1 -0
- package/dist/billing/receivable.js +2 -0
- package/dist/billing/receivable.js.map +1 -0
- package/dist/billing/repository.d.ts +97 -0
- package/dist/billing/repository.d.ts.map +1 -0
- package/dist/billing/repository.js +167 -0
- package/dist/billing/repository.js.map +1 -0
- package/dist/cjs/audit/audit.js +31 -0
- package/dist/cjs/audit/audit.js.map +1 -0
- package/dist/cjs/audit/repository.js +32 -0
- package/dist/cjs/audit/repository.js.map +1 -0
- package/dist/cjs/auth/password-reset.js +58 -0
- package/dist/cjs/auth/password-reset.js.map +1 -0
- package/dist/cjs/auth/password.js +32 -0
- package/dist/cjs/auth/password.js.map +1 -0
- package/dist/cjs/auth/service.js +191 -0
- package/dist/cjs/auth/service.js.map +1 -0
- package/dist/cjs/auth/session-token.js +18 -0
- package/dist/cjs/auth/session-token.js.map +1 -0
- package/dist/cjs/billing/dunning.js +54 -0
- package/dist/cjs/billing/dunning.js.map +1 -0
- package/dist/cjs/billing/provider/asaas.js +125 -0
- package/dist/cjs/billing/provider/asaas.js.map +1 -0
- package/dist/cjs/billing/provider/manual.js +28 -0
- package/dist/cjs/billing/provider/manual.js.map +1 -0
- package/dist/cjs/billing/provider/registry.js +27 -0
- package/dist/cjs/billing/provider/registry.js.map +1 -0
- package/dist/cjs/billing/provider/types.js +10 -0
- package/dist/cjs/billing/provider/types.js.map +1 -0
- package/dist/cjs/billing/receivable.js +3 -0
- package/dist/cjs/billing/receivable.js.map +1 -0
- package/dist/cjs/billing/repository.js +180 -0
- package/dist/cjs/billing/repository.js.map +1 -0
- package/dist/cjs/clients/repository.js +123 -0
- package/dist/cjs/clients/repository.js.map +1 -0
- package/dist/cjs/commercial-catalog/catalog.js +108 -0
- package/dist/cjs/commercial-catalog/catalog.js.map +1 -0
- package/dist/cjs/commercial-catalog/consumption-contracts.js +10 -0
- package/dist/cjs/commercial-catalog/consumption-contracts.js.map +1 -0
- package/dist/cjs/commercial-catalog/coupon.js +53 -0
- package/dist/cjs/commercial-catalog/coupon.js.map +1 -0
- package/dist/cjs/commercial-catalog/index.js +16 -0
- package/dist/cjs/commercial-catalog/index.js.map +1 -0
- package/dist/cjs/commercial-catalog/offer-application.js +53 -0
- package/dist/cjs/commercial-catalog/offer-application.js.map +1 -0
- package/dist/cjs/commercial-catalog/types.js +26 -0
- package/dist/cjs/commercial-catalog/types.js.map +1 -0
- package/dist/cjs/crm/repository.js +195 -0
- package/dist/cjs/crm/repository.js.map +1 -0
- package/dist/cjs/dashboard/repository.js +39 -0
- package/dist/cjs/dashboard/repository.js.map +1 -0
- package/dist/cjs/db/client.js +27 -0
- package/dist/cjs/db/client.js.map +1 -0
- package/dist/cjs/db/context.js +43 -0
- package/dist/cjs/db/context.js.map +1 -0
- package/dist/cjs/db/load-env.js +47 -0
- package/dist/cjs/db/load-env.js.map +1 -0
- package/dist/cjs/db/seed.js +69 -0
- package/dist/cjs/db/seed.js.map +1 -0
- package/dist/cjs/entitlements/decision.js +203 -0
- package/dist/cjs/entitlements/decision.js.map +1 -0
- package/dist/cjs/entitlements/derive.js +46 -0
- package/dist/cjs/entitlements/derive.js.map +1 -0
- package/dist/cjs/entitlements/index.js +23 -0
- package/dist/cjs/entitlements/index.js.map +1 -0
- package/dist/cjs/entitlements/sources.js +60 -0
- package/dist/cjs/entitlements/sources.js.map +1 -0
- package/dist/cjs/entitlements/standing.js +42 -0
- package/dist/cjs/entitlements/standing.js.map +1 -0
- package/dist/cjs/entitlements/types.js +16 -0
- package/dist/cjs/entitlements/types.js.map +1 -0
- package/dist/cjs/import/clients-import.js +147 -0
- package/dist/cjs/import/clients-import.js.map +1 -0
- package/dist/cjs/index.js +335 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/mail/dedup-store.js +56 -0
- package/dist/cjs/mail/dedup-store.js.map +1 -0
- package/dist/cjs/mail/index.js +24 -0
- package/dist/cjs/mail/index.js.map +1 -0
- package/dist/cjs/mail/provider.js +251 -0
- package/dist/cjs/mail/provider.js.map +1 -0
- package/dist/cjs/mail/resend-client.js +103 -0
- package/dist/cjs/mail/resend-client.js.map +1 -0
- package/dist/cjs/mail/resend.js +21 -0
- package/dist/cjs/mail/resend.js.map +1 -0
- package/dist/cjs/mail/sanitize.js +56 -0
- package/dist/cjs/mail/sanitize.js.map +1 -0
- package/dist/cjs/mail/sender-resolver.js +15 -0
- package/dist/cjs/mail/sender-resolver.js.map +1 -0
- package/dist/cjs/mail/template-renderer.js +21 -0
- package/dist/cjs/mail/template-renderer.js.map +1 -0
- package/dist/cjs/mail/types.js +38 -0
- package/dist/cjs/mail/types.js.map +1 -0
- package/dist/cjs/notifications/repository.js +49 -0
- package/dist/cjs/notifications/repository.js.map +1 -0
- package/dist/cjs/onboarding/domain.js +370 -0
- package/dist/cjs/onboarding/domain.js.map +1 -0
- package/dist/cjs/onboarding/interaction-review.js +425 -0
- package/dist/cjs/onboarding/interaction-review.js.map +1 -0
- package/dist/cjs/onboarding/persistence.js +444 -0
- package/dist/cjs/onboarding/persistence.js.map +1 -0
- package/dist/cjs/onboarding/portal-actions.js +157 -0
- package/dist/cjs/onboarding/portal-actions.js.map +1 -0
- package/dist/cjs/onboarding/portal.js +177 -0
- package/dist/cjs/onboarding/portal.js.map +1 -0
- package/dist/cjs/package.json +3 -0
- package/dist/cjs/portal/repository.js +37 -0
- package/dist/cjs/portal/repository.js.map +1 -0
- package/dist/cjs/pricing-engine/bundle.js +49 -0
- package/dist/cjs/pricing-engine/bundle.js.map +1 -0
- package/dist/cjs/pricing-engine/errors.js +48 -0
- package/dist/cjs/pricing-engine/errors.js.map +1 -0
- package/dist/cjs/pricing-engine/index.js +30 -0
- package/dist/cjs/pricing-engine/index.js.map +1 -0
- package/dist/cjs/pricing-engine/money.js +69 -0
- package/dist/cjs/pricing-engine/money.js.map +1 -0
- package/dist/cjs/pricing-engine/pipeline.js +330 -0
- package/dist/cjs/pricing-engine/pipeline.js.map +1 -0
- package/dist/cjs/pricing-engine/proration.js +53 -0
- package/dist/cjs/pricing-engine/proration.js.map +1 -0
- package/dist/cjs/pricing-engine/shadow.js +58 -0
- package/dist/cjs/pricing-engine/shadow.js.map +1 -0
- package/dist/cjs/pricing-engine/types.js +34 -0
- package/dist/cjs/pricing-engine/types.js.map +1 -0
- package/dist/cjs/products/catalog.js +10 -0
- package/dist/cjs/products/catalog.js.map +1 -0
- package/dist/cjs/products/repository.js +61 -0
- package/dist/cjs/products/repository.js.map +1 -0
- package/dist/cjs/rbac/authorize.js +36 -0
- package/dist/cjs/rbac/authorize.js.map +1 -0
- package/dist/cjs/rbac/catalog.js +455 -0
- package/dist/cjs/rbac/catalog.js.map +1 -0
- package/dist/cjs/requests/repository.js +114 -0
- package/dist/cjs/requests/repository.js.map +1 -0
- package/dist/cjs/subscription-billing/dunning.js +26 -0
- package/dist/cjs/subscription-billing/dunning.js.map +1 -0
- package/dist/cjs/subscription-billing/events.js +45 -0
- package/dist/cjs/subscription-billing/events.js.map +1 -0
- package/dist/cjs/subscription-billing/index.js +62 -0
- package/dist/cjs/subscription-billing/index.js.map +1 -0
- package/dist/cjs/subscription-billing/plans.js +88 -0
- package/dist/cjs/subscription-billing/plans.js.map +1 -0
- package/dist/cjs/subscription-billing/product-config.js +54 -0
- package/dist/cjs/subscription-billing/product-config.js.map +1 -0
- package/dist/cjs/subscription-billing/provider/asaas.js +233 -0
- package/dist/cjs/subscription-billing/provider/asaas.js.map +1 -0
- package/dist/cjs/subscription-billing/provider/disabled.js +46 -0
- package/dist/cjs/subscription-billing/provider/disabled.js.map +1 -0
- package/dist/cjs/subscription-billing/provider/registry.js +29 -0
- package/dist/cjs/subscription-billing/provider/registry.js.map +1 -0
- package/dist/cjs/subscription-billing/reconcile.js +198 -0
- package/dist/cjs/subscription-billing/reconcile.js.map +1 -0
- package/dist/cjs/subscription-billing/repository.js +359 -0
- package/dist/cjs/subscription-billing/repository.js.map +1 -0
- package/dist/cjs/subscription-billing/service.js +838 -0
- package/dist/cjs/subscription-billing/service.js.map +1 -0
- package/dist/cjs/subscription-billing/types.js +28 -0
- package/dist/cjs/subscription-billing/types.js.map +1 -0
- package/dist/cjs/tenancy/provisioning.js +126 -0
- package/dist/cjs/tenancy/provisioning.js.map +1 -0
- package/dist/cjs/users/repository.js +83 -0
- package/dist/cjs/users/repository.js.map +1 -0
- package/dist/cjs/vault/crypto.js +94 -0
- package/dist/cjs/vault/crypto.js.map +1 -0
- package/dist/cjs/vault/repository.js +120 -0
- package/dist/cjs/vault/repository.js.map +1 -0
- package/dist/commercial-catalog/catalog.d.ts +27 -0
- package/dist/commercial-catalog/catalog.d.ts.map +1 -0
- package/dist/commercial-catalog/catalog.js +104 -0
- package/dist/commercial-catalog/catalog.js.map +1 -0
- package/dist/commercial-catalog/consumption-contracts.d.ts +33 -0
- package/dist/commercial-catalog/consumption-contracts.d.ts.map +1 -0
- package/dist/commercial-catalog/consumption-contracts.js +9 -0
- package/dist/commercial-catalog/consumption-contracts.js.map +1 -0
- package/dist/commercial-catalog/coupon.d.ts +27 -0
- package/dist/commercial-catalog/coupon.d.ts.map +1 -0
- package/dist/commercial-catalog/coupon.js +47 -0
- package/dist/commercial-catalog/coupon.js.map +1 -0
- package/dist/commercial-catalog/index.d.ts +10 -0
- package/dist/commercial-catalog/index.d.ts.map +1 -0
- package/dist/commercial-catalog/index.js +5 -0
- package/dist/commercial-catalog/index.js.map +1 -0
- package/dist/commercial-catalog/offer-application.d.ts +39 -0
- package/dist/commercial-catalog/offer-application.d.ts.map +1 -0
- package/dist/commercial-catalog/offer-application.js +50 -0
- package/dist/commercial-catalog/offer-application.js.map +1 -0
- package/dist/commercial-catalog/types.d.ts +155 -0
- package/dist/commercial-catalog/types.d.ts.map +1 -0
- package/dist/commercial-catalog/types.js +23 -0
- package/dist/commercial-catalog/types.js.map +1 -0
- package/dist/crm/repository.d.ts +109 -0
- package/dist/crm/repository.d.ts.map +1 -0
- package/dist/crm/repository.js +181 -0
- package/dist/crm/repository.js.map +1 -0
- package/dist/db/context.d.ts +2 -0
- package/dist/db/context.d.ts.map +1 -1
- package/dist/db/context.js +3 -0
- package/dist/db/context.js.map +1 -1
- package/dist/db/migrate.js +7 -2
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/seed.js +4 -1
- package/dist/db/seed.js.map +1 -1
- package/dist/entitlements/decision.d.ts +86 -0
- package/dist/entitlements/decision.d.ts.map +1 -0
- package/dist/entitlements/decision.js +196 -0
- package/dist/entitlements/decision.js.map +1 -0
- package/dist/entitlements/derive.d.ts +30 -0
- package/dist/entitlements/derive.d.ts.map +1 -0
- package/dist/entitlements/derive.js +42 -0
- package/dist/entitlements/derive.js.map +1 -0
- package/dist/entitlements/index.d.ts +10 -0
- package/dist/entitlements/index.d.ts.map +1 -0
- package/dist/entitlements/index.js +7 -0
- package/dist/entitlements/index.js.map +1 -0
- package/dist/entitlements/sources.d.ts +30 -0
- package/dist/entitlements/sources.d.ts.map +1 -0
- package/dist/entitlements/sources.js +55 -0
- package/dist/entitlements/sources.js.map +1 -0
- package/dist/entitlements/standing.d.ts +22 -0
- package/dist/entitlements/standing.d.ts.map +1 -0
- package/dist/entitlements/standing.js +38 -0
- package/dist/entitlements/standing.js.map +1 -0
- package/dist/entitlements/types.d.ts +26 -0
- package/dist/entitlements/types.d.ts.map +1 -0
- package/dist/entitlements/types.js +15 -0
- package/dist/entitlements/types.js.map +1 -0
- package/dist/index.d.ts +74 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +51 -4
- package/dist/index.js.map +1 -1
- package/dist/mail/dedup-store.d.ts +25 -0
- package/dist/mail/dedup-store.d.ts.map +1 -0
- package/dist/mail/dedup-store.js +51 -0
- package/dist/mail/dedup-store.js.map +1 -0
- package/dist/mail/index.d.ts +10 -0
- package/dist/mail/index.d.ts.map +1 -0
- package/dist/mail/index.js +9 -0
- package/dist/mail/index.js.map +1 -0
- package/dist/mail/provider.d.ts +31 -0
- package/dist/mail/provider.d.ts.map +1 -0
- package/dist/mail/provider.js +248 -0
- package/dist/mail/provider.js.map +1 -0
- package/dist/mail/resend-client.d.ts +16 -0
- package/dist/mail/resend-client.d.ts.map +1 -0
- package/dist/mail/resend-client.js +100 -0
- package/dist/mail/resend-client.js.map +1 -0
- package/dist/mail/resend.d.ts.map +1 -1
- package/dist/mail/resend.js +2 -0
- package/dist/mail/resend.js.map +1 -1
- package/dist/mail/sanitize.d.ts +17 -0
- package/dist/mail/sanitize.d.ts.map +1 -0
- package/dist/mail/sanitize.js +51 -0
- package/dist/mail/sanitize.js.map +1 -0
- package/dist/mail/sender-resolver.d.ts +8 -0
- package/dist/mail/sender-resolver.d.ts.map +1 -0
- package/dist/mail/sender-resolver.js +11 -0
- package/dist/mail/sender-resolver.js.map +1 -0
- package/dist/mail/template-renderer.d.ts +10 -0
- package/dist/mail/template-renderer.d.ts.map +1 -0
- package/dist/mail/template-renderer.js +17 -0
- package/dist/mail/template-renderer.js.map +1 -0
- package/dist/mail/types.d.ts +143 -0
- package/dist/mail/types.d.ts.map +1 -0
- package/dist/mail/types.js +34 -0
- package/dist/mail/types.js.map +1 -0
- package/dist/onboarding/domain.d.ts +146 -0
- package/dist/onboarding/domain.d.ts.map +1 -0
- package/dist/onboarding/domain.js +348 -0
- package/dist/onboarding/domain.js.map +1 -0
- package/dist/onboarding/interaction-review.d.ts +123 -0
- package/dist/onboarding/interaction-review.d.ts.map +1 -0
- package/dist/onboarding/interaction-review.js +413 -0
- package/dist/onboarding/interaction-review.js.map +1 -0
- package/dist/onboarding/persistence.d.ts +106 -0
- package/dist/onboarding/persistence.d.ts.map +1 -0
- package/dist/onboarding/persistence.js +430 -0
- package/dist/onboarding/persistence.js.map +1 -0
- package/dist/onboarding/portal-actions.d.ts +48 -0
- package/dist/onboarding/portal-actions.d.ts.map +1 -0
- package/dist/onboarding/portal-actions.js +153 -0
- package/dist/onboarding/portal-actions.js.map +1 -0
- package/dist/onboarding/portal.d.ts +58 -0
- package/dist/onboarding/portal.d.ts.map +1 -0
- package/dist/onboarding/portal.js +170 -0
- package/dist/onboarding/portal.js.map +1 -0
- package/dist/pricing-engine/bundle.d.ts +22 -0
- package/dist/pricing-engine/bundle.d.ts.map +1 -0
- package/dist/pricing-engine/bundle.js +44 -0
- package/dist/pricing-engine/bundle.js.map +1 -0
- package/dist/pricing-engine/errors.d.ts +32 -0
- package/dist/pricing-engine/errors.d.ts.map +1 -0
- package/dist/pricing-engine/errors.js +44 -0
- package/dist/pricing-engine/errors.js.map +1 -0
- package/dist/pricing-engine/index.d.ts +12 -0
- package/dist/pricing-engine/index.d.ts.map +1 -0
- package/dist/pricing-engine/index.js +8 -0
- package/dist/pricing-engine/index.js.map +1 -0
- package/dist/pricing-engine/money.d.ts +32 -0
- package/dist/pricing-engine/money.d.ts.map +1 -0
- package/dist/pricing-engine/money.js +58 -0
- package/dist/pricing-engine/money.js.map +1 -0
- package/dist/pricing-engine/pipeline.d.ts +3 -0
- package/dist/pricing-engine/pipeline.d.ts.map +1 -0
- package/dist/pricing-engine/pipeline.js +327 -0
- package/dist/pricing-engine/pipeline.js.map +1 -0
- package/dist/pricing-engine/proration.d.ts +3 -0
- package/dist/pricing-engine/proration.d.ts.map +1 -0
- package/dist/pricing-engine/proration.js +50 -0
- package/dist/pricing-engine/proration.js.map +1 -0
- package/dist/pricing-engine/shadow.d.ts +51 -0
- package/dist/pricing-engine/shadow.d.ts.map +1 -0
- package/dist/pricing-engine/shadow.js +54 -0
- package/dist/pricing-engine/shadow.js.map +1 -0
- package/dist/pricing-engine/types.d.ts +184 -0
- package/dist/pricing-engine/types.d.ts.map +1 -0
- package/dist/pricing-engine/types.js +31 -0
- package/dist/pricing-engine/types.js.map +1 -0
- package/dist/rbac/authorize.d.ts +3 -6
- package/dist/rbac/authorize.d.ts.map +1 -1
- package/dist/rbac/authorize.js +4 -8
- package/dist/rbac/authorize.js.map +1 -1
- package/dist/rbac/catalog.d.ts.map +1 -1
- package/dist/rbac/catalog.js +414 -21
- package/dist/rbac/catalog.js.map +1 -1
- package/dist/subscription-billing/dunning.d.ts +18 -0
- package/dist/subscription-billing/dunning.d.ts.map +1 -0
- package/dist/subscription-billing/dunning.js +28 -0
- package/dist/subscription-billing/dunning.js.map +1 -0
- package/dist/subscription-billing/events.d.ts +58 -0
- package/dist/subscription-billing/events.d.ts.map +1 -0
- package/dist/subscription-billing/events.js +38 -0
- package/dist/subscription-billing/events.js.map +1 -0
- package/dist/subscription-billing/index.d.ts +18 -0
- package/dist/subscription-billing/index.d.ts.map +1 -0
- package/dist/subscription-billing/index.js +16 -0
- package/dist/subscription-billing/index.js.map +1 -0
- package/dist/subscription-billing/plans.d.ts +34 -0
- package/dist/subscription-billing/plans.d.ts.map +1 -0
- package/dist/subscription-billing/plans.js +85 -0
- package/dist/subscription-billing/plans.js.map +1 -0
- package/dist/subscription-billing/product-config.d.ts +61 -0
- package/dist/subscription-billing/product-config.d.ts.map +1 -0
- package/dist/subscription-billing/product-config.js +50 -0
- package/dist/subscription-billing/product-config.js.map +1 -0
- package/dist/subscription-billing/provider/asaas.d.ts +26 -0
- package/dist/subscription-billing/provider/asaas.d.ts.map +1 -0
- package/dist/subscription-billing/provider/asaas.js +229 -0
- package/dist/subscription-billing/provider/asaas.js.map +1 -0
- package/dist/subscription-billing/provider/disabled.d.ts +30 -0
- package/dist/subscription-billing/provider/disabled.d.ts.map +1 -0
- package/dist/subscription-billing/provider/disabled.js +42 -0
- package/dist/subscription-billing/provider/disabled.js.map +1 -0
- package/dist/subscription-billing/provider/registry.d.ts +10 -0
- package/dist/subscription-billing/provider/registry.d.ts.map +1 -0
- package/dist/subscription-billing/provider/registry.js +26 -0
- package/dist/subscription-billing/provider/registry.js.map +1 -0
- package/dist/subscription-billing/reconcile.d.ts +45 -0
- package/dist/subscription-billing/reconcile.d.ts.map +1 -0
- package/dist/subscription-billing/reconcile.js +192 -0
- package/dist/subscription-billing/reconcile.js.map +1 -0
- package/dist/subscription-billing/repository.d.ts +168 -0
- package/dist/subscription-billing/repository.d.ts.map +1 -0
- package/dist/subscription-billing/repository.js +336 -0
- package/dist/subscription-billing/repository.js.map +1 -0
- package/dist/subscription-billing/service.d.ts +175 -0
- package/dist/subscription-billing/service.d.ts.map +1 -0
- package/dist/subscription-billing/service.js +818 -0
- package/dist/subscription-billing/service.js.map +1 -0
- package/dist/subscription-billing/types.d.ts +161 -0
- package/dist/subscription-billing/types.d.ts.map +1 -0
- package/dist/subscription-billing/types.js +24 -0
- package/dist/subscription-billing/types.js.map +1 -0
- package/dist/vault/crypto.d.ts +22 -0
- package/dist/vault/crypto.d.ts.map +1 -0
- package/dist/vault/crypto.js +88 -0
- package/dist/vault/crypto.js.map +1 -0
- package/dist/vault/repository.d.ts +45 -0
- package/dist/vault/repository.d.ts.map +1 -0
- package/dist/vault/repository.js +111 -0
- package/dist/vault/repository.js.map +1 -0
- package/package.json +23 -13
- package/src/db/migrations/0012_vault.sql +51 -0
- package/src/db/migrations/0013_crm.sql +67 -0
- package/src/db/migrations/0014_billing.sql +146 -0
- package/src/db/migrations/0015_merchant_billing_ar.sql +201 -0
- package/src/db/migrations/0016_office_onboarding.sql +162 -0
- package/src/db/migrations/0017_office_onboarding_api.sql +21 -0
- package/src/db/migrations/0018_office_onboarding_portal_actions.sql +60 -0
- package/src/db/migrations/0019_office_onboarding_interaction_review.sql +134 -0
- package/src/db/migrations/0020_saas_billing.sql +157 -0
- package/src/db/migrations/0021_saas_billing_indexes.sql +23 -0
- package/src/db/migrations/0022_saas_billing_multi_product.sql +75 -0
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { buildDedupKey, InMemoryDedupStore } from './dedup-store.js';
|
|
2
|
+
import { sendViaResend } from './resend-client.js';
|
|
3
|
+
import { logSanitized, logSanitizedInfo } from './sanitize.js';
|
|
4
|
+
import { StaticSenderResolver } from './sender-resolver.js';
|
|
5
|
+
import { PassthroughTemplateRenderer } from './template-renderer.js';
|
|
6
|
+
import { DEFAULT_REMOTE_RESERVATION_MAX_WAIT_MS, DEFAULT_REMOTE_RESERVATION_POLL_INTERVAL_MS, DEFAULT_TIMEOUT_MS, MIN_DEDUP_WINDOW_MS, } from './types.js';
|
|
7
|
+
/** Validação prática de endereço (RFC §4 — borda do Provider): local@domínio.tld, sem espaços, um único "@". */
|
|
8
|
+
const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
9
|
+
function isValidEmailAddress(address) {
|
|
10
|
+
return EMAIL_PATTERN.test(address);
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Valida os endereços que o Provider efetivamente usará na chamada ao provider externo
|
|
14
|
+
* (Correção 3 — Auditoria Codex). Roda depois de `from` resolvido, para pegar também
|
|
15
|
+
* remetentes vindos do `SenderResolver`/`defaultFrom`, não só o `input.from` explícito.
|
|
16
|
+
*/
|
|
17
|
+
function validateAddresses(fields) {
|
|
18
|
+
const invalidFields = [];
|
|
19
|
+
if (!isValidEmailAddress(fields.to))
|
|
20
|
+
invalidFields.push('to');
|
|
21
|
+
if (!isValidEmailAddress(fields.from))
|
|
22
|
+
invalidFields.push('from');
|
|
23
|
+
if (fields.replyTo !== undefined && !isValidEmailAddress(fields.replyTo))
|
|
24
|
+
invalidFields.push('replyTo');
|
|
25
|
+
if (invalidFields.length === 0)
|
|
26
|
+
return undefined;
|
|
27
|
+
return {
|
|
28
|
+
code: 'invalid-recipient',
|
|
29
|
+
message: `Endereço(s) de e-mail inválido(s): ${invalidFields.join(', ')}.`,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Provider canônico de `cap.communication.transactional-email` (RFC-CAPABILITY-TRANSACTIONAL-EMAIL-001 v0.2).
|
|
34
|
+
* Extensões (`templateRenderer`/`senderResolver`/`hooks`/`dedupStore`) são injetadas na construção,
|
|
35
|
+
* nunca descobertas por convenção (RFC §4.7).
|
|
36
|
+
*/
|
|
37
|
+
export function createTransactionalEmailProvider(config) {
|
|
38
|
+
const templateRenderer = config.templateRenderer ?? new PassthroughTemplateRenderer();
|
|
39
|
+
const senderResolver = config.senderResolver ?? new StaticSenderResolver(config.defaultFrom);
|
|
40
|
+
const hooks = config.hooks ?? [];
|
|
41
|
+
const dedupStore = config.dedupStore ?? new InMemoryDedupStore();
|
|
42
|
+
const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
43
|
+
const remoteReservationPollIntervalMs = config.remoteReservationPollIntervalMs ?? DEFAULT_REMOTE_RESERVATION_POLL_INTERVAL_MS;
|
|
44
|
+
const remoteReservationMaxWaitMs = config.remoteReservationMaxWaitMs ?? DEFAULT_REMOTE_RESERVATION_MAX_WAIT_MS;
|
|
45
|
+
const apiKey = config.apiKey;
|
|
46
|
+
/**
|
|
47
|
+
* Nenhuma chamada ao `DedupStore` (`reserve`/`get`/`set`) pode escapar sem tratamento
|
|
48
|
+
* (Bloqueador 1 — Certification Round 2: sanitização não pode se limitar ao `DeliveryResult`;
|
|
49
|
+
* uma implementação de store real — Redis/Postgres — pode lançar erros de rede/conexão cuja
|
|
50
|
+
* mensagem contém credenciais, ex.: uma connection string). Toda chamada passa por aqui:
|
|
51
|
+
* nunca propaga a exceção, sempre loga sanitizado, sempre devolve um fallback seguro.
|
|
52
|
+
*/
|
|
53
|
+
async function safeDedupCall(operation, fn, fallback) {
|
|
54
|
+
try {
|
|
55
|
+
return await fn();
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
logSanitized(`[transactional-email] DedupStore.${operation} falhou (ignorado):`, errorMessage(err), [apiKey]);
|
|
59
|
+
return fallback;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function sleep(ms) {
|
|
63
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Aguarda, de forma limitada, o resultado de uma reserva mantida por outra instância/réplica
|
|
67
|
+
* (`DedupStore` `mode: 'shared'`) — é o mecanismo real de coalescência distribuída (Bloqueador 2).
|
|
68
|
+
* Nunca espera indefinidamente: `maxWaitMs` limita o tempo total, sempre com um valor determinístico
|
|
69
|
+
* ao final (achou o resultado, ou desistiu — nunca fica pendurado).
|
|
70
|
+
*/
|
|
71
|
+
async function waitForRemoteResult(dedupKey, pollIntervalMs, maxWaitMs) {
|
|
72
|
+
const deadline = Date.now() + maxWaitMs;
|
|
73
|
+
while (Date.now() < deadline) {
|
|
74
|
+
await sleep(pollIntervalMs);
|
|
75
|
+
const entry = await safeDedupCall('get', () => dedupStore.get(dedupKey), null);
|
|
76
|
+
if (entry)
|
|
77
|
+
return entry;
|
|
78
|
+
}
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Coalescência local de envios em andamento por `dedupKey` (Bloqueador 2 — Auditoria Codex).
|
|
83
|
+
* A checagem (`get`) e a reserva (criar e guardar a Promise) acontecem no mesmo trecho
|
|
84
|
+
* síncrono — sem `await` entre elas — então duas chamadas concorrentes (`Promise.all`)
|
|
85
|
+
* nunca observam um estado intermediário: a segunda sempre encontra a Promise da primeira
|
|
86
|
+
* já registrada e aguarda o mesmo resultado, em vez de disparar um segundo envio.
|
|
87
|
+
* Garantia real: só dentro deste processo Node (mesma instância do Provider). Atomicidade
|
|
88
|
+
* entre processos/réplicas depende do `dedupStore.reserve` fornecido (RFC §4.2).
|
|
89
|
+
*/
|
|
90
|
+
const localSendsInFlight = new Map();
|
|
91
|
+
/** Resolve `from` e renderiza o template com segurança (Correção 4) — nunca deixa exceção escapar do contrato. */
|
|
92
|
+
function prepareSend(input) {
|
|
93
|
+
let from;
|
|
94
|
+
try {
|
|
95
|
+
from = input.from ?? senderResolver.resolveFrom(input.brand);
|
|
96
|
+
}
|
|
97
|
+
catch (err) {
|
|
98
|
+
logSanitized('[transactional-email] SenderResolver falhou:', errorMessage(err), [apiKey]);
|
|
99
|
+
return {
|
|
100
|
+
status: 'failed',
|
|
101
|
+
error: { code: 'unknown', message: 'Falha ao resolver o remetente do e-mail.' },
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
const addressError = validateAddresses({ to: input.to, from, replyTo: input.replyTo });
|
|
105
|
+
if (addressError) {
|
|
106
|
+
return { status: 'failed', error: addressError };
|
|
107
|
+
}
|
|
108
|
+
let rendered;
|
|
109
|
+
try {
|
|
110
|
+
rendered = templateRenderer.render(input.template, input.data);
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
logSanitized('[transactional-email] TemplateRenderer falhou:', errorMessage(err), [apiKey]);
|
|
114
|
+
return {
|
|
115
|
+
status: 'failed',
|
|
116
|
+
error: { code: 'unknown', message: 'Falha ao renderizar o template do e-mail.' },
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
return { from, rendered };
|
|
120
|
+
}
|
|
121
|
+
async function performSend(input) {
|
|
122
|
+
const prepared = prepareSend(input);
|
|
123
|
+
if ('status' in prepared) {
|
|
124
|
+
return prepared;
|
|
125
|
+
}
|
|
126
|
+
return sendViaResend({
|
|
127
|
+
apiKey: apiKey,
|
|
128
|
+
from: prepared.from,
|
|
129
|
+
to: input.to,
|
|
130
|
+
replyTo: input.replyTo,
|
|
131
|
+
tag: input.tag,
|
|
132
|
+
rendered: prepared.rendered,
|
|
133
|
+
timeoutMs,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
async function sendDeduplicated(input, dedupKey) {
|
|
137
|
+
const existingInFlight = localSendsInFlight.get(dedupKey);
|
|
138
|
+
if (existingInFlight) {
|
|
139
|
+
return existingInFlight;
|
|
140
|
+
}
|
|
141
|
+
const sendPromise = (async () => {
|
|
142
|
+
try {
|
|
143
|
+
let reservation = await safeDedupCall('reserve', () => dedupStore.reserve(dedupKey, MIN_DEDUP_WINDOW_MS), { acquired: true });
|
|
144
|
+
if (!reservation.acquired && reservation.entry) {
|
|
145
|
+
return reservation.entry.result;
|
|
146
|
+
}
|
|
147
|
+
if (!reservation.acquired) {
|
|
148
|
+
// Reserva de outra instância/réplica em andamento, sem resultado ainda disponível
|
|
149
|
+
// (só ocorre com um DedupStore `mode: 'shared'` real — `InMemoryDedupStore` nunca
|
|
150
|
+
// devolve esse caso, ver seu jsdoc). Bloqueador 2 (Certification Round 2): a versão
|
|
151
|
+
// anterior caía direto em `performSend` aqui, reenviando às cegas. Agora espera de
|
|
152
|
+
// forma limitada pelo resultado real da outra instância antes de decidir qualquer coisa.
|
|
153
|
+
const remoteEntry = await waitForRemoteResult(dedupKey, remoteReservationPollIntervalMs, remoteReservationMaxWaitMs);
|
|
154
|
+
if (remoteEntry) {
|
|
155
|
+
return remoteEntry.result;
|
|
156
|
+
}
|
|
157
|
+
// Esgotado o tempo de espera: a reserva remota pode estar órfã (a instância que a
|
|
158
|
+
// detinha morreu sem liberar) — tenta assumir. Se o TTL da reserva remota já expirou
|
|
159
|
+
// no store, esta chamada adquire; caso contrário, ainda pertence a outra instância viva.
|
|
160
|
+
reservation = await safeDedupCall('reserve', () => dedupStore.reserve(dedupKey, MIN_DEDUP_WINDOW_MS), { acquired: true });
|
|
161
|
+
if (!reservation.acquired) {
|
|
162
|
+
if (reservation.entry) {
|
|
163
|
+
return reservation.entry.result;
|
|
164
|
+
}
|
|
165
|
+
// Ainda sem dono claro após a espera + nova tentativa: nunca reenviar às cegas
|
|
166
|
+
// (romperia o invariante de dedup). Falha determinística e retryable — o consumidor
|
|
167
|
+
// decide se tenta de novo (RFC §5, taxonomia por retryability).
|
|
168
|
+
return {
|
|
169
|
+
status: 'failed',
|
|
170
|
+
error: {
|
|
171
|
+
code: 'provider-unavailable',
|
|
172
|
+
message: 'Coordenação de deduplicação não respondeu a tempo; tente novamente.',
|
|
173
|
+
},
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
// `reservation.acquired === true`: este chamador é o dono do envio.
|
|
178
|
+
const result = await performSend(input);
|
|
179
|
+
await safeDedupCall('set', () => dedupStore.set(dedupKey, { result, expiresAt: Date.now() + MIN_DEDUP_WINDOW_MS }), undefined);
|
|
180
|
+
return result;
|
|
181
|
+
}
|
|
182
|
+
finally {
|
|
183
|
+
localSendsInFlight.delete(dedupKey);
|
|
184
|
+
}
|
|
185
|
+
})();
|
|
186
|
+
localSendsInFlight.set(dedupKey, sendPromise);
|
|
187
|
+
return sendPromise;
|
|
188
|
+
}
|
|
189
|
+
async function sendTransactionalEmail(rawInput) {
|
|
190
|
+
let input = rawInput;
|
|
191
|
+
for (const hook of hooks) {
|
|
192
|
+
if (hook.beforeSend) {
|
|
193
|
+
input = runSafely(() => hook.beforeSend(input), apiKey) ?? input;
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
const startedAt = Date.now();
|
|
197
|
+
if (!apiKey) {
|
|
198
|
+
const result = { status: 'skipped' };
|
|
199
|
+
logOutcome(input, result, startedAt, apiKey);
|
|
200
|
+
notifyAfterSend(hooks, input, result, apiKey);
|
|
201
|
+
return result;
|
|
202
|
+
}
|
|
203
|
+
const dedupKey = input.idempotencyKey
|
|
204
|
+
? buildDedupKey(input.to, input.template, input.idempotencyKey)
|
|
205
|
+
: null;
|
|
206
|
+
const result = dedupKey ? await sendDeduplicated(input, dedupKey) : await performSend(input);
|
|
207
|
+
logOutcome(input, result, startedAt, apiKey);
|
|
208
|
+
notifyAfterSend(hooks, input, result, apiKey);
|
|
209
|
+
return result;
|
|
210
|
+
}
|
|
211
|
+
return { sendTransactionalEmail };
|
|
212
|
+
}
|
|
213
|
+
function errorMessage(err) {
|
|
214
|
+
return err instanceof Error ? err.message : String(err);
|
|
215
|
+
}
|
|
216
|
+
/**
|
|
217
|
+
* Log estruturado mínimo de observabilidade (validação operacional pré-certificação).
|
|
218
|
+
* Sempre sanitizado — nunca inclui a apiKey nem o corpo bruto do provider (Bloqueador 1).
|
|
219
|
+
* Não inclui identificador de correlação porque o contrato atual (`SendTransactionalEmailInput`)
|
|
220
|
+
* não define um — não é inventado aqui (RFC não estende o contrato nesta correção).
|
|
221
|
+
*/
|
|
222
|
+
function logOutcome(input, result, startedAt, apiKey) {
|
|
223
|
+
logSanitizedInfo('[transactional-email] outcome', {
|
|
224
|
+
status: result.status,
|
|
225
|
+
errorCode: result.error?.code,
|
|
226
|
+
durationMs: Date.now() - startedAt,
|
|
227
|
+
template: input.template,
|
|
228
|
+
deduplicated: Boolean(input.idempotencyKey),
|
|
229
|
+
}, [apiKey]);
|
|
230
|
+
}
|
|
231
|
+
/** Hooks nunca podem quebrar o envio principal — falha de um hook é ignorada (logada), não propagada. */
|
|
232
|
+
function runSafely(fn, apiKey) {
|
|
233
|
+
try {
|
|
234
|
+
return fn();
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
logSanitized('[transactional-email] hook falhou (ignorado):', errorMessage(err), [apiKey]);
|
|
238
|
+
return undefined;
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
function notifyAfterSend(hooks, input, result, apiKey) {
|
|
242
|
+
for (const hook of hooks) {
|
|
243
|
+
if (hook.afterSend) {
|
|
244
|
+
runSafely(() => hook.afterSend(input, result), apiKey);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../src/mail/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { DeliveryResult, EmailAddress, RenderedEmail } from './types.js';
|
|
2
|
+
export interface SendViaResendInput {
|
|
3
|
+
apiKey: string;
|
|
4
|
+
from: EmailAddress;
|
|
5
|
+
to: EmailAddress;
|
|
6
|
+
replyTo?: EmailAddress;
|
|
7
|
+
tag?: string;
|
|
8
|
+
rendered: RenderedEmail;
|
|
9
|
+
timeoutMs: number;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Cliente HTTP de baixo nível do Provider Resend. Nunca importado fora de `mail/` —
|
|
13
|
+
* o Resend é um Provider substituível (ADR-ECO-0019), não uma dependência do contrato.
|
|
14
|
+
*/
|
|
15
|
+
export declare function sendViaResend(input: SendViaResendInput): Promise<DeliveryResult>;
|
|
16
|
+
//# sourceMappingURL=resend-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-client.d.ts","sourceRoot":"","sources":["../../src/mail/resend-client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAqB,cAAc,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAkBjG,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,YAAY,CAAC;IACnB,EAAE,EAAE,YAAY,CAAC;IACjB,OAAO,CAAC,EAAE,YAAY,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,aAAa,CAAC;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,cAAc,CAAC,CAmDtF"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { logSanitized } from './sanitize.js';
|
|
2
|
+
const RESEND_ENDPOINT = 'https://api.resend.com/emails';
|
|
3
|
+
/**
|
|
4
|
+
* Mensagens públicas canônicas por código de erro (Bloqueador 1 — RFC §4.2/invariante).
|
|
5
|
+
* `DeliveryResult.error.message` nunca contém o corpo bruto do provider — o detalhe
|
|
6
|
+
* técnico (sanitizado) só vai para o log interno via `logSanitized`.
|
|
7
|
+
*/
|
|
8
|
+
const CANONICAL_ERROR_MESSAGES = {
|
|
9
|
+
timeout: 'O provider de e-mail não respondeu dentro do tempo limite.',
|
|
10
|
+
'provider-unavailable': 'O provider de e-mail está indisponível no momento.',
|
|
11
|
+
'invalid-recipient': 'O provider de e-mail rejeitou o endereço informado.',
|
|
12
|
+
'provider-rejected': 'O provider de e-mail rejeitou a requisição.',
|
|
13
|
+
unknown: 'Falha desconhecida ao contatar o provider de e-mail.',
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Cliente HTTP de baixo nível do Provider Resend. Nunca importado fora de `mail/` —
|
|
17
|
+
* o Resend é um Provider substituível (ADR-ECO-0019), não uma dependência do contrato.
|
|
18
|
+
*/
|
|
19
|
+
export async function sendViaResend(input) {
|
|
20
|
+
const controller = new AbortController();
|
|
21
|
+
const timer = setTimeout(() => controller.abort(), input.timeoutMs);
|
|
22
|
+
try {
|
|
23
|
+
const res = await fetch(RESEND_ENDPOINT, {
|
|
24
|
+
method: 'POST',
|
|
25
|
+
headers: {
|
|
26
|
+
Authorization: `Bearer ${input.apiKey}`,
|
|
27
|
+
'Content-Type': 'application/json',
|
|
28
|
+
},
|
|
29
|
+
body: JSON.stringify({
|
|
30
|
+
from: input.from,
|
|
31
|
+
to: [input.to],
|
|
32
|
+
subject: input.rendered.subject,
|
|
33
|
+
html: input.rendered.html,
|
|
34
|
+
text: input.rendered.text,
|
|
35
|
+
reply_to: input.replyTo,
|
|
36
|
+
tags: input.tag ? [{ name: 'type', value: input.tag }] : undefined,
|
|
37
|
+
}),
|
|
38
|
+
signal: controller.signal,
|
|
39
|
+
});
|
|
40
|
+
const rawText = await res.text();
|
|
41
|
+
const json = rawText ? safeJsonParse(rawText) : {};
|
|
42
|
+
if (res.ok) {
|
|
43
|
+
return {
|
|
44
|
+
status: 'sent',
|
|
45
|
+
providerId: typeof json['id'] === 'string' ? json['id'] : undefined,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
return { status: 'failed', error: classifyResendError(res.status, json, input.apiKey) };
|
|
49
|
+
}
|
|
50
|
+
catch (err) {
|
|
51
|
+
if (err instanceof Error && err.name === 'AbortError') {
|
|
52
|
+
return {
|
|
53
|
+
status: 'failed',
|
|
54
|
+
error: { code: 'timeout', message: `Resend não respondeu em ${input.timeoutMs}ms` },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
status: 'failed',
|
|
59
|
+
error: {
|
|
60
|
+
code: 'provider-unavailable',
|
|
61
|
+
message: 'Falha de rede ao contatar o provider de e-mail',
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
clearTimeout(timer);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
function safeJsonParse(text) {
|
|
70
|
+
try {
|
|
71
|
+
return JSON.parse(text);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return {};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Classificação por retryability (RFC §5, R1). O corpo bruto do provider é lido só para
|
|
79
|
+
* classificar o status e para logging interno sanitizado (Bloqueador 1) — nunca é
|
|
80
|
+
* devolvido ao chamador. `DeliveryResult.error.message` é sempre a mensagem pública
|
|
81
|
+
* canônica correspondente ao código, nunca o texto que o provider enviou.
|
|
82
|
+
*/
|
|
83
|
+
function classifyResendError(status, body, apiKey) {
|
|
84
|
+
const providerMessage = typeof body['message'] === 'string' ? body['message'] : `Resend respondeu ${status}`;
|
|
85
|
+
const code = classifyResendStatus(status);
|
|
86
|
+
logSanitized('[transactional-email] provider respondeu com erro:', { status, code, providerMessage }, [apiKey]);
|
|
87
|
+
return { code, message: CANONICAL_ERROR_MESSAGES[code] };
|
|
88
|
+
}
|
|
89
|
+
function classifyResendStatus(status) {
|
|
90
|
+
if (status >= 500)
|
|
91
|
+
return 'provider-unavailable';
|
|
92
|
+
if (status === 401 || status === 403)
|
|
93
|
+
return 'provider-rejected';
|
|
94
|
+
if (status === 422)
|
|
95
|
+
return 'invalid-recipient';
|
|
96
|
+
if (status >= 400)
|
|
97
|
+
return 'provider-rejected';
|
|
98
|
+
return 'unknown';
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=resend-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resend-client.js","sourceRoot":"","sources":["../../src/mail/resend-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/mail/resend.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/mail/resend.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,CAAC;CACd;AAED,wBAAsB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,EAAE,GAAG,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,CAc/F"}
|
package/dist/mail/resend.js
CHANGED
|
@@ -6,6 +6,8 @@ export async function sendEmail(apiKey, msg) {
|
|
|
6
6
|
method: 'POST',
|
|
7
7
|
headers: { authorization: `Bearer ${apiKey}`, 'content-type': 'application/json' },
|
|
8
8
|
body: JSON.stringify(msg),
|
|
9
|
+
// Best-effort com teto: um Resend pendurado não pode segurar o chamador.
|
|
10
|
+
signal: AbortSignal.timeout(8000),
|
|
9
11
|
});
|
|
10
12
|
return res.ok;
|
|
11
13
|
}
|
package/dist/mail/resend.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resend.js","sourceRoot":"","sources":["../../src/mail/resend.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAA0B,EAAE,GAAiB;IAC3E,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,+BAA+B,EAAE;YACvD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAClF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;
|
|
1
|
+
{"version":3,"file":"resend.js","sourceRoot":"","sources":["../../src/mail/resend.ts"],"names":[],"mappings":"AAYA,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,MAA0B,EAAE,GAAiB;IAC3E,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CAAC,+BAA+B,EAAE;YACvD,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,MAAM,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAClF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC;YACzB,yEAAyE;YACzE,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,OAAO,GAAG,CAAC,EAAE,CAAC;IAChB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitização genérica de segredos (Bloqueador 1 — Auditoria Codex, Capability Certification 001/002).
|
|
3
|
+
* Nunca depende de um valor específico de teste, nem de um formato específico de credencial: redige
|
|
4
|
+
* a(s) credencial(is) conhecida(s) em tempo de execução (ex.: a apiKey configurada) e, defensivamente,
|
|
5
|
+
* a FORMA de um segredo (par chave=valor rotulado, credencial embutida em URI, token estruturado tipo
|
|
6
|
+
* JWT, ou qualquer string opaca de alta entropia) — nunca uma lista fechada de formatos conhecidos.
|
|
7
|
+
* Certification Round 2 (2026-07-21) apontou que a v1 só cobria padrões rotulados
|
|
8
|
+
* (`token=`/`Authorization:`/`Bearer `); esta versão adiciona duas camadas adicionais, também
|
|
9
|
+
* genéricas, para cobrir formatos desconhecidos a priori (ver Evidence Mapping, `CAPABILITY_REGRESSION_MATRIX.md`).
|
|
10
|
+
*/
|
|
11
|
+
/** Redige ocorrências de segredos conhecidos (por valor) e de padrões genéricos de credencial (por forma). */
|
|
12
|
+
export declare function redactSecrets(text: string, knownSecrets: ReadonlyArray<string | undefined>): string;
|
|
13
|
+
/** console.error sanitizado — nenhum segredo conhecido chega ao log (Bloqueador 1, requisito de logging). */
|
|
14
|
+
export declare function logSanitized(prefix: string, detail: unknown, knownSecrets: ReadonlyArray<string | undefined>): void;
|
|
15
|
+
/** console.log sanitizado — para eventos informativos (ex.: outcome de envio), não erros. */
|
|
16
|
+
export declare function logSanitizedInfo(prefix: string, detail: unknown, knownSecrets: ReadonlyArray<string | undefined>): void;
|
|
17
|
+
//# sourceMappingURL=sanitize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.d.ts","sourceRoot":"","sources":["../../src/mail/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAqBH,8GAA8G;AAC9G,wBAAgB,aAAa,CAC3B,IAAI,EAAE,MAAM,EACZ,YAAY,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,GAC9C,MAAM,CAWR;AAED,6GAA6G;AAC7G,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,GAC9C,IAAI,CAGN;AAED,6FAA6F;AAC7F,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,OAAO,EACf,YAAY,EAAE,aAAa,CAAC,MAAM,GAAG,SAAS,CAAC,GAC9C,IAAI,CAGN"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sanitização genérica de segredos (Bloqueador 1 — Auditoria Codex, Capability Certification 001/002).
|
|
3
|
+
* Nunca depende de um valor específico de teste, nem de um formato específico de credencial: redige
|
|
4
|
+
* a(s) credencial(is) conhecida(s) em tempo de execução (ex.: a apiKey configurada) e, defensivamente,
|
|
5
|
+
* a FORMA de um segredo (par chave=valor rotulado, credencial embutida em URI, token estruturado tipo
|
|
6
|
+
* JWT, ou qualquer string opaca de alta entropia) — nunca uma lista fechada de formatos conhecidos.
|
|
7
|
+
* Certification Round 2 (2026-07-21) apontou que a v1 só cobria padrões rotulados
|
|
8
|
+
* (`token=`/`Authorization:`/`Bearer `); esta versão adiciona duas camadas adicionais, também
|
|
9
|
+
* genéricas, para cobrir formatos desconhecidos a priori (ver Evidence Mapping, `CAPABILITY_REGRESSION_MATRIX.md`).
|
|
10
|
+
*/
|
|
11
|
+
const REDACTED = '[REDACTED]';
|
|
12
|
+
const SENSITIVE_VALUE_PATTERNS = [
|
|
13
|
+
// Camada 1 — segredo rotulado: "Bearer <token>" / "Authorization: <valor>" / "api_key=<valor>" etc.
|
|
14
|
+
/bearer\s+\S+/gi,
|
|
15
|
+
/authorization\s*[:=]\s*\S+/gi,
|
|
16
|
+
/\b(api[_-]?key|apikey|access[_-]?token|refresh[_-]?token|client[_-]?secret|secret|token|password|passwd|pwd)\b\s*[:=]\s*['"]?[^\s'",;]{4,}['"]?/gi,
|
|
17
|
+
// Camada 2 — credencial embutida em URI (scheme://user:senha@host), formato comum de connection
|
|
18
|
+
// string (Redis/Postgres/etc.) que nenhuma regra rotulada acima captura.
|
|
19
|
+
/\b[a-z][a-z0-9+.-]*:\/\/[^\s/:@'"]+:[^\s/@'"]+@/gi,
|
|
20
|
+
// Camada 3 — token estruturado tipo JWT (3 segmentos base64url separados por ".").
|
|
21
|
+
/\bey[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\.[a-zA-Z0-9_-]{10,}\b/g,
|
|
22
|
+
// Camada 4 — última linha de defesa: qualquer string opaca de alta entropia (>= 20 chars,
|
|
23
|
+
// mistura letras+dígitos, sem espaço) que sobrou sem rótulo reconhecido — cobre formatos de
|
|
24
|
+
// provider desconhecidos a priori (ex.: `re_...` do Resend, `sk_live_...` do Stripe, `AKIA...`
|
|
25
|
+
// da AWS) sem codificar nenhum deles por nome, conforme exigido pela Certification Round 2.
|
|
26
|
+
/\b(?=[a-zA-Z0-9_-]{20,}\b)(?=[a-zA-Z0-9_-]*[0-9])(?=[a-zA-Z0-9_-]*[a-zA-Z])[a-zA-Z0-9_-]{20,}\b/g,
|
|
27
|
+
];
|
|
28
|
+
/** Redige ocorrências de segredos conhecidos (por valor) e de padrões genéricos de credencial (por forma). */
|
|
29
|
+
export function redactSecrets(text, knownSecrets) {
|
|
30
|
+
let redacted = text;
|
|
31
|
+
for (const secret of knownSecrets) {
|
|
32
|
+
if (secret && secret.length >= 4) {
|
|
33
|
+
redacted = redacted.split(secret).join(REDACTED);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
for (const pattern of SENSITIVE_VALUE_PATTERNS) {
|
|
37
|
+
redacted = redacted.replace(pattern, REDACTED);
|
|
38
|
+
}
|
|
39
|
+
return redacted;
|
|
40
|
+
}
|
|
41
|
+
/** console.error sanitizado — nenhum segredo conhecido chega ao log (Bloqueador 1, requisito de logging). */
|
|
42
|
+
export function logSanitized(prefix, detail, knownSecrets) {
|
|
43
|
+
const serialized = typeof detail === 'string' ? detail : JSON.stringify(detail);
|
|
44
|
+
console.error(prefix, redactSecrets(serialized, knownSecrets));
|
|
45
|
+
}
|
|
46
|
+
/** console.log sanitizado — para eventos informativos (ex.: outcome de envio), não erros. */
|
|
47
|
+
export function logSanitizedInfo(prefix, detail, knownSecrets) {
|
|
48
|
+
const serialized = typeof detail === 'string' ? detail : JSON.stringify(detail);
|
|
49
|
+
console.log(prefix, redactSecrets(serialized, knownSecrets));
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=sanitize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sanitize.js","sourceRoot":"","sources":["../../src/mail/sanitize.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,QAAQ,GAAG,YAAY,CAAC;AAE9B,MAAM,wBAAwB,GAAa;IACzC,oGAAoG;IACpG,gBAAgB;IAChB,8BAA8B;IAC9B,mJAAmJ;IACnJ,gGAAgG;IAChG,yEAAyE;IACzE,mDAAmD;IACnD,mFAAmF;IACnF,mEAAmE;IACnE,0FAA0F;IAC1F,4FAA4F;IAC5F,+FAA+F;IAC/F,4FAA4F;IAC5F,kGAAkG;CACnG,CAAC;AAEF,8GAA8G;AAC9G,MAAM,UAAU,aAAa,CAC3B,IAAY,EACZ,YAA+C;IAE/C,IAAI,QAAQ,GAAG,IAAI,CAAC;IACpB,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;QAClC,IAAI,MAAM,IAAI,MAAM,CAAC,MAAM,IAAI,CAAC,EAAE,CAAC;YACjC,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IACD,KAAK,MAAM,OAAO,IAAI,wBAAwB,EAAE,CAAC;QAC/C,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IACjD,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,6GAA6G;AAC7G,MAAM,UAAU,YAAY,CAC1B,MAAc,EACd,MAAe,EACf,YAA+C;IAE/C,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChF,OAAO,CAAC,KAAK,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;AACjE,CAAC;AAED,6FAA6F;AAC7F,MAAM,UAAU,gBAAgB,CAC9B,MAAc,EACd,MAAe,EACf,YAA+C;IAE/C,MAAM,UAAU,GAAG,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,UAAU,EAAE,YAAY,CAAC,CAAC,CAAC;AAC/D,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { EmailAddress, SenderResolver } from './types.js';
|
|
2
|
+
/** Default — sempre retorna o `from` configurado no Provider, ignorando `brand` (RFC §4.5, precedência 3). */
|
|
3
|
+
export declare class StaticSenderResolver implements SenderResolver {
|
|
4
|
+
private readonly defaultFrom;
|
|
5
|
+
constructor(defaultFrom: EmailAddress);
|
|
6
|
+
resolveFrom(): EmailAddress;
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=sender-resolver.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender-resolver.d.ts","sourceRoot":"","sources":["../../src/mail/sender-resolver.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE/D,8GAA8G;AAC9G,qBAAa,oBAAqB,YAAW,cAAc;IAC7C,OAAO,CAAC,QAAQ,CAAC,WAAW;gBAAX,WAAW,EAAE,YAAY;IAEtD,WAAW,IAAI,YAAY;CAG5B"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/** Default — sempre retorna o `from` configurado no Provider, ignorando `brand` (RFC §4.5, precedência 3). */
|
|
2
|
+
export class StaticSenderResolver {
|
|
3
|
+
defaultFrom;
|
|
4
|
+
constructor(defaultFrom) {
|
|
5
|
+
this.defaultFrom = defaultFrom;
|
|
6
|
+
}
|
|
7
|
+
resolveFrom() {
|
|
8
|
+
return this.defaultFrom;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=sender-resolver.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sender-resolver.js","sourceRoot":"","sources":["../../src/mail/sender-resolver.ts"],"names":[],"mappings":"AAEA,8GAA8G;AAC9G,MAAM,OAAO,oBAAoB;IACF;IAA7B,YAA6B,WAAyB;QAAzB,gBAAW,GAAX,WAAW,CAAc;IAAG,CAAC;IAE1D,WAAW;QACT,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1B,CAAC;CACF"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { RenderedEmail, TemplateRenderer } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Default — escape hatch para consumidores sem motor de template (RFC §4.3, melhoria recomendada).
|
|
4
|
+
* `data` já deve chegar como `{ subject, html, text? }` pronto; `template` é usado só como
|
|
5
|
+
* rótulo opaco (logging/tag), nunca resolvido.
|
|
6
|
+
*/
|
|
7
|
+
export declare class PassthroughTemplateRenderer implements TemplateRenderer {
|
|
8
|
+
render(template: string, data: Record<string, unknown>): RenderedEmail;
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=template-renderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-renderer.d.ts","sourceRoot":"","sources":["../../src/mail/template-renderer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAElE;;;;GAIG;AACH,qBAAa,2BAA4B,YAAW,gBAAgB;IAClE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,aAAa;CAavE"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Default — escape hatch para consumidores sem motor de template (RFC §4.3, melhoria recomendada).
|
|
3
|
+
* `data` já deve chegar como `{ subject, html, text? }` pronto; `template` é usado só como
|
|
4
|
+
* rótulo opaco (logging/tag), nunca resolvido.
|
|
5
|
+
*/
|
|
6
|
+
export class PassthroughTemplateRenderer {
|
|
7
|
+
render(template, data) {
|
|
8
|
+
const subject = data['subject'];
|
|
9
|
+
const html = data['html'];
|
|
10
|
+
const text = data['text'];
|
|
11
|
+
if (typeof subject !== 'string' || typeof html !== 'string') {
|
|
12
|
+
throw new Error(`PassthroughTemplateRenderer: template "${template}" exige data.subject e data.html como string`);
|
|
13
|
+
}
|
|
14
|
+
return { subject, html, text: typeof text === 'string' ? text : undefined };
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=template-renderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-renderer.js","sourceRoot":"","sources":["../../src/mail/template-renderer.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,OAAO,2BAA2B;IACtC,MAAM,CAAC,QAAgB,EAAE,IAA6B;QACpD,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAC1B,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC;QAE1B,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC5D,MAAM,IAAI,KAAK,CACb,0CAA0C,QAAQ,8CAA8C,CACjG,CAAC;QACJ,CAAC;QAED,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC;IAC9E,CAAC;CACF"}
|