@baruk/core 0.1.0 → 0.3.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 +63 -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 +43 -0
- package/dist/commercial-catalog/coupon.d.ts.map +1 -0
- package/dist/commercial-catalog/coupon.js +57 -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 +175 -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,167 @@
|
|
|
1
|
+
import { NotFoundError, uuidv7 } from '@baruk/shared';
|
|
2
|
+
function mapFee(r) {
|
|
3
|
+
return {
|
|
4
|
+
id: r.id,
|
|
5
|
+
clientId: r.client_id,
|
|
6
|
+
description: r.description,
|
|
7
|
+
amount: Number(r.amount),
|
|
8
|
+
periodicity: r.periodicity,
|
|
9
|
+
dueDay: r.due_day,
|
|
10
|
+
billingMethod: r.billing_method,
|
|
11
|
+
discount: Number(r.discount),
|
|
12
|
+
finePercent: Number(r.fine_percent),
|
|
13
|
+
interestPercent: Number(r.interest_percent),
|
|
14
|
+
status: r.status,
|
|
15
|
+
startsOn: r.starts_on ? r.starts_on.toISOString().slice(0, 10) : null,
|
|
16
|
+
endsOn: r.ends_on ? r.ends_on.toISOString().slice(0, 10) : null,
|
|
17
|
+
createdAt: r.created_at.toISOString(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
const FEE_COLS = `
|
|
21
|
+
id, client_id, description, amount, periodicity, due_day, billing_method,
|
|
22
|
+
discount, fine_percent, interest_percent, status, starts_on, ends_on, created_at
|
|
23
|
+
`;
|
|
24
|
+
export async function createFeeAgreement(tx, input) {
|
|
25
|
+
const rows = await tx `
|
|
26
|
+
INSERT INTO fee_agreement (
|
|
27
|
+
id, tenant_id, client_id, description, amount, periodicity, due_day,
|
|
28
|
+
billing_method, discount, fine_percent, interest_percent, starts_on, created_by
|
|
29
|
+
) VALUES (
|
|
30
|
+
${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.clientId},
|
|
31
|
+
${input.description ?? 'Honorários'}, ${input.amount}, ${input.periodicity ?? 'monthly'},
|
|
32
|
+
${input.dueDay ?? null}, ${input.billingMethod ?? 'pix'}, ${input.discount ?? 0},
|
|
33
|
+
${input.finePercent ?? 0}, ${input.interestPercent ?? 0}, ${input.startsOn ?? null}, ${input.createdBy ?? null}
|
|
34
|
+
)
|
|
35
|
+
RETURNING ${tx.unsafe(FEE_COLS)}
|
|
36
|
+
`;
|
|
37
|
+
return mapFee(rows[0]);
|
|
38
|
+
}
|
|
39
|
+
export async function listFeeAgreements(tx, clientId) {
|
|
40
|
+
const rows = await tx `
|
|
41
|
+
SELECT ${tx.unsafe(FEE_COLS)} FROM fee_agreement
|
|
42
|
+
WHERE deleted_at IS NULL
|
|
43
|
+
AND (${clientId ?? null}::uuid IS NULL OR client_id = ${clientId ?? null})
|
|
44
|
+
ORDER BY created_at DESC
|
|
45
|
+
`;
|
|
46
|
+
return rows.map(mapFee);
|
|
47
|
+
}
|
|
48
|
+
export async function setFeeStatus(tx, id, status) {
|
|
49
|
+
const rows = await tx `
|
|
50
|
+
UPDATE fee_agreement SET status = ${status}, updated_at = now(), version = version + 1
|
|
51
|
+
WHERE id = ${id} AND deleted_at IS NULL RETURNING id
|
|
52
|
+
`;
|
|
53
|
+
return rows.count;
|
|
54
|
+
}
|
|
55
|
+
function mapCharge(r) {
|
|
56
|
+
return {
|
|
57
|
+
id: r.id,
|
|
58
|
+
clientId: r.client_id,
|
|
59
|
+
feeAgreementId: r.fee_agreement_id,
|
|
60
|
+
provider: r.provider,
|
|
61
|
+
externalId: r.external_id,
|
|
62
|
+
method: r.method,
|
|
63
|
+
amount: Number(r.amount),
|
|
64
|
+
status: r.status,
|
|
65
|
+
description: r.description,
|
|
66
|
+
dueDate: r.due_date ? r.due_date.toISOString().slice(0, 10) : null,
|
|
67
|
+
paidAt: r.paid_at ? r.paid_at.toISOString() : null,
|
|
68
|
+
metadata: r.metadata ?? {},
|
|
69
|
+
createdAt: r.created_at.toISOString(),
|
|
70
|
+
};
|
|
71
|
+
}
|
|
72
|
+
const CHARGE_COLS = `
|
|
73
|
+
id, client_id, fee_agreement_id, provider, external_id, method, amount,
|
|
74
|
+
status, description, due_date, paid_at, metadata, created_at
|
|
75
|
+
`;
|
|
76
|
+
export async function createCharge(tx, input) {
|
|
77
|
+
const rows = await tx `
|
|
78
|
+
INSERT INTO charge (
|
|
79
|
+
id, tenant_id, client_id, fee_agreement_id, provider, external_id, method,
|
|
80
|
+
amount, status, description, due_date, metadata, created_by
|
|
81
|
+
) VALUES (
|
|
82
|
+
${uuidv7()}, current_setting('app.current_tenant')::uuid, ${input.clientId},
|
|
83
|
+
${input.feeAgreementId ?? null}, ${input.provider ?? 'manual'}, ${input.externalId ?? null},
|
|
84
|
+
${input.method ?? 'pix'}, ${input.amount}, ${input.status ?? 'pending'},
|
|
85
|
+
${input.description ?? null}, ${input.dueDate ?? null},
|
|
86
|
+
${tx.json((input.metadata ?? {}))}, ${input.createdBy ?? null}
|
|
87
|
+
)
|
|
88
|
+
RETURNING ${tx.unsafe(CHARGE_COLS)}
|
|
89
|
+
`;
|
|
90
|
+
return mapCharge(rows[0]);
|
|
91
|
+
}
|
|
92
|
+
export async function listCharges(tx, filter = {}) {
|
|
93
|
+
const limit = Math.min(filter.limit ?? 50, 200);
|
|
94
|
+
const offset = filter.offset ?? 0;
|
|
95
|
+
const rows = await tx `
|
|
96
|
+
SELECT ${tx.unsafe(CHARGE_COLS)}, count(*) OVER() AS total
|
|
97
|
+
FROM charge
|
|
98
|
+
WHERE deleted_at IS NULL
|
|
99
|
+
AND (${filter.clientId ?? null}::uuid IS NULL OR client_id = ${filter.clientId ?? null})
|
|
100
|
+
AND (${filter.status ?? null}::text IS NULL OR status = ${filter.status ?? null})
|
|
101
|
+
ORDER BY created_at DESC
|
|
102
|
+
LIMIT ${limit} OFFSET ${offset}
|
|
103
|
+
`;
|
|
104
|
+
const total = rows[0] ? Number(rows[0].total) : 0;
|
|
105
|
+
return { items: rows.map(mapCharge), total };
|
|
106
|
+
}
|
|
107
|
+
export async function getCharge(tx, id) {
|
|
108
|
+
const rows = await tx `
|
|
109
|
+
SELECT ${tx.unsafe(CHARGE_COLS)} FROM charge WHERE id = ${id} AND deleted_at IS NULL
|
|
110
|
+
`;
|
|
111
|
+
if (!rows[0])
|
|
112
|
+
throw new NotFoundError('Cobrança não encontrada');
|
|
113
|
+
return mapCharge(rows[0]);
|
|
114
|
+
}
|
|
115
|
+
export async function markChargePaid(tx, id, paidAt) {
|
|
116
|
+
const rows = await tx `
|
|
117
|
+
UPDATE charge SET status = 'paid', paid_at = COALESCE(${paidAt ?? null}::timestamptz, now()),
|
|
118
|
+
updated_at = now(), version = version + 1
|
|
119
|
+
WHERE id = ${id} AND deleted_at IS NULL AND status <> 'paid' RETURNING id
|
|
120
|
+
`;
|
|
121
|
+
return rows.count;
|
|
122
|
+
}
|
|
123
|
+
/** Reconciliação por webhook: encontra a cobrança pelo (provider, external_id) e marca paga. */
|
|
124
|
+
export async function markChargePaidByExternal(tx, provider, externalId, paidAt) {
|
|
125
|
+
const rows = await tx `
|
|
126
|
+
UPDATE charge SET status = 'paid', paid_at = COALESCE(${paidAt ?? null}::timestamptz, now()),
|
|
127
|
+
updated_at = now(), version = version + 1
|
|
128
|
+
WHERE provider = ${provider} AND external_id = ${externalId}
|
|
129
|
+
AND deleted_at IS NULL AND status <> 'paid' RETURNING id
|
|
130
|
+
`;
|
|
131
|
+
return rows.count;
|
|
132
|
+
}
|
|
133
|
+
export async function setChargeStatus(tx, id, status) {
|
|
134
|
+
const rows = await tx `
|
|
135
|
+
UPDATE charge SET status = ${status}, updated_at = now(), version = version + 1
|
|
136
|
+
WHERE id = ${id} AND deleted_at IS NULL RETURNING id
|
|
137
|
+
`;
|
|
138
|
+
return rows.count;
|
|
139
|
+
}
|
|
140
|
+
/** KPIs financeiros do dashboard: previsto, recebido e inadimplência. */
|
|
141
|
+
export async function billingSummary(tx) {
|
|
142
|
+
const rows = await tx `
|
|
143
|
+
SELECT
|
|
144
|
+
COALESCE(sum(amount) FILTER (WHERE status IN ('pending','sent','overdue')), 0) AS expected,
|
|
145
|
+
COALESCE(sum(amount) FILTER (WHERE status = 'paid'), 0) AS received,
|
|
146
|
+
COALESCE(sum(amount) FILTER (WHERE status = 'overdue'), 0) AS overdue,
|
|
147
|
+
COALESCE(count(*) FILTER (WHERE status = 'overdue'), 0)::int AS overdue_count
|
|
148
|
+
FROM charge WHERE deleted_at IS NULL
|
|
149
|
+
`;
|
|
150
|
+
const r = rows[0];
|
|
151
|
+
return {
|
|
152
|
+
expected: Number(r.expected),
|
|
153
|
+
received: Number(r.received),
|
|
154
|
+
overdue: Number(r.overdue),
|
|
155
|
+
overdueCount: r.overdue_count,
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
/** Cobranças em aberto vencidas até `today` — usadas pela régua de inadimplência. */
|
|
159
|
+
export async function listOpenCharges(tx) {
|
|
160
|
+
const rows = await tx `
|
|
161
|
+
SELECT ${tx.unsafe(CHARGE_COLS)} FROM charge
|
|
162
|
+
WHERE deleted_at IS NULL AND status IN ('pending','sent','overdue') AND due_date IS NOT NULL
|
|
163
|
+
ORDER BY due_date ASC
|
|
164
|
+
`;
|
|
165
|
+
return rows.map(mapCharge);
|
|
166
|
+
}
|
|
167
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../src/billing/repository.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.appendAudit = appendAudit;
|
|
4
|
+
const shared_1 = require("@baruk/shared");
|
|
5
|
+
/**
|
|
6
|
+
* Registra uma linha na trilha append-only. DEVE rodar dentro de um contexto de
|
|
7
|
+
* tenant (`withContext`): o `tenant_id` é derivado da GUC `app.current_tenant`,
|
|
8
|
+
* então a linha auditada sempre pertence ao tenant corrente e satisfaz a RLS.
|
|
9
|
+
*/
|
|
10
|
+
async function appendAudit(tx, entry) {
|
|
11
|
+
await tx `
|
|
12
|
+
INSERT INTO audit_log (
|
|
13
|
+
id, tenant_id, actor_type, actor_id, action, resource_type,
|
|
14
|
+
resource_id, result, diff, metadata, ip, user_agent
|
|
15
|
+
) VALUES (
|
|
16
|
+
${(0, shared_1.uuidv7)()},
|
|
17
|
+
current_setting('app.current_tenant')::uuid,
|
|
18
|
+
${entry.actorType ?? 'user'},
|
|
19
|
+
${entry.actorId ?? null},
|
|
20
|
+
${entry.action},
|
|
21
|
+
${entry.resourceType},
|
|
22
|
+
${entry.resourceId ?? null},
|
|
23
|
+
${entry.result ?? 'success'},
|
|
24
|
+
${entry.diff === undefined ? null : tx.json(entry.diff)},
|
|
25
|
+
${tx.json((entry.metadata ?? {}))},
|
|
26
|
+
${entry.ip ?? null},
|
|
27
|
+
${entry.userAgent ?? null}
|
|
28
|
+
)
|
|
29
|
+
`;
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/audit/audit.ts"],"names":[],"mappings":";;AAsBA,kCAoBC;AA1CD,0CAAuD;AAiBvD;;;;GAIG;AACI,KAAK,UAAU,WAAW,CAAC,EAAM,EAAE,KAAiB;IACzD,MAAM,EAAE,CAAA;;;;;QAKF,IAAA,eAAM,GAAE;;QAER,KAAK,CAAC,SAAS,IAAI,MAAM;QACzB,KAAK,CAAC,OAAO,IAAI,IAAI;QACrB,KAAK,CAAC,MAAM;QACZ,KAAK,CAAC,YAAY;QAClB,KAAK,CAAC,UAAU,IAAI,IAAI;QACxB,KAAK,CAAC,MAAM,IAAI,SAAS;QACzB,KAAK,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,CAAC,IAAa,CAAC;QAC9D,EAAE,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,QAAQ,IAAI,EAAE,CAAU,CAAC;QACxC,KAAK,CAAC,EAAE,IAAI,IAAI;QAChB,KAAK,CAAC,SAAS,IAAI,IAAI;;GAE5B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.listAudit = listAudit;
|
|
4
|
+
/** Lista a trilha de auditoria do tenant corrente (RLS já isola). Somente leitura. */
|
|
5
|
+
async function listAudit(tx, filter = {}) {
|
|
6
|
+
const limit = Math.min(filter.limit ?? 30, 100);
|
|
7
|
+
const offset = filter.offset ?? 0;
|
|
8
|
+
const rows = await tx `
|
|
9
|
+
SELECT id, actor_type, actor_id, action, resource_type, resource_id, result,
|
|
10
|
+
occurred_at, count(*) OVER() AS total
|
|
11
|
+
FROM audit_log
|
|
12
|
+
WHERE (${filter.action ?? null}::text IS NULL OR action = ${filter.action ?? null})
|
|
13
|
+
AND (${filter.resourceType ?? null}::text IS NULL OR resource_type = ${filter.resourceType ?? null})
|
|
14
|
+
ORDER BY occurred_at DESC
|
|
15
|
+
LIMIT ${limit} OFFSET ${offset}
|
|
16
|
+
`;
|
|
17
|
+
const total = rows[0] ? Number(rows[0].total) : 0;
|
|
18
|
+
return {
|
|
19
|
+
total,
|
|
20
|
+
items: rows.map((r) => ({
|
|
21
|
+
id: r.id,
|
|
22
|
+
actorType: r.actor_type,
|
|
23
|
+
actorId: r.actor_id,
|
|
24
|
+
action: r.action,
|
|
25
|
+
resourceType: r.resource_type,
|
|
26
|
+
resourceId: r.resource_id,
|
|
27
|
+
result: r.result,
|
|
28
|
+
occurredAt: r.occurred_at.toISOString(),
|
|
29
|
+
})),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=repository.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"repository.js","sourceRoot":"","sources":["../../../src/audit/repository.ts"],"names":[],"mappings":";;AAcA,8BA+BC;AAhCD,sFAAsF;AAC/E,KAAK,UAAU,SAAS,CAC7B,EAAM,EACN,SAAsF,EAAE;IAExF,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,EAAE,GAAG,CAAC,CAAC;IAChD,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,CAAC,CAAC;IAClC,MAAM,IAAI,GAAG,MAAM,EAAE,CAEpB;;;;aAIU,MAAM,CAAC,MAAM,IAAI,IAAI,8BAA8B,MAAM,CAAC,MAAM,IAAI,IAAI;aACxE,MAAM,CAAC,YAAY,IAAI,IAAI,qCAAqC,MAAM,CAAC,YAAY,IAAI,IAAI;;YAE5F,KAAK,WAAW,MAAM;GAC/B,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClD,OAAO;QACL,KAAK;QACL,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACtB,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,SAAS,EAAE,CAAC,CAAC,UAAU;YACvB,OAAO,EAAE,CAAC,CAAC,QAAQ;YACnB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,YAAY,EAAE,CAAC,CAAC,aAAa;YAC7B,UAAU,EAAE,CAAC,CAAC,WAAW;YACzB,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,UAAU,EAAE,CAAC,CAAC,WAAW,CAAC,WAAW,EAAE;SACxC,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.requestPasswordReset = requestPasswordReset;
|
|
4
|
+
exports.resetPassword = resetPassword;
|
|
5
|
+
const shared_1 = require("@baruk/shared");
|
|
6
|
+
const password_js_1 = require("./password.js");
|
|
7
|
+
const session_token_js_1 = require("./session-token.js");
|
|
8
|
+
const RESET_TTL_MS = 60 * 60 * 1000; // 1h
|
|
9
|
+
const REAL_CLOCK = { now: () => Date.now() };
|
|
10
|
+
/**
|
|
11
|
+
* Solicita reset. Retorna o token EM CLARO (para compor o link do e-mail) e o
|
|
12
|
+
* userId — ou null se o e-mail não existe (o chamador responde genericamente
|
|
13
|
+
* de qualquer forma, para não revelar existência de conta).
|
|
14
|
+
*/
|
|
15
|
+
async function requestPasswordReset(db, email, clock = REAL_CLOCK) {
|
|
16
|
+
const users = await db `
|
|
17
|
+
SELECT id, status FROM "user" WHERE email = ${email} AND deleted_at IS NULL
|
|
18
|
+
`;
|
|
19
|
+
const user = users[0];
|
|
20
|
+
if (!user || user.status === 'disabled')
|
|
21
|
+
return null;
|
|
22
|
+
const { token, tokenHash } = (0, session_token_js_1.generateSessionToken)();
|
|
23
|
+
const now = clock.now();
|
|
24
|
+
await db `
|
|
25
|
+
INSERT INTO password_reset (id, user_id, token_hash, expires_at)
|
|
26
|
+
VALUES (${(0, shared_1.uuidv7)()}, ${user.id}, ${tokenHash}, ${new Date(now + RESET_TTL_MS)})
|
|
27
|
+
`;
|
|
28
|
+
return { token, userId: user.id };
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Redefine a senha usando um token válido (não usado, não expirado). Marca o
|
|
32
|
+
* token como usado, limpa `must_change_password` e revoga sessões anteriores.
|
|
33
|
+
*/
|
|
34
|
+
async function resetPassword(db, token, newPassword, clock = REAL_CLOCK) {
|
|
35
|
+
if (newPassword.length < 8)
|
|
36
|
+
return false;
|
|
37
|
+
const th = (0, session_token_js_1.hashToken)(token);
|
|
38
|
+
const rows = await db `
|
|
39
|
+
SELECT id, user_id FROM password_reset
|
|
40
|
+
WHERE token_hash = ${th} AND used_at IS NULL AND expires_at > ${new Date(clock.now())}
|
|
41
|
+
`;
|
|
42
|
+
const reset = rows[0];
|
|
43
|
+
if (!reset)
|
|
44
|
+
return false;
|
|
45
|
+
await db.begin(async (tx) => {
|
|
46
|
+
await tx `
|
|
47
|
+
INSERT INTO user_credential (user_id, password_hash, must_change_password)
|
|
48
|
+
VALUES (${reset.user_id}, ${(0, password_js_1.hashPassword)(newPassword)}, false)
|
|
49
|
+
ON CONFLICT (user_id) DO UPDATE
|
|
50
|
+
SET password_hash = EXCLUDED.password_hash, must_change_password = false, updated_at = now()
|
|
51
|
+
`;
|
|
52
|
+
await tx `UPDATE password_reset SET used_at = now() WHERE id = ${reset.id}`;
|
|
53
|
+
// Revoga sessões anteriores (uso único de fato).
|
|
54
|
+
await tx `UPDATE user_session SET revoked_at = now() WHERE user_id = ${reset.user_id} AND revoked_at IS NULL`;
|
|
55
|
+
});
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
//# sourceMappingURL=password-reset.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password-reset.js","sourceRoot":"","sources":["../../../src/auth/password-reset.ts"],"names":[],"mappings":";;AAiBA,oDAkBC;AAMD,sCA2BC;AApED,0CAAuC;AAEvC,+CAA6C;AAC7C,yDAAqE;AAErE,MAAM,YAAY,GAAG,EAAE,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC,KAAK;AAK1C,MAAM,UAAU,GAAU,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC;AAEpD;;;;GAIG;AACI,KAAK,UAAU,oBAAoB,CACxC,EAAM,EACN,KAAa,EACb,QAAe,UAAU;IAEzB,MAAM,KAAK,GAAG,MAAM,EAAE,CAAkC;kDACR,KAAK;GACpD,CAAC;IACF,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,IAAI,CAAC;IAErD,MAAM,EAAE,KAAK,EAAE,SAAS,EAAE,GAAG,IAAA,uCAAoB,GAAE,CAAC;IACpD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,EAAE,CAAC;IACxB,MAAM,EAAE,CAAA;;cAEI,IAAA,eAAM,GAAE,KAAK,IAAI,CAAC,EAAE,KAAK,SAAS,KAAK,IAAI,IAAI,CAAC,GAAG,GAAG,YAAY,CAAC;GAC9E,CAAC;IACF,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC;AACpC,CAAC;AAED;;;GAGG;AACI,KAAK,UAAU,aAAa,CACjC,EAAM,EACN,KAAa,EACb,WAAmB,EACnB,QAAe,UAAU;IAEzB,IAAI,WAAW,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,KAAK,CAAC;IACzC,MAAM,EAAE,GAAG,IAAA,4BAAS,EAAC,KAAK,CAAC,CAAC;IAC5B,MAAM,IAAI,GAAG,MAAM,EAAE,CAAmC;;yBAEjC,EAAE,yCAAyC,IAAI,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;GACtF,CAAC;IACF,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACtB,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IAEzB,MAAM,EAAE,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,EAAE,EAAE;QAC1B,MAAM,EAAE,CAAA;;gBAEI,KAAK,CAAC,OAAO,KAAK,IAAA,0BAAY,EAAC,WAAW,CAAC;;;KAGtD,CAAC;QACF,MAAM,EAAE,CAAA,wDAAwD,KAAK,CAAC,EAAE,EAAE,CAAC;QAC3E,iDAAiD;QACjD,MAAM,EAAE,CAAA,8DAA8D,KAAK,CAAC,OAAO,yBAAyB,CAAC;IAC/G,CAAC,CAAC,CAAC;IACH,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.hashPassword = hashPassword;
|
|
4
|
+
exports.verifyPassword = verifyPassword;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
// scrypt (nativo do Node, sem dependência). Parâmetros dentro do maxmem padrão.
|
|
7
|
+
const N = 16384;
|
|
8
|
+
const R = 8;
|
|
9
|
+
const P = 1;
|
|
10
|
+
const KEYLEN = 64;
|
|
11
|
+
/** Deriva um hash scrypt com salt aleatório, no formato `scrypt$N$r$p$salt$hash`. */
|
|
12
|
+
function hashPassword(password) {
|
|
13
|
+
const salt = (0, node_crypto_1.randomBytes)(16);
|
|
14
|
+
const derived = (0, node_crypto_1.scryptSync)(password, salt, KEYLEN, { N, r: R, p: P });
|
|
15
|
+
return ['scrypt', N, R, P, salt.toString('base64'), derived.toString('base64')].join('$');
|
|
16
|
+
}
|
|
17
|
+
/** Verifica uma senha contra o hash armazenado, em tempo constante. */
|
|
18
|
+
function verifyPassword(password, stored) {
|
|
19
|
+
const parts = stored.split('$');
|
|
20
|
+
if (parts.length !== 6 || parts[0] !== 'scrypt')
|
|
21
|
+
return false;
|
|
22
|
+
const [, n, r, p, saltB64, hashB64] = parts;
|
|
23
|
+
const salt = Buffer.from(saltB64, 'base64');
|
|
24
|
+
const expected = Buffer.from(hashB64, 'base64');
|
|
25
|
+
const derived = (0, node_crypto_1.scryptSync)(password, salt, expected.length, {
|
|
26
|
+
N: Number(n),
|
|
27
|
+
r: Number(r),
|
|
28
|
+
p: Number(p),
|
|
29
|
+
});
|
|
30
|
+
return derived.length === expected.length && (0, node_crypto_1.timingSafeEqual)(derived, expected);
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=password.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/auth/password.ts"],"names":[],"mappings":";;AASA,oCAIC;AAGD,wCAYC;AA5BD,6CAAuE;AAEvE,gFAAgF;AAChF,MAAM,CAAC,GAAG,KAAK,CAAC;AAChB,MAAM,CAAC,GAAG,CAAC,CAAC;AACZ,MAAM,CAAC,GAAG,CAAC,CAAC;AACZ,MAAM,MAAM,GAAG,EAAE,CAAC;AAElB,qFAAqF;AACrF,SAAgB,YAAY,CAAC,QAAgB;IAC3C,MAAM,IAAI,GAAG,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC;IAC7B,MAAM,OAAO,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACtE,OAAO,CAAC,QAAQ,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5F,CAAC;AAED,uEAAuE;AACvE,SAAgB,cAAc,CAAC,QAAgB,EAAE,MAAc;IAC7D,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC9D,MAAM,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IAC5C,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,OAAQ,EAAE,QAAQ,CAAC,CAAC;IAC7C,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAQ,EAAE,QAAQ,CAAC,CAAC;IACjD,MAAM,OAAO,GAAG,IAAA,wBAAU,EAAC,QAAQ,EAAE,IAAI,EAAE,QAAQ,CAAC,MAAM,EAAE;QAC1D,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACZ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;QACZ,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;KACb,CAAC,CAAC;IACH,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,CAAC,MAAM,IAAI,IAAA,6BAAe,EAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;AAClF,CAAC"}
|
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.upsertUserWithPassword = upsertUserWithPassword;
|
|
4
|
+
exports.login = login;
|
|
5
|
+
exports.listMemberships = listMemberships;
|
|
6
|
+
exports.selectTenant = selectTenant;
|
|
7
|
+
exports.authenticate = authenticate;
|
|
8
|
+
exports.sessionMemberships = sessionMemberships;
|
|
9
|
+
exports.sessionProducts = sessionProducts;
|
|
10
|
+
exports.logout = logout;
|
|
11
|
+
const shared_1 = require("@baruk/shared");
|
|
12
|
+
const context_js_1 = require("../db/context.js");
|
|
13
|
+
const audit_js_1 = require("../audit/audit.js");
|
|
14
|
+
const authorize_js_1 = require("../rbac/authorize.js");
|
|
15
|
+
const repository_js_1 = require("../portal/repository.js");
|
|
16
|
+
const repository_js_2 = require("../products/repository.js");
|
|
17
|
+
const password_js_1 = require("./password.js");
|
|
18
|
+
const session_token_js_1 = require("./session-token.js");
|
|
19
|
+
const SESSION_TTL_MS = 12 * 60 * 60 * 1000; // 12h
|
|
20
|
+
const REAL_CLOCK = { now: () => Date.now() };
|
|
21
|
+
/** Cria (ou atualiza) um usuário staff com senha local. Usado pelo seed. */
|
|
22
|
+
async function upsertUserWithPassword(db, input) {
|
|
23
|
+
const rows = await db `
|
|
24
|
+
INSERT INTO "user" (id, email, full_name, user_type, auth_provider)
|
|
25
|
+
VALUES (${(0, shared_1.uuidv7)()}, ${input.email}, ${input.fullName}, ${input.userType ?? 'staff'}, 'password')
|
|
26
|
+
ON CONFLICT (email) WHERE deleted_at IS NULL
|
|
27
|
+
DO UPDATE SET full_name = EXCLUDED.full_name, updated_at = now()
|
|
28
|
+
RETURNING id
|
|
29
|
+
`;
|
|
30
|
+
const userId = rows[0].id;
|
|
31
|
+
await db `
|
|
32
|
+
INSERT INTO user_credential (user_id, password_hash)
|
|
33
|
+
VALUES (${userId}, ${(0, password_js_1.hashPassword)(input.password)})
|
|
34
|
+
ON CONFLICT (user_id) DO UPDATE SET password_hash = EXCLUDED.password_hash, updated_at = now()
|
|
35
|
+
`;
|
|
36
|
+
return {
|
|
37
|
+
id: userId,
|
|
38
|
+
email: input.email,
|
|
39
|
+
fullName: input.fullName,
|
|
40
|
+
userType: input.userType ?? 'staff',
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/** Login com e-mail/senha. Emite sessão; auto-seleciona tenant se houver só um. */
|
|
44
|
+
async function login(db, input, clock = REAL_CLOCK) {
|
|
45
|
+
const users = await db `
|
|
46
|
+
SELECT id, email, full_name, user_type, status
|
|
47
|
+
FROM "user" WHERE email = ${input.email} AND deleted_at IS NULL
|
|
48
|
+
`;
|
|
49
|
+
const user = users[0];
|
|
50
|
+
if (!user || user.status !== 'active') {
|
|
51
|
+
throw new shared_1.UnauthorizedError('Credenciais inválidas');
|
|
52
|
+
}
|
|
53
|
+
const creds = await db `
|
|
54
|
+
SELECT password_hash FROM user_credential WHERE user_id = ${user.id}
|
|
55
|
+
`;
|
|
56
|
+
if (!creds[0] || !(0, password_js_1.verifyPassword)(input.password, creds[0].password_hash)) {
|
|
57
|
+
throw new shared_1.UnauthorizedError('Credenciais inválidas');
|
|
58
|
+
}
|
|
59
|
+
const { token, tokenHash } = (0, session_token_js_1.generateSessionToken)();
|
|
60
|
+
const now = clock.now();
|
|
61
|
+
const sessionId = (0, shared_1.uuidv7)();
|
|
62
|
+
const expiresAt = new Date(now + SESSION_TTL_MS);
|
|
63
|
+
await db `
|
|
64
|
+
INSERT INTO user_session (id, user_id, token_hash, active_tenant_id, expires_at)
|
|
65
|
+
VALUES (${sessionId}, ${user.id}, ${tokenHash}, NULL, ${expiresAt})
|
|
66
|
+
`;
|
|
67
|
+
await db `UPDATE "user" SET last_login_at = ${new Date(now)} WHERE id = ${user.id}`;
|
|
68
|
+
const memberships = await listMemberships(db, user.id);
|
|
69
|
+
let activeTenantId = null;
|
|
70
|
+
if (memberships.length === 1) {
|
|
71
|
+
activeTenantId = memberships[0].tenantId;
|
|
72
|
+
await db `UPDATE user_session SET active_tenant_id = ${activeTenantId} WHERE id = ${sessionId}`;
|
|
73
|
+
await auditWithinTenant(db, activeTenantId, user.id, {
|
|
74
|
+
action: 'login',
|
|
75
|
+
resourceType: 'user_session',
|
|
76
|
+
resourceId: sessionId,
|
|
77
|
+
ip: input.ip,
|
|
78
|
+
userAgent: input.userAgent,
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
token,
|
|
83
|
+
user: { id: user.id, email: user.email, fullName: user.full_name, userType: user.user_type },
|
|
84
|
+
memberships,
|
|
85
|
+
activeTenantId,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/** Lista os tenants a que o usuário pertence (usa RLS self-clause de membership). */
|
|
89
|
+
async function listMemberships(db, userId) {
|
|
90
|
+
return (0, context_js_1.withContext)(db, { userId }, async (tx) => {
|
|
91
|
+
const rows = await tx `
|
|
92
|
+
SELECT m.tenant_id, t.code, t.display_name, m.status
|
|
93
|
+
FROM membership m
|
|
94
|
+
JOIN tenant t ON t.id = m.tenant_id
|
|
95
|
+
WHERE m.user_id = ${userId} AND m.deleted_at IS NULL AND m.status = 'active'
|
|
96
|
+
ORDER BY t.display_name
|
|
97
|
+
`;
|
|
98
|
+
return rows.map((r) => ({
|
|
99
|
+
tenantId: r.tenant_id,
|
|
100
|
+
tenantCode: r.code,
|
|
101
|
+
tenantName: r.display_name,
|
|
102
|
+
status: r.status,
|
|
103
|
+
}));
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
/** Escolhe/troca o tenant ativo de uma sessão, validando a membership. */
|
|
107
|
+
async function selectTenant(db, input) {
|
|
108
|
+
const session = await resolveSessionRow(db, input.token);
|
|
109
|
+
const memberships = await listMemberships(db, session.user_id);
|
|
110
|
+
const allowed = memberships.some((m) => m.tenantId === input.tenantId);
|
|
111
|
+
if (!allowed) {
|
|
112
|
+
throw new shared_1.ForbiddenError('Usuário não pertence a este tenant');
|
|
113
|
+
}
|
|
114
|
+
await db `
|
|
115
|
+
UPDATE user_session SET active_tenant_id = ${input.tenantId} WHERE id = ${session.id}
|
|
116
|
+
`;
|
|
117
|
+
return (0, context_js_1.withContext)(db, { tenantId: input.tenantId, userId: session.user_id }, async (tx) => {
|
|
118
|
+
const permissions = await (0, authorize_js_1.loadUserPermissions)(tx, session.user_id);
|
|
119
|
+
await (0, audit_js_1.appendAudit)(tx, {
|
|
120
|
+
actorId: session.user_id,
|
|
121
|
+
action: 'select_tenant',
|
|
122
|
+
resourceType: 'tenant',
|
|
123
|
+
resourceId: input.tenantId,
|
|
124
|
+
ip: input.ip,
|
|
125
|
+
userAgent: input.userAgent,
|
|
126
|
+
});
|
|
127
|
+
return {
|
|
128
|
+
userId: session.user_id,
|
|
129
|
+
userType: session.user_type,
|
|
130
|
+
tenantId: input.tenantId,
|
|
131
|
+
permissions,
|
|
132
|
+
};
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Resolve uma sessão ativa em contexto autenticado (o que o middleware da API
|
|
137
|
+
* chama por request). Exige tenant ativo já selecionado.
|
|
138
|
+
*/
|
|
139
|
+
async function authenticate(db, token, clock = REAL_CLOCK) {
|
|
140
|
+
const session = await resolveSessionRow(db, token, clock);
|
|
141
|
+
if (!session.active_tenant_id) {
|
|
142
|
+
throw new shared_1.UnauthorizedError('Nenhum tenant selecionado para esta sessão');
|
|
143
|
+
}
|
|
144
|
+
const tenantId = session.active_tenant_id;
|
|
145
|
+
return (0, context_js_1.withContext)(db, { tenantId, userId: session.user_id }, async (tx) => {
|
|
146
|
+
const permissions = await (0, authorize_js_1.loadUserPermissions)(tx, session.user_id);
|
|
147
|
+
const ctx = {
|
|
148
|
+
userId: session.user_id,
|
|
149
|
+
userType: session.user_type,
|
|
150
|
+
tenantId,
|
|
151
|
+
permissions,
|
|
152
|
+
};
|
|
153
|
+
if (session.user_type === 'client_portal') {
|
|
154
|
+
ctx.clientId = await (0, repository_js_1.getPortalClientId)(tx, session.user_id);
|
|
155
|
+
}
|
|
156
|
+
return ctx;
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
async function resolveSessionRow(db, token, clock = REAL_CLOCK) {
|
|
160
|
+
const rows = await db `
|
|
161
|
+
SELECT s.id, s.user_id, u.user_type, s.active_tenant_id
|
|
162
|
+
FROM user_session s
|
|
163
|
+
JOIN "user" u ON u.id = s.user_id
|
|
164
|
+
WHERE s.token_hash = ${(0, session_token_js_1.hashToken)(token)}
|
|
165
|
+
AND s.revoked_at IS NULL
|
|
166
|
+
AND s.expires_at > ${new Date(clock.now())}
|
|
167
|
+
AND u.deleted_at IS NULL
|
|
168
|
+
`;
|
|
169
|
+
if (!rows[0])
|
|
170
|
+
throw new shared_1.UnauthorizedError('Sessão inválida ou expirada');
|
|
171
|
+
return rows[0];
|
|
172
|
+
}
|
|
173
|
+
/** Memberships da sessão atual (para o seletor de tenant, antes de escolher um). */
|
|
174
|
+
async function sessionMemberships(db, token) {
|
|
175
|
+
const session = await resolveSessionRow(db, token);
|
|
176
|
+
return listMemberships(db, session.user_id);
|
|
177
|
+
}
|
|
178
|
+
/** Produtos que a sessão pode acessar (entitlements) + audiência. Roteamento do Hub. */
|
|
179
|
+
async function sessionProducts(db, token) {
|
|
180
|
+
const session = await resolveSessionRow(db, token);
|
|
181
|
+
const products = await (0, context_js_1.withContext)(db, { userId: session.user_id }, (tx) => (0, repository_js_2.listProductsForUser)(tx, session.user_id));
|
|
182
|
+
return { userType: session.user_type, products };
|
|
183
|
+
}
|
|
184
|
+
/** Revoga a sessão (logout). */
|
|
185
|
+
async function logout(db, token) {
|
|
186
|
+
await db `UPDATE user_session SET revoked_at = now() WHERE token_hash = ${(0, session_token_js_1.hashToken)(token)}`;
|
|
187
|
+
}
|
|
188
|
+
async function auditWithinTenant(db, tenantId, actorId, entry) {
|
|
189
|
+
await (0, context_js_1.withContext)(db, { tenantId, userId: actorId }, (tx) => (0, audit_js_1.appendAudit)(tx, entry));
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../../src/auth/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateSessionToken = generateSessionToken;
|
|
4
|
+
exports.hashToken = hashToken;
|
|
5
|
+
const node_crypto_1 = require("node:crypto");
|
|
6
|
+
/**
|
|
7
|
+
* Sessão opaca: o cliente recebe um token aleatório; o banco guarda apenas o
|
|
8
|
+
* hash SHA-256 (nunca o token em claro). Resolver a sessão = hashear o token
|
|
9
|
+
* recebido e buscar por igualdade.
|
|
10
|
+
*/
|
|
11
|
+
function generateSessionToken() {
|
|
12
|
+
const token = (0, node_crypto_1.randomBytes)(32).toString('base64url');
|
|
13
|
+
return { token, tokenHash: hashToken(token) };
|
|
14
|
+
}
|
|
15
|
+
function hashToken(token) {
|
|
16
|
+
return (0, node_crypto_1.createHash)('sha256').update(token).digest('hex');
|
|
17
|
+
}
|
|
18
|
+
//# sourceMappingURL=session-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session-token.js","sourceRoot":"","sources":["../../../src/auth/session-token.ts"],"names":[],"mappings":";;AAOA,oDAGC;AAED,8BAEC;AAdD,6CAAsD;AAEtD;;;;GAIG;AACH,SAAgB,oBAAoB;IAClC,MAAM,KAAK,GAAG,IAAA,yBAAW,EAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,WAAW,CAAC,CAAC;IACpD,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;AAChD,CAAC;AAED,SAAgB,SAAS,CAAC,KAAa;IACrC,OAAO,IAAA,wBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Motor de régua de inadimplência (dunning) — PURO e determinístico. Não envia
|
|
4
|
+
* nada: apenas decide QUAIS passos estão vencidos para uma cobrança numa data de
|
|
5
|
+
* referência. O disparo efetivo (WhatsApp/Email/Notificação) é responsabilidade
|
|
6
|
+
* do Communication/Automation Engine — o Billing só define a política. Assim a
|
|
7
|
+
* régua é 100% testável sem I/O e pronta para rodar num cron/queue.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.DEFAULT_DUNNING_STEPS = void 0;
|
|
11
|
+
exports.stepKey = stepKey;
|
|
12
|
+
exports.dueDunningSteps = dueDunningSteps;
|
|
13
|
+
/** Régua padrão de contabilidade: lembrete antes + escalonamento após o vencimento. */
|
|
14
|
+
exports.DEFAULT_DUNNING_STEPS = [
|
|
15
|
+
{ offsetDays: -3, channel: 'whatsapp', template: 'lembrete_previo' },
|
|
16
|
+
{ offsetDays: 0, channel: 'whatsapp', template: 'vencimento_hoje' },
|
|
17
|
+
{ offsetDays: 3, channel: 'whatsapp', template: 'atraso_3d' },
|
|
18
|
+
{ offsetDays: 7, channel: 'email', template: 'atraso_7d' },
|
|
19
|
+
{ offsetDays: 15, channel: 'email', template: 'atraso_15d' },
|
|
20
|
+
{ offsetDays: 30, channel: 'whatsapp', template: 'atraso_30d' },
|
|
21
|
+
{ offsetDays: 60, channel: 'email', template: 'atraso_60d' },
|
|
22
|
+
{ offsetDays: 90, channel: 'notification', template: 'atraso_90d' },
|
|
23
|
+
];
|
|
24
|
+
function stepKey(step) {
|
|
25
|
+
const tag = step.offsetDays === 0 ? 'D0' : step.offsetDays > 0 ? `D+${step.offsetDays}` : `D${step.offsetDays}`;
|
|
26
|
+
return `${tag}:${step.channel}`;
|
|
27
|
+
}
|
|
28
|
+
function addDays(isoDate, days) {
|
|
29
|
+
const d = new Date(`${isoDate}T00:00:00Z`);
|
|
30
|
+
d.setUTCDate(d.getUTCDate() + days);
|
|
31
|
+
return d.toISOString().slice(0, 10);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Retorna os passos VENCIDOS (data agendada <= hoje) ainda não executados, para
|
|
35
|
+
* uma cobrança em aberto. `today` e `executed` são injetados (determinismo).
|
|
36
|
+
*/
|
|
37
|
+
function dueDunningSteps(steps, charge, today, executed = new Set()) {
|
|
38
|
+
if (!charge.dueDate)
|
|
39
|
+
return [];
|
|
40
|
+
if (charge.status === 'paid' || charge.status === 'canceled' || charge.status === 'refunded')
|
|
41
|
+
return [];
|
|
42
|
+
const due = [];
|
|
43
|
+
for (const step of steps) {
|
|
44
|
+
const key = stepKey(step);
|
|
45
|
+
if (executed.has(key))
|
|
46
|
+
continue;
|
|
47
|
+
const scheduledFor = addDays(charge.dueDate, step.offsetDays);
|
|
48
|
+
if (scheduledFor <= today) {
|
|
49
|
+
due.push({ ...step, stepKey: key, scheduledFor });
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return due.sort((a, b) => a.scheduledFor.localeCompare(b.scheduledFor));
|
|
53
|
+
}
|
|
54
|
+
//# sourceMappingURL=dunning.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dunning.js","sourceRoot":"","sources":["../../../src/billing/dunning.ts"],"names":[],"mappings":";AAAA;;;;;;GAMG;;;AA8BH,0BAGC;AAiBD,0CAmBC;AAnDD,uFAAuF;AAC1E,QAAA,qBAAqB,GAA2B;IAC3D,EAAE,UAAU,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE;IACpE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,iBAAiB,EAAE;IACnE,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE;IAC7D,EAAE,UAAU,EAAE,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE;IAC1D,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE;IAC5D,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,YAAY,EAAE;IAC/D,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE;IAC5D,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE,QAAQ,EAAE,YAAY,EAAE;CACpE,CAAC;AAEF,SAAgB,OAAO,CAAC,IAAiB;IACvC,MAAM,GAAG,GAAG,IAAI,CAAC,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;IAChH,OAAO,GAAG,GAAG,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;AAClC,CAAC;AAED,SAAS,OAAO,CAAC,OAAe,EAAE,IAAY;IAC5C,MAAM,CAAC,GAAG,IAAI,IAAI,CAAC,GAAG,OAAO,YAAY,CAAC,CAAC;IAC3C,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,UAAU,EAAE,GAAG,IAAI,CAAC,CAAC;IACpC,OAAO,CAAC,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AACtC,CAAC;AAOD;;;GAGG;AACH,SAAgB,eAAe,CAC7B,KAA6B,EAC7B,MAAyB,EACzB,KAAa,EACb,WAAgC,IAAI,GAAG,EAAE;IAEzC,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAC/B,IAAI,MAAM,CAAC,MAAM,KAAK,MAAM,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU;QAAE,OAAO,EAAE,CAAC;IAExG,MAAM,GAAG,GAAqB,EAAE,CAAC;IACjC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,GAAG,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QAC1B,IAAI,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC;YAAE,SAAS;QAChC,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,CAAC,UAAU,CAAC,CAAC;QAC9D,IAAI,YAAY,IAAI,KAAK,EAAE,CAAC;YAC1B,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;QACpD,CAAC;IACH,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC;AAC1E,CAAC"}
|