@baruk/core 0.4.2 → 0.5.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/.baruk-provenance.json +4 -4
- package/CHANGELOG.md +42 -0
- package/dist/audit/repository.d.ts +33 -1
- package/dist/audit/repository.d.ts.map +1 -1
- package/dist/audit/repository.js +41 -7
- package/dist/audit/repository.js.map +1 -1
- package/dist/auth/service.d.ts +21 -0
- package/dist/auth/service.d.ts.map +1 -1
- package/dist/auth/service.js +46 -1
- package/dist/auth/service.js.map +1 -1
- package/dist/billing/ar-repository.d.ts +41 -1
- package/dist/billing/ar-repository.d.ts.map +1 -1
- package/dist/billing/ar-repository.js +82 -6
- package/dist/billing/ar-repository.js.map +1 -1
- package/dist/billing/provider-account.d.ts +38 -0
- package/dist/billing/provider-account.d.ts.map +1 -1
- package/dist/billing/provider-account.js +58 -2
- package/dist/billing/provider-account.js.map +1 -1
- package/dist/billing/repository.d.ts +44 -0
- package/dist/billing/repository.d.ts.map +1 -1
- package/dist/billing/repository.js +49 -5
- package/dist/billing/repository.js.map +1 -1
- package/dist/cjs/audit/repository.js +41 -7
- package/dist/cjs/audit/repository.js.map +1 -1
- package/dist/cjs/auth/service.js +46 -1
- package/dist/cjs/auth/service.js.map +1 -1
- package/dist/cjs/billing/ar-repository.js +82 -6
- package/dist/cjs/billing/ar-repository.js.map +1 -1
- package/dist/cjs/billing/provider-account.js +60 -1
- package/dist/cjs/billing/provider-account.js.map +1 -1
- package/dist/cjs/billing/repository.js +51 -5
- package/dist/cjs/billing/repository.js.map +1 -1
- package/dist/cjs/clients/ibge.js +103 -0
- package/dist/cjs/clients/ibge.js.map +1 -0
- package/dist/cjs/clients/repository.js +186 -9
- package/dist/cjs/clients/repository.js.map +1 -1
- package/dist/cjs/collection/branding.js +190 -0
- package/dist/cjs/collection/branding.js.map +1 -1
- package/dist/cjs/collection/clearance-store.js +74 -0
- package/dist/cjs/collection/clearance-store.js.map +1 -0
- package/dist/cjs/collection/communication-runtime.js +65 -2
- package/dist/cjs/collection/communication-runtime.js.map +1 -1
- package/dist/cjs/collection/engine.js +20 -0
- package/dist/cjs/collection/engine.js.map +1 -1
- package/dist/cjs/collection/policy.js +29 -1
- package/dist/cjs/collection/policy.js.map +1 -1
- package/dist/cjs/communication/clearance.js +18 -0
- package/dist/cjs/communication/clearance.js.map +1 -0
- package/dist/cjs/communication/dry-run-scenario.js +5 -0
- package/dist/cjs/communication/dry-run-scenario.js.map +1 -1
- package/dist/cjs/communication/engine.js +12 -0
- package/dist/cjs/communication/engine.js.map +1 -1
- package/dist/cjs/communication/policy.js.map +1 -1
- package/dist/cjs/competence/business-days.js +155 -0
- package/dist/cjs/competence/business-days.js.map +1 -0
- package/dist/cjs/competence/catalog-validation.js +174 -0
- package/dist/cjs/competence/catalog-validation.js.map +1 -0
- package/dist/cjs/competence/obligation-preview.js +190 -0
- package/dist/cjs/competence/obligation-preview.js.map +1 -0
- package/dist/cjs/competence/repository.js +330 -17
- package/dist/cjs/competence/repository.js.map +1 -1
- package/dist/cjs/dashboard/pilot-panel.js +90 -0
- package/dist/cjs/dashboard/pilot-panel.js.map +1 -0
- package/dist/cjs/dashboard/repository.js +11 -1
- package/dist/cjs/dashboard/repository.js.map +1 -1
- package/dist/cjs/db/client.js +17 -11
- package/dist/cjs/db/client.js.map +1 -1
- package/dist/cjs/db/provision-e2e-identity.js +111 -0
- package/dist/cjs/db/provision-e2e-identity.js.map +1 -0
- package/dist/cjs/fiscal/applicability.js +164 -0
- package/dist/cjs/fiscal/applicability.js.map +1 -0
- package/dist/cjs/fiscal/conditions.js +198 -0
- package/dist/cjs/fiscal/conditions.js.map +1 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-contract.js +390 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-contract.js.map +1 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js +108 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js +220 -0
- package/dist/cjs/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
- package/dist/cjs/fiscal/coverage/model.js +127 -0
- package/dist/cjs/fiscal/coverage/model.js.map +1 -0
- package/dist/cjs/fiscal/coverage/requests.js +99 -0
- package/dist/cjs/fiscal/coverage/requests.js.map +1 -0
- package/dist/cjs/fiscal/credentials/material.js +168 -0
- package/dist/cjs/fiscal/credentials/material.js.map +1 -0
- package/dist/cjs/fiscal/credentials/readiness.js +163 -0
- package/dist/cjs/fiscal/credentials/readiness.js.map +1 -0
- package/dist/cjs/fiscal/eligibility.js +199 -0
- package/dist/cjs/fiscal/eligibility.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js +128 -0
- package/dist/cjs/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/adn-transport.js +229 -0
- package/dist/cjs/fiscal/ingestion/adn-transport.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/direction.js +36 -0
- package/dist/cjs/fiscal/ingestion/direction.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/nfse-adn.js +228 -0
- package/dist/cjs/fiscal/ingestion/nfse-adn.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/pipeline.js +704 -0
- package/dist/cjs/fiscal/ingestion/pipeline.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/provider.js +51 -0
- package/dist/cjs/fiscal/ingestion/provider.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/repository.js +132 -0
- package/dist/cjs/fiscal/ingestion/repository.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/synthetic-provider.js +103 -0
- package/dist/cjs/fiscal/ingestion/synthetic-provider.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js +13 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport.js +61 -0
- package/dist/cjs/fiscal/ingestion/synthetic-transport.js.map +1 -0
- package/dist/cjs/fiscal/ingestion/xml-reader.js +121 -0
- package/dist/cjs/fiscal/ingestion/xml-reader.js.map +1 -0
- package/dist/cjs/fiscal/repository.js +470 -0
- package/dist/cjs/fiscal/repository.js.map +1 -0
- package/dist/cjs/fiscal/sync/circuit.js +124 -0
- package/dist/cjs/fiscal/sync/circuit.js.map +1 -0
- package/dist/cjs/fiscal/sync/intervention.js +140 -0
- package/dist/cjs/fiscal/sync/intervention.js.map +1 -0
- package/dist/cjs/fiscal/sync/lease.js +146 -0
- package/dist/cjs/fiscal/sync/lease.js.map +1 -0
- package/dist/cjs/fiscal/sync/observability.js +244 -0
- package/dist/cjs/fiscal/sync/observability.js.map +1 -0
- package/dist/cjs/fiscal/sync/orchestrator.js +490 -0
- package/dist/cjs/fiscal/sync/orchestrator.js.map +1 -0
- package/dist/cjs/fiscal/sync/policy.js +143 -0
- package/dist/cjs/fiscal/sync/policy.js.map +1 -0
- package/dist/cjs/fiscal/sync/reprocess.js +241 -0
- package/dist/cjs/fiscal/sync/reprocess.js.map +1 -0
- package/dist/cjs/fiscal/sync/retry.js +183 -0
- package/dist/cjs/fiscal/sync/retry.js.map +1 -0
- package/dist/cjs/fiscal/sync/secret-boundary.js +123 -0
- package/dist/cjs/fiscal/sync/secret-boundary.js.map +1 -0
- package/dist/cjs/fiscal/transport/https.js +309 -0
- package/dist/cjs/fiscal/transport/https.js.map +1 -0
- package/dist/cjs/fiscal/transport/synthetic-tls.js +328 -0
- package/dist/cjs/fiscal/transport/synthetic-tls.js.map +1 -0
- package/dist/cjs/fiscal/transport/types.js +93 -0
- package/dist/cjs/fiscal/transport/types.js.map +1 -0
- package/dist/cjs/import/br-documents.js +85 -0
- package/dist/cjs/import/br-documents.js.map +1 -0
- package/dist/cjs/import/clients-import.js +347 -40
- package/dist/cjs/import/clients-import.js.map +1 -1
- package/dist/cjs/index.js +316 -11
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/legal/documents.js +100 -15
- package/dist/cjs/legal/documents.js.map +1 -1
- package/dist/cjs/legal/index.js +3 -1
- package/dist/cjs/legal/index.js.map +1 -1
- package/dist/cjs/legal/types.js.map +1 -1
- package/dist/cjs/onboarding/persistence.js +4 -4
- package/dist/cjs/onboarding/persistence.js.map +1 -1
- package/dist/cjs/pilot/go-live-checklist.js +212 -0
- package/dist/cjs/pilot/go-live-checklist.js.map +1 -0
- package/dist/cjs/pilot/milestone.js +79 -0
- package/dist/cjs/pilot/milestone.js.map +1 -0
- package/dist/cjs/platform/capabilities.js +144 -0
- package/dist/cjs/platform/capabilities.js.map +1 -0
- package/dist/cjs/platform/job-contract.js +411 -0
- package/dist/cjs/platform/job-contract.js.map +1 -0
- package/dist/cjs/rbac/catalog.js +34 -0
- package/dist/cjs/rbac/catalog.js.map +1 -1
- package/dist/cjs/subscription-billing/index.js +2 -1
- package/dist/cjs/subscription-billing/index.js.map +1 -1
- package/dist/cjs/subscription-billing/service.js +153 -77
- package/dist/cjs/subscription-billing/service.js.map +1 -1
- package/dist/cjs/tenancy/features.js +131 -0
- package/dist/cjs/tenancy/features.js.map +1 -0
- package/dist/cjs/tenancy/settings.js +224 -0
- package/dist/cjs/tenancy/settings.js.map +1 -0
- package/dist/cjs/users/repository.js +24 -1
- package/dist/cjs/users/repository.js.map +1 -1
- package/dist/clients/ibge.d.ts +17 -0
- package/dist/clients/ibge.d.ts.map +1 -0
- package/dist/clients/ibge.js +98 -0
- package/dist/clients/ibge.js.map +1 -0
- package/dist/clients/repository.d.ts +154 -0
- package/dist/clients/repository.d.ts.map +1 -1
- package/dist/clients/repository.js +182 -9
- package/dist/clients/repository.js.map +1 -1
- package/dist/collection/branding.d.ts +65 -0
- package/dist/collection/branding.d.ts.map +1 -1
- package/dist/collection/branding.js +186 -0
- package/dist/collection/branding.js.map +1 -1
- package/dist/collection/clearance-store.d.ts +39 -0
- package/dist/collection/clearance-store.d.ts.map +1 -0
- package/dist/collection/clearance-store.js +69 -0
- package/dist/collection/clearance-store.js.map +1 -0
- package/dist/collection/communication-runtime.d.ts +37 -0
- package/dist/collection/communication-runtime.d.ts.map +1 -1
- package/dist/collection/communication-runtime.js +63 -1
- package/dist/collection/communication-runtime.js.map +1 -1
- package/dist/collection/engine.d.ts +23 -0
- package/dist/collection/engine.d.ts.map +1 -1
- package/dist/collection/engine.js +20 -0
- package/dist/collection/engine.js.map +1 -1
- package/dist/collection/policy.d.ts +25 -0
- package/dist/collection/policy.d.ts.map +1 -1
- package/dist/collection/policy.js +27 -0
- package/dist/collection/policy.js.map +1 -1
- package/dist/communication/clearance.d.ts +53 -0
- package/dist/communication/clearance.d.ts.map +1 -0
- package/dist/communication/clearance.js +15 -0
- package/dist/communication/clearance.js.map +1 -0
- package/dist/communication/dry-run-scenario.d.ts.map +1 -1
- package/dist/communication/dry-run-scenario.js +5 -0
- package/dist/communication/dry-run-scenario.js.map +1 -1
- package/dist/communication/engine.d.ts +10 -0
- package/dist/communication/engine.d.ts.map +1 -1
- package/dist/communication/engine.js +12 -0
- package/dist/communication/engine.js.map +1 -1
- package/dist/communication/policy.d.ts +16 -0
- package/dist/communication/policy.d.ts.map +1 -1
- package/dist/communication/policy.js.map +1 -1
- package/dist/competence/business-days.d.ts +51 -0
- package/dist/competence/business-days.d.ts.map +1 -0
- package/dist/competence/business-days.js +145 -0
- package/dist/competence/business-days.js.map +1 -0
- package/dist/competence/catalog-validation.d.ts +86 -0
- package/dist/competence/catalog-validation.d.ts.map +1 -0
- package/dist/competence/catalog-validation.js +168 -0
- package/dist/competence/catalog-validation.js.map +1 -0
- package/dist/competence/obligation-preview.d.ts +103 -0
- package/dist/competence/obligation-preview.d.ts.map +1 -0
- package/dist/competence/obligation-preview.js +184 -0
- package/dist/competence/obligation-preview.js.map +1 -0
- package/dist/competence/repository.d.ts +139 -1
- package/dist/competence/repository.d.ts.map +1 -1
- package/dist/competence/repository.js +325 -17
- package/dist/competence/repository.js.map +1 -1
- package/dist/dashboard/pilot-panel.d.ts +100 -0
- package/dist/dashboard/pilot-panel.d.ts.map +1 -0
- package/dist/dashboard/pilot-panel.js +87 -0
- package/dist/dashboard/pilot-panel.js.map +1 -0
- package/dist/dashboard/repository.d.ts.map +1 -1
- package/dist/dashboard/repository.js +11 -1
- package/dist/dashboard/repository.js.map +1 -1
- package/dist/db/client.d.ts +45 -0
- package/dist/db/client.d.ts.map +1 -1
- package/dist/db/client.js +16 -11
- package/dist/db/client.js.map +1 -1
- package/dist/db/migrate.d.ts +36 -1
- package/dist/db/migrate.d.ts.map +1 -1
- package/dist/db/migrate.js +199 -32
- package/dist/db/migrate.js.map +1 -1
- package/dist/db/provision-e2e-identity.d.ts +2 -0
- package/dist/db/provision-e2e-identity.d.ts.map +1 -0
- package/dist/db/provision-e2e-identity.js +109 -0
- package/dist/db/provision-e2e-identity.js.map +1 -0
- package/dist/fiscal/applicability.d.ts +73 -0
- package/dist/fiscal/applicability.d.ts.map +1 -0
- package/dist/fiscal/applicability.js +160 -0
- package/dist/fiscal/applicability.js.map +1 -0
- package/dist/fiscal/conditions.d.ts +99 -0
- package/dist/fiscal/conditions.d.ts.map +1 -0
- package/dist/fiscal/conditions.js +190 -0
- package/dist/fiscal/conditions.js.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-contract.d.ts +315 -0
- package/dist/fiscal/contracts/nfse-adn-contract.d.ts.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-contract.js +386 -0
- package/dist/fiscal/contracts/nfse-adn-contract.js.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts +13 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.d.ts.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.js +103 -0
- package/dist/fiscal/contracts/nfse-adn-endpoint.js.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.d.ts +77 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.d.ts.map +1 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.js +215 -0
- package/dist/fiscal/contracts/nfse-adn-envelope.js.map +1 -0
- package/dist/fiscal/coverage/model.d.ts +86 -0
- package/dist/fiscal/coverage/model.d.ts.map +1 -0
- package/dist/fiscal/coverage/model.js +120 -0
- package/dist/fiscal/coverage/model.js.map +1 -0
- package/dist/fiscal/coverage/requests.d.ts +70 -0
- package/dist/fiscal/coverage/requests.d.ts.map +1 -0
- package/dist/fiscal/coverage/requests.js +95 -0
- package/dist/fiscal/coverage/requests.js.map +1 -0
- package/dist/fiscal/credentials/material.d.ts +81 -0
- package/dist/fiscal/credentials/material.d.ts.map +1 -0
- package/dist/fiscal/credentials/material.js +164 -0
- package/dist/fiscal/credentials/material.js.map +1 -0
- package/dist/fiscal/credentials/readiness.d.ts +92 -0
- package/dist/fiscal/credentials/readiness.d.ts.map +1 -0
- package/dist/fiscal/credentials/readiness.js +159 -0
- package/dist/fiscal/credentials/readiness.js.map +1 -0
- package/dist/fiscal/eligibility.d.ts +106 -0
- package/dist/fiscal/eligibility.d.ts.map +1 -0
- package/dist/fiscal/eligibility.js +194 -0
- package/dist/fiscal/eligibility.js.map +1 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts +57 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.d.ts.map +1 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.js +121 -0
- package/dist/fiscal/ingestion/__fixtures__/nfse.js.map +1 -0
- package/dist/fiscal/ingestion/adn-transport.d.ts +123 -0
- package/dist/fiscal/ingestion/adn-transport.d.ts.map +1 -0
- package/dist/fiscal/ingestion/adn-transport.js +220 -0
- package/dist/fiscal/ingestion/adn-transport.js.map +1 -0
- package/dist/fiscal/ingestion/direction.d.ts +60 -0
- package/dist/fiscal/ingestion/direction.d.ts.map +1 -0
- package/dist/fiscal/ingestion/direction.js +32 -0
- package/dist/fiscal/ingestion/direction.js.map +1 -0
- package/dist/fiscal/ingestion/nfse-adn.d.ts +91 -0
- package/dist/fiscal/ingestion/nfse-adn.d.ts.map +1 -0
- package/dist/fiscal/ingestion/nfse-adn.js +222 -0
- package/dist/fiscal/ingestion/nfse-adn.js.map +1 -0
- package/dist/fiscal/ingestion/pipeline.d.ts +168 -0
- package/dist/fiscal/ingestion/pipeline.d.ts.map +1 -0
- package/dist/fiscal/ingestion/pipeline.js +699 -0
- package/dist/fiscal/ingestion/pipeline.js.map +1 -0
- package/dist/fiscal/ingestion/provider.d.ts +206 -0
- package/dist/fiscal/ingestion/provider.d.ts.map +1 -0
- package/dist/fiscal/ingestion/provider.js +47 -0
- package/dist/fiscal/ingestion/provider.js.map +1 -0
- package/dist/fiscal/ingestion/repository.d.ts +82 -0
- package/dist/fiscal/ingestion/repository.d.ts.map +1 -0
- package/dist/fiscal/ingestion/repository.js +127 -0
- package/dist/fiscal/ingestion/repository.js.map +1 -0
- package/dist/fiscal/ingestion/synthetic-provider.d.ts +92 -0
- package/dist/fiscal/ingestion/synthetic-provider.d.ts.map +1 -0
- package/dist/fiscal/ingestion/synthetic-provider.js +99 -0
- package/dist/fiscal/ingestion/synthetic-provider.js.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.d.ts +19 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.d.ts.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.js +9 -0
- package/dist/fiscal/ingestion/synthetic-transport-types.js.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport.d.ts +55 -0
- package/dist/fiscal/ingestion/synthetic-transport.d.ts.map +1 -0
- package/dist/fiscal/ingestion/synthetic-transport.js +57 -0
- package/dist/fiscal/ingestion/synthetic-transport.js.map +1 -0
- package/dist/fiscal/ingestion/xml-reader.d.ts +55 -0
- package/dist/fiscal/ingestion/xml-reader.d.ts.map +1 -0
- package/dist/fiscal/ingestion/xml-reader.js +112 -0
- package/dist/fiscal/ingestion/xml-reader.js.map +1 -0
- package/dist/fiscal/repository.d.ts +220 -0
- package/dist/fiscal/repository.d.ts.map +1 -0
- package/dist/fiscal/repository.js +449 -0
- package/dist/fiscal/repository.js.map +1 -0
- package/dist/fiscal/sync/circuit.d.ts +86 -0
- package/dist/fiscal/sync/circuit.d.ts.map +1 -0
- package/dist/fiscal/sync/circuit.js +118 -0
- package/dist/fiscal/sync/circuit.js.map +1 -0
- package/dist/fiscal/sync/intervention.d.ts +81 -0
- package/dist/fiscal/sync/intervention.d.ts.map +1 -0
- package/dist/fiscal/sync/intervention.js +135 -0
- package/dist/fiscal/sync/intervention.js.map +1 -0
- package/dist/fiscal/sync/lease.d.ts +118 -0
- package/dist/fiscal/sync/lease.d.ts.map +1 -0
- package/dist/fiscal/sync/lease.js +139 -0
- package/dist/fiscal/sync/lease.js.map +1 -0
- package/dist/fiscal/sync/observability.d.ts +148 -0
- package/dist/fiscal/sync/observability.d.ts.map +1 -0
- package/dist/fiscal/sync/observability.js +239 -0
- package/dist/fiscal/sync/observability.js.map +1 -0
- package/dist/fiscal/sync/orchestrator.d.ts +132 -0
- package/dist/fiscal/sync/orchestrator.d.ts.map +1 -0
- package/dist/fiscal/sync/orchestrator.js +487 -0
- package/dist/fiscal/sync/orchestrator.js.map +1 -0
- package/dist/fiscal/sync/policy.d.ts +87 -0
- package/dist/fiscal/sync/policy.d.ts.map +1 -0
- package/dist/fiscal/sync/policy.js +136 -0
- package/dist/fiscal/sync/policy.js.map +1 -0
- package/dist/fiscal/sync/reprocess.d.ts +76 -0
- package/dist/fiscal/sync/reprocess.d.ts.map +1 -0
- package/dist/fiscal/sync/reprocess.js +237 -0
- package/dist/fiscal/sync/reprocess.js.map +1 -0
- package/dist/fiscal/sync/retry.d.ts +82 -0
- package/dist/fiscal/sync/retry.d.ts.map +1 -0
- package/dist/fiscal/sync/retry.js +176 -0
- package/dist/fiscal/sync/retry.js.map +1 -0
- package/dist/fiscal/sync/secret-boundary.d.ts +169 -0
- package/dist/fiscal/sync/secret-boundary.d.ts.map +1 -0
- package/dist/fiscal/sync/secret-boundary.js +116 -0
- package/dist/fiscal/sync/secret-boundary.js.map +1 -0
- package/dist/fiscal/transport/https.d.ts +86 -0
- package/dist/fiscal/transport/https.d.ts.map +1 -0
- package/dist/fiscal/transport/https.js +303 -0
- package/dist/fiscal/transport/https.js.map +1 -0
- package/dist/fiscal/transport/synthetic-tls.d.ts +80 -0
- package/dist/fiscal/transport/synthetic-tls.d.ts.map +1 -0
- package/dist/fiscal/transport/synthetic-tls.js +323 -0
- package/dist/fiscal/transport/synthetic-tls.js.map +1 -0
- package/dist/fiscal/transport/types.d.ts +134 -0
- package/dist/fiscal/transport/types.d.ts.map +1 -0
- package/dist/fiscal/transport/types.js +88 -0
- package/dist/fiscal/transport/types.js.map +1 -0
- package/dist/import/br-documents.d.ts +26 -0
- package/dist/import/br-documents.d.ts.map +1 -0
- package/dist/import/br-documents.js +78 -0
- package/dist/import/br-documents.js.map +1 -0
- package/dist/import/clients-import.d.ts +122 -4
- package/dist/import/clients-import.d.ts.map +1 -1
- package/dist/import/clients-import.js +341 -41
- package/dist/import/clients-import.js.map +1 -1
- package/dist/index.d.ts +115 -11
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +100 -7
- package/dist/index.js.map +1 -1
- package/dist/legal/documents.d.ts +12 -1
- package/dist/legal/documents.d.ts.map +1 -1
- package/dist/legal/documents.js +98 -14
- package/dist/legal/documents.js.map +1 -1
- package/dist/legal/index.d.ts +1 -1
- package/dist/legal/index.d.ts.map +1 -1
- package/dist/legal/index.js +1 -1
- package/dist/legal/index.js.map +1 -1
- package/dist/legal/types.d.ts +37 -2
- package/dist/legal/types.d.ts.map +1 -1
- package/dist/legal/types.js.map +1 -1
- package/dist/onboarding/persistence.d.ts +10 -1
- package/dist/onboarding/persistence.d.ts.map +1 -1
- package/dist/onboarding/persistence.js +4 -4
- package/dist/onboarding/persistence.js.map +1 -1
- package/dist/pilot/go-live-checklist.d.ts +41 -0
- package/dist/pilot/go-live-checklist.d.ts.map +1 -0
- package/dist/pilot/go-live-checklist.js +209 -0
- package/dist/pilot/go-live-checklist.js.map +1 -0
- package/dist/pilot/milestone.d.ts +56 -0
- package/dist/pilot/milestone.d.ts.map +1 -0
- package/dist/pilot/milestone.js +74 -0
- package/dist/pilot/milestone.js.map +1 -0
- package/dist/platform/capabilities.d.ts +88 -0
- package/dist/platform/capabilities.d.ts.map +1 -0
- package/dist/platform/capabilities.js +140 -0
- package/dist/platform/capabilities.js.map +1 -0
- package/dist/platform/job-contract.d.ts +232 -0
- package/dist/platform/job-contract.d.ts.map +1 -0
- package/dist/platform/job-contract.js +403 -0
- package/dist/platform/job-contract.js.map +1 -0
- package/dist/rbac/catalog.d.ts.map +1 -1
- package/dist/rbac/catalog.js +34 -0
- package/dist/rbac/catalog.js.map +1 -1
- package/dist/subscription-billing/index.d.ts +6 -5
- package/dist/subscription-billing/index.d.ts.map +1 -1
- package/dist/subscription-billing/index.js +3 -3
- package/dist/subscription-billing/index.js.map +1 -1
- package/dist/subscription-billing/service.d.ts +21 -0
- package/dist/subscription-billing/service.d.ts.map +1 -1
- package/dist/subscription-billing/service.js +90 -15
- package/dist/subscription-billing/service.js.map +1 -1
- package/dist/tenancy/features.d.ts +69 -0
- package/dist/tenancy/features.d.ts.map +1 -0
- package/dist/tenancy/features.js +123 -0
- package/dist/tenancy/features.js.map +1 -0
- package/dist/tenancy/settings.d.ts +63 -0
- package/dist/tenancy/settings.d.ts.map +1 -0
- package/dist/tenancy/settings.js +218 -0
- package/dist/tenancy/settings.js.map +1 -0
- package/dist/users/repository.d.ts +16 -1
- package/dist/users/repository.d.ts.map +1 -1
- package/dist/users/repository.js +24 -1
- package/dist/users/repository.js.map +1 -1
- package/package.json +9 -2
- package/src/db/migrations/0045_role_write_scope.sql +122 -0
- package/src/db/migrations/0046_pilot_activation_model.sql +184 -0
- package/src/db/migrations/0047_recipient_clearance.sql +89 -0
- package/src/db/migrations/0048_item_type_note.sql +16 -0
- package/src/db/migrations/0049_national_fiscal_engine.sql +279 -0
- package/src/db/migrations/0050_fiscal_vocabulary_readonly.sql +29 -0
- package/src/db/migrations/0051_seed_rules_from_catalog.sql +72 -0
- package/src/db/migrations/0052_fiscal_rule_delete_scope.sql +57 -0
- package/src/db/migrations/0053_rule_validity_lower_bound.sql +44 -0
- package/src/db/migrations/0054_tenant_profile_and_rule_source.sql +89 -0
- package/src/db/migrations/0055_job_capability_contract.sql +300 -0
- package/src/db/migrations/0056_fiscal_document_ingestion.sql +337 -0
- package/src/db/migrations/0057_fiscal_pending_event_inbox.sql +228 -0
- package/src/db/migrations/0058_fiscal_operational_engine.sql +516 -0
- package/src/db/migrations/0059_fiscal_contract_version.sql +59 -0
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { Tx } from '../../db/client.js';
|
|
2
|
+
import type { Keyring } from '../../vault/crypto.js';
|
|
3
|
+
import type { ClientTlsMaterial } from '../transport/types.js';
|
|
4
|
+
import type { FiscalCredentialKind } from '../eligibility.js';
|
|
5
|
+
import { type FiscalSecretAuthorization } from '../sync/secret-boundary.js';
|
|
6
|
+
/**
|
|
7
|
+
* O material de TLS mútuo, do cofre para a memória — e para lugar nenhum mais.
|
|
8
|
+
*
|
|
9
|
+
* ## As três coisas que este módulo recusa a fazer
|
|
10
|
+
*
|
|
11
|
+
* **Não escreve no disco.** Um PKCS#12 em `/tmp` precisa de permissão restrita,
|
|
12
|
+
* de limpeza garantida em todo caminho de saída (inclusive `SIGKILL`) e de
|
|
13
|
+
* alguém que lembre das duas coisas no dia do incidente. O `https.Agent` do Node
|
|
14
|
+
* aceita `Buffer`, então o arquivo temporário nunca é necessário — e "nunca
|
|
15
|
+
* necessário" é a única forma segura de "nunca esquecido".
|
|
16
|
+
*
|
|
17
|
+
* **Não passa por variável de ambiente.** Env var vaza em `env`, em dump de
|
|
18
|
+
* processo, em painel de provedor e em log de boot. Este ecossistema já perdeu
|
|
19
|
+
* `DATABASE_URL` inteiro por um `env | grep` bem-intencionado.
|
|
20
|
+
*
|
|
21
|
+
* **Não aparece em log, erro ou trilha.** O único campo desta estrutura que
|
|
22
|
+
* pode ser impresso é `fingerprintSha256`, e é por isso que ele existe: ele
|
|
23
|
+
* responde "qual certificado foi apresentado?" sem revelar nada dele.
|
|
24
|
+
*
|
|
25
|
+
* ## O envelope
|
|
26
|
+
*
|
|
27
|
+
* `vault_credential` guarda UM texto cifrado. Para certificado, esse texto é um
|
|
28
|
+
* JSON com formato declarado — e não o base64 solto, que obrigaria quem lê a
|
|
29
|
+
* adivinhar se recebeu PKCS#12 ou PEM:
|
|
30
|
+
*
|
|
31
|
+
* {"format":"pkcs12","material":"<base64 do .pfx>","passphrase":"..."}
|
|
32
|
+
* {"format":"pem","cert":"<base64 do PEM>","key":"<base64 do PEM>"}
|
|
33
|
+
*
|
|
34
|
+
* O `format` é obrigatório. Um envelope sem ele é recusado em vez de tentado
|
|
35
|
+
* como PKCS#12: adivinhar formato de material criptográfico produz um erro de
|
|
36
|
+
* OpenSSL seis camadas adiante, indistinguível de senha errada.
|
|
37
|
+
*/
|
|
38
|
+
/** O que deu errado ao buscar o material. Classe, nunca o texto do sistema. */
|
|
39
|
+
export type TlsMaterialFailure = 'no_credential' | 'vault_unavailable' | 'envelope_unreadable' | 'unsupported_format';
|
|
40
|
+
export type TlsMaterialResult = {
|
|
41
|
+
status: 'ok';
|
|
42
|
+
material: ClientTlsMaterial;
|
|
43
|
+
} | {
|
|
44
|
+
status: 'unavailable';
|
|
45
|
+
reason: TlsMaterialFailure;
|
|
46
|
+
};
|
|
47
|
+
/**
|
|
48
|
+
* Constrói o material a partir do envelope decifrado.
|
|
49
|
+
*
|
|
50
|
+
* Separado da leitura do banco de propósito: é esta função que o teste
|
|
51
|
+
* exercita com um PKCS#12 sintético, sem precisar de cofre nem de tenant.
|
|
52
|
+
*/
|
|
53
|
+
export declare function buildTlsMaterial(raw: string): TlsMaterialResult;
|
|
54
|
+
/**
|
|
55
|
+
* Busca o material do certificado de um cliente.
|
|
56
|
+
*
|
|
57
|
+
* O ponteiro vem de `digital_certificate.vault_credential_id` — o MESMO domínio
|
|
58
|
+
* que a prontidão lê, e não uma segunda tabela de credencial fiscal. Duas
|
|
59
|
+
* origens para o mesmo fato divergiriam na primeira atualização de uma só.
|
|
60
|
+
*
|
|
61
|
+
* NUNCA lança por ausência: um cliente sem certificado é estado normal, e uma
|
|
62
|
+
* exceção aqui derrubaria o worker no meio da carteira por causa do primeiro
|
|
63
|
+
* cliente não configurado.
|
|
64
|
+
*
|
|
65
|
+
* ## O `authorization` não é decoração
|
|
66
|
+
*
|
|
67
|
+
* Esta é a única porta do produto para material de certificado, e ela agora
|
|
68
|
+
* EXIGE o passe que o orquestrador emite depois do último portão. Um chamador
|
|
69
|
+
* que tente abrir o cofre antes disso — para "só conferir se o certificado
|
|
70
|
+
* abre", que é sempre como começa — recebe `FiscalSecretBoundaryError` em vez de
|
|
71
|
+
* uma chave privada. Ver `sync/secret-boundary.ts`.
|
|
72
|
+
*
|
|
73
|
+
* A checagem lança ANTES do primeiro `SELECT`: nem a existência do ponteiro é
|
|
74
|
+
* revelada a quem não passou pelos portões.
|
|
75
|
+
*/
|
|
76
|
+
export declare function loadFiscalTlsMaterial(tx: Tx, keyring: Keyring, tenantId: string, input: {
|
|
77
|
+
clientId: string;
|
|
78
|
+
kind?: FiscalCredentialKind;
|
|
79
|
+
authorization: FiscalSecretAuthorization;
|
|
80
|
+
}): Promise<TlsMaterialResult>;
|
|
81
|
+
//# sourceMappingURL=material.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"material.d.ts","sourceRoot":"","sources":["../../../src/fiscal/credentials/material.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAErD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AAC9D,OAAO,EAGL,KAAK,yBAAyB,EAC/B,MAAM,4BAA4B,CAAC;AAEpC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,+EAA+E;AAC/E,MAAM,MAAM,kBAAkB,GAC5B,eAAe,GAAG,mBAAmB,GAAG,qBAAqB,GAAG,oBAAoB,CAAC;AAEvF,MAAM,MAAM,iBAAiB,GACzB;IAAE,MAAM,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,iBAAiB,CAAA;CAAE,GAC7C;IAAE,MAAM,EAAE,aAAa,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAe1D;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,MAAM,GAAG,iBAAiB,CAsC/D;AAwCD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAsB,qBAAqB,CACzC,EAAE,EAAE,EAAE,EACN,OAAO,EAAE,OAAO,EAChB,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,oBAAoB,CAAC;IAC5B,aAAa,EAAE,yBAAyB,CAAC;CAC1C,GACA,OAAO,CAAC,iBAAiB,CAAC,CA6D5B"}
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { createHash } from 'node:crypto';
|
|
2
|
+
import { revealSecret } from '../../vault/repository.js';
|
|
3
|
+
import { FiscalSecretBoundaryError, assertFiscalSecretAccess, } from '../sync/secret-boundary.js';
|
|
4
|
+
/**
|
|
5
|
+
* Constrói o material a partir do envelope decifrado.
|
|
6
|
+
*
|
|
7
|
+
* Separado da leitura do banco de propósito: é esta função que o teste
|
|
8
|
+
* exercita com um PKCS#12 sintético, sem precisar de cofre nem de tenant.
|
|
9
|
+
*/
|
|
10
|
+
export function buildTlsMaterial(raw) {
|
|
11
|
+
let envelope;
|
|
12
|
+
try {
|
|
13
|
+
envelope = JSON.parse(raw);
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
// Sem `err.message`: um JSON malformado costuma vir citado inteiro na
|
|
17
|
+
// exceção, e o "JSON malformado" aqui é um certificado.
|
|
18
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
19
|
+
}
|
|
20
|
+
if (!envelope || typeof envelope !== 'object' || !('format' in envelope)) {
|
|
21
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
22
|
+
}
|
|
23
|
+
try {
|
|
24
|
+
if (envelope.format === 'pkcs12') {
|
|
25
|
+
if (typeof envelope.material !== 'string' || envelope.material === '') {
|
|
26
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
27
|
+
}
|
|
28
|
+
const pfx = Buffer.from(envelope.material, 'base64');
|
|
29
|
+
if (pfx.byteLength === 0)
|
|
30
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
31
|
+
return { status: 'ok', material: sealed({ pfx, passphrase: envelope.passphrase }) };
|
|
32
|
+
}
|
|
33
|
+
if (envelope.format === 'pem') {
|
|
34
|
+
if (typeof envelope.cert !== 'string' || typeof envelope.key !== 'string') {
|
|
35
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
36
|
+
}
|
|
37
|
+
const cert = Buffer.from(envelope.cert, 'base64');
|
|
38
|
+
const key = Buffer.from(envelope.key, 'base64');
|
|
39
|
+
const ca = (envelope.ca ?? []).map((c) => Buffer.from(c, 'base64'));
|
|
40
|
+
if (cert.byteLength === 0 || key.byteLength === 0) {
|
|
41
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
42
|
+
}
|
|
43
|
+
return { status: 'ok', material: sealed({ cert, key, ca }) };
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return { status: 'unavailable', reason: 'envelope_unreadable' };
|
|
48
|
+
}
|
|
49
|
+
return { status: 'unavailable', reason: 'unsupported_format' };
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Embrulha os buffers com a impressão digital e com o descarte.
|
|
53
|
+
*
|
|
54
|
+
* A impressão é do material APRESENTADO (o `.pfx` ou o `cert`), nunca da chave
|
|
55
|
+
* privada: identificar qual certificado foi usado não deve exigir tocar no
|
|
56
|
+
* segredo, nem sequer para calcular um hash.
|
|
57
|
+
*/
|
|
58
|
+
function sealed(parts) {
|
|
59
|
+
const identity = parts.pfx ?? parts.cert ?? Buffer.alloc(0);
|
|
60
|
+
const fingerprintSha256 = createHash('sha256').update(identity).digest('hex');
|
|
61
|
+
let disposed = false;
|
|
62
|
+
return {
|
|
63
|
+
...(parts.pfx ? { pfx: parts.pfx } : {}),
|
|
64
|
+
...(parts.passphrase ? { passphrase: parts.passphrase } : {}),
|
|
65
|
+
...(parts.cert ? { cert: parts.cert } : {}),
|
|
66
|
+
...(parts.key ? { key: parts.key } : {}),
|
|
67
|
+
...(parts.ca && parts.ca.length > 0 ? { ca: parts.ca } : {}),
|
|
68
|
+
fingerprintSha256,
|
|
69
|
+
dispose() {
|
|
70
|
+
if (disposed)
|
|
71
|
+
return;
|
|
72
|
+
disposed = true;
|
|
73
|
+
// Zerar não é cerimônia: o Buffer sobrevive no heap até o GC passar, e um
|
|
74
|
+
// heap dump de produção é um arquivo que alguém abre e guarda.
|
|
75
|
+
parts.pfx?.fill(0);
|
|
76
|
+
parts.cert?.fill(0);
|
|
77
|
+
parts.key?.fill(0);
|
|
78
|
+
for (const c of parts.ca ?? [])
|
|
79
|
+
c.fill(0);
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Busca o material do certificado de um cliente.
|
|
85
|
+
*
|
|
86
|
+
* O ponteiro vem de `digital_certificate.vault_credential_id` — o MESMO domínio
|
|
87
|
+
* que a prontidão lê, e não uma segunda tabela de credencial fiscal. Duas
|
|
88
|
+
* origens para o mesmo fato divergiriam na primeira atualização de uma só.
|
|
89
|
+
*
|
|
90
|
+
* NUNCA lança por ausência: um cliente sem certificado é estado normal, e uma
|
|
91
|
+
* exceção aqui derrubaria o worker no meio da carteira por causa do primeiro
|
|
92
|
+
* cliente não configurado.
|
|
93
|
+
*
|
|
94
|
+
* ## O `authorization` não é decoração
|
|
95
|
+
*
|
|
96
|
+
* Esta é a única porta do produto para material de certificado, e ela agora
|
|
97
|
+
* EXIGE o passe que o orquestrador emite depois do último portão. Um chamador
|
|
98
|
+
* que tente abrir o cofre antes disso — para "só conferir se o certificado
|
|
99
|
+
* abre", que é sempre como começa — recebe `FiscalSecretBoundaryError` em vez de
|
|
100
|
+
* uma chave privada. Ver `sync/secret-boundary.ts`.
|
|
101
|
+
*
|
|
102
|
+
* A checagem lança ANTES do primeiro `SELECT`: nem a existência do ponteiro é
|
|
103
|
+
* revelada a quem não passou pelos portões.
|
|
104
|
+
*/
|
|
105
|
+
export async function loadFiscalTlsMaterial(tx, keyring, tenantId, input) {
|
|
106
|
+
assertFiscalSecretAccess(input.authorization, 'loadFiscalTlsMaterial');
|
|
107
|
+
/*
|
|
108
|
+
* O passe é AUTÊNTICO — mas para quem?
|
|
109
|
+
*
|
|
110
|
+
* `assertFiscalSecretAccess` responde "esta autorização saiu dos portões", e
|
|
111
|
+
* não "esta autorização é DESTE cliente". A diferença abre um caso que a RLS
|
|
112
|
+
* não fecha: dentro do MESMO escritório, um passe emitido para o cliente X
|
|
113
|
+
* abriria o certificado do cliente Y, porque a política de tenant considera as
|
|
114
|
+
* duas linhas visíveis. É o `WHERE client_id = ...` abaixo que escolhe a
|
|
115
|
+
* linha, e ele obedece ao parâmetro, não ao passe.
|
|
116
|
+
*
|
|
117
|
+
* Hoje o orquestrador emite e usa o passe no mesmo par (tenant, cliente), de
|
|
118
|
+
* modo que o caso não ocorre. Mas é exatamente esse tipo de invariante — "quem
|
|
119
|
+
* chama sempre passa os mesmos valores" — que um refactor quebra em silêncio,
|
|
120
|
+
* e o módulo inteiro da fronteira existe porque convenção não é portão.
|
|
121
|
+
*
|
|
122
|
+
* A checagem é de ESCOPO, e vem antes de qualquer consulta: um passe fora do
|
|
123
|
+
* seu escopo não chega nem a saber se existe certificado do outro lado.
|
|
124
|
+
*/
|
|
125
|
+
if (input.authorization.tenantId !== tenantId ||
|
|
126
|
+
input.authorization.clientId !== input.clientId) {
|
|
127
|
+
throw new FiscalSecretBoundaryError('loadFiscalTlsMaterial:scope');
|
|
128
|
+
}
|
|
129
|
+
const certType = input.kind === 'certificate_a3' ? 'A3' : 'A1';
|
|
130
|
+
let rows;
|
|
131
|
+
try {
|
|
132
|
+
rows = await tx `
|
|
133
|
+
SELECT vault_credential_id
|
|
134
|
+
FROM digital_certificate
|
|
135
|
+
WHERE client_id = ${input.clientId}
|
|
136
|
+
AND cert_type = ${certType}
|
|
137
|
+
AND deleted_at IS NULL
|
|
138
|
+
ORDER BY expires_at DESC
|
|
139
|
+
LIMIT 1
|
|
140
|
+
`;
|
|
141
|
+
}
|
|
142
|
+
catch (err) {
|
|
143
|
+
const code = err?.code;
|
|
144
|
+
if (code === '42P01' || code === '42703') {
|
|
145
|
+
return { status: 'unavailable', reason: 'no_credential' };
|
|
146
|
+
}
|
|
147
|
+
throw err;
|
|
148
|
+
}
|
|
149
|
+
const pointer = rows[0]?.vault_credential_id;
|
|
150
|
+
if (!pointer)
|
|
151
|
+
return { status: 'unavailable', reason: 'no_credential' };
|
|
152
|
+
let secret;
|
|
153
|
+
try {
|
|
154
|
+
({ secret } = await revealSecret(tx, keyring, tenantId, pointer));
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// Ponteiro pendurado, chave de cifra ausente, linha invisível sob RLS: os
|
|
158
|
+
// três colapsam em "não deu para abrir", e diferenciá-los aqui vazaria a
|
|
159
|
+
// existência de um registro que a RLS já respondeu como ausente.
|
|
160
|
+
return { status: 'unavailable', reason: 'vault_unavailable' };
|
|
161
|
+
}
|
|
162
|
+
return buildTlsMaterial(secret);
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=material.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"material.js","sourceRoot":"","sources":["../../../src/fiscal/credentials/material.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import type { Tx } from '../../db/client.js';
|
|
2
|
+
import type { FiscalCredentialKind, FiscalEnvironment } from '../eligibility.js';
|
|
3
|
+
/**
|
|
4
|
+
* A prontidão OPERACIONAL da credencial de um cliente.
|
|
5
|
+
*
|
|
6
|
+
* ## Por que não bastava o que a Fase 1 já respondia
|
|
7
|
+
*
|
|
8
|
+
* `readCredentialReadiness` (eligibility.ts) responde à pergunta do PORTÃO:
|
|
9
|
+
* "posso deixar este cliente entrar na automação?". Devolve cinco valores e é
|
|
10
|
+
* suficiente para isso.
|
|
11
|
+
*
|
|
12
|
+
* O worker precisa de outra coisa: quando o portão fecha, ele tem de decidir o
|
|
13
|
+
* que fazer com o fechamento — retentar amanhã, abrir tarefa para uma pessoa, ou
|
|
14
|
+
* nem uma coisa nem outra. `configured_not_verified` e `expired` reprovam
|
|
15
|
+
* igualmente no portão e pedem ações opostas depois dele.
|
|
16
|
+
*
|
|
17
|
+
* ## Cadastrado não é autorizado — e a separação é um campo, não um comentário
|
|
18
|
+
*
|
|
19
|
+
* Existe um erro caro que este módulo existe para tornar indizível: tratar
|
|
20
|
+
* "o cliente cadastrou um A1 válido" como "estamos autorizados a consultar o
|
|
21
|
+
* ambiente nacional em nome dele". São fatos independentes.
|
|
22
|
+
*
|
|
23
|
+
* material o certificado existe, abre, e não venceu.
|
|
24
|
+
* providerAuthorization aquele ambiente JÁ ACEITOU esse material alguma vez.
|
|
25
|
+
*
|
|
26
|
+
* O segundo não se deduz do primeiro. Um A1 impecável cujo titular não outorgou
|
|
27
|
+
* procuração é recusado pelo servidor — e o primeiro campo continua `READY`. Por
|
|
28
|
+
* isso a autorização sai de FATO OBSERVADO (um `fiscal_sync_run` bem-sucedido
|
|
29
|
+
* naquele ambiente), e nunca de inferência sobre o cadastro.
|
|
30
|
+
*/
|
|
31
|
+
/**
|
|
32
|
+
* Estados operacionais.
|
|
33
|
+
*
|
|
34
|
+
* `NOT_CONFIGURED` não há credencial. Ninguém prometeu nada.
|
|
35
|
+
* `READY` existe, abre, não venceu, e já foi exercida.
|
|
36
|
+
* `EXPIRED` venceu. Só a renovação resolve.
|
|
37
|
+
* `INVALID` revogada, ou o ponteiro para o cofre não resolve.
|
|
38
|
+
* `ACCESS_DENIED` o material serve; o ambiente recusou o TITULAR.
|
|
39
|
+
* `REQUIRES_REVIEW` cadastrada e nunca exercida — ou de um tipo que um cron
|
|
40
|
+
* não consegue usar (A3 vive em token com PIN presencial).
|
|
41
|
+
*/
|
|
42
|
+
export type FiscalCredentialState = 'NOT_CONFIGURED' | 'READY' | 'EXPIRED' | 'INVALID' | 'ACCESS_DENIED' | 'REQUIRES_REVIEW';
|
|
43
|
+
export interface FiscalCredentialReadiness {
|
|
44
|
+
state: FiscalCredentialState;
|
|
45
|
+
kind: FiscalCredentialKind | null;
|
|
46
|
+
/** Só `READY` autoriza o worker a tentar. Nenhum outro estado, por motivo nenhum. */
|
|
47
|
+
usableByWorker: boolean;
|
|
48
|
+
/**
|
|
49
|
+
* `true` quando um retry futuro pode mudar o desfecho sem intervenção humana.
|
|
50
|
+
* `EXPIRED`, `INVALID` e `ACCESS_DENIED` são `false` — e é isso que decide se
|
|
51
|
+
* o caso vira linha na fila de pessoas ou só espera.
|
|
52
|
+
*/
|
|
53
|
+
selfHealing: boolean;
|
|
54
|
+
expiresOn: string | null;
|
|
55
|
+
verifiedAt: string | null;
|
|
56
|
+
/** sha256 truncado do material, quando registrado. Seguro para tela e trilha. */
|
|
57
|
+
fingerprint: string | null;
|
|
58
|
+
/**
|
|
59
|
+
* O ambiente já aceitou esta credencial? Sai de execução observada, jamais do
|
|
60
|
+
* cadastro. `unknown` é o estado inicial e honesto de todo cliente novo.
|
|
61
|
+
*/
|
|
62
|
+
providerAuthorization: 'unknown' | 'established';
|
|
63
|
+
/** Classe e contexto. NUNCA a resposta do provedor. */
|
|
64
|
+
detail: string;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Lê a prontidão operacional.
|
|
68
|
+
*
|
|
69
|
+
* Roda dentro de `withContext` com o tenant: `digital_certificate` tem RLS FORCE
|
|
70
|
+
* e é a GUC que decide de quem são as linhas lidas.
|
|
71
|
+
*
|
|
72
|
+
* Tolera a ausência da tabela (`42P01`) porque `digital_certificate` pertence à
|
|
73
|
+
* VERTICAL contábil: um tenant sem ela instalada não tem credencial nenhuma, e
|
|
74
|
+
* a leitura correta disso é `NOT_CONFIGURED` — não uma exceção que derruba o
|
|
75
|
+
* worker no meio da carteira.
|
|
76
|
+
*/
|
|
77
|
+
export declare function readFiscalCredentialReadiness(tx: Tx, input: {
|
|
78
|
+
clientId: string;
|
|
79
|
+
environment: FiscalEnvironment;
|
|
80
|
+
source: string;
|
|
81
|
+
kind?: FiscalCredentialKind;
|
|
82
|
+
}): Promise<FiscalCredentialReadiness>;
|
|
83
|
+
/**
|
|
84
|
+
* O motivo de intervenção que este estado pede — ou `null` quando não pede.
|
|
85
|
+
*
|
|
86
|
+
* Aqui mora a regra de B2.36 que evita a fila ilegível: `REQUIRES_REVIEW` e
|
|
87
|
+
* `NOT_CONFIGURED` NÃO abrem tarefa. Não configurar automação é uma escolha
|
|
88
|
+
* legítima do escritório, e transformá-la em pendência encheria a fila de
|
|
89
|
+
* clientes que ninguém pediu para automatizar.
|
|
90
|
+
*/
|
|
91
|
+
export declare function interventionKindFor(state: FiscalCredentialState): 'certificate_expired' | 'certificate_invalid' | 'auth_required' | null;
|
|
92
|
+
//# sourceMappingURL=readiness.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readiness.d.ts","sourceRoot":"","sources":["../../../src/fiscal/credentials/readiness.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,oBAAoB,CAAC;AAC7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAEjF;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AAEH;;;;;;;;;;GAUG;AACH,MAAM,MAAM,qBAAqB,GAC/B,gBAAgB,GAAG,OAAO,GAAG,SAAS,GAAG,SAAS,GAAG,eAAe,GAAG,iBAAiB,CAAC;AAE3F,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,qBAAqB,CAAC;IAC7B,IAAI,EAAE,oBAAoB,GAAG,IAAI,CAAC;IAClC,qFAAqF;IACrF,cAAc,EAAE,OAAO,CAAC;IACxB;;;;OAIG;IACH,WAAW,EAAE,OAAO,CAAC;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,iFAAiF;IACjF,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B;;;OAGG;IACH,qBAAqB,EAAE,SAAS,GAAG,aAAa,CAAC;IACjD,uDAAuD;IACvD,MAAM,EAAE,MAAM,CAAC;CAChB;AAoBD;;;;;;;;;;GAUG;AACH,wBAAsB,6BAA6B,CACjD,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,iBAAiB,CAAC;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,oBAAoB,CAAC;CAC7B,GACA,OAAO,CAAC,yBAAyB,CAAC,CAuHpC;AAWD;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,KAAK,EAAE,qBAAqB,GAC3B,qBAAqB,GAAG,qBAAqB,GAAG,eAAe,GAAG,IAAI,CAWxE"}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Classes de erro de verificação que significam "o titular foi recusado".
|
|
3
|
+
*
|
|
4
|
+
* Guardadas em `digital_certificate.last_verification_error` como CLASSE — a
|
|
5
|
+
* coluna existe desde a 1004 justamente para não guardar a mensagem.
|
|
6
|
+
*/
|
|
7
|
+
const DENIED_CLASSES = new Set(['auth', 'not_allowed', 'access_denied', 'permission_denied']);
|
|
8
|
+
/**
|
|
9
|
+
* Lê a prontidão operacional.
|
|
10
|
+
*
|
|
11
|
+
* Roda dentro de `withContext` com o tenant: `digital_certificate` tem RLS FORCE
|
|
12
|
+
* e é a GUC que decide de quem são as linhas lidas.
|
|
13
|
+
*
|
|
14
|
+
* Tolera a ausência da tabela (`42P01`) porque `digital_certificate` pertence à
|
|
15
|
+
* VERTICAL contábil: um tenant sem ela instalada não tem credencial nenhuma, e
|
|
16
|
+
* a leitura correta disso é `NOT_CONFIGURED` — não uma exceção que derruba o
|
|
17
|
+
* worker no meio da carteira.
|
|
18
|
+
*/
|
|
19
|
+
export async function readFiscalCredentialReadiness(tx, input) {
|
|
20
|
+
const kind = input.kind ?? 'certificate_a1';
|
|
21
|
+
const base = {
|
|
22
|
+
kind,
|
|
23
|
+
usableByWorker: false,
|
|
24
|
+
selfHealing: false,
|
|
25
|
+
expiresOn: null,
|
|
26
|
+
verifiedAt: null,
|
|
27
|
+
fingerprint: null,
|
|
28
|
+
providerAuthorization: 'unknown',
|
|
29
|
+
};
|
|
30
|
+
if (kind === 'municipal_portal') {
|
|
31
|
+
// Login de portal municipal não é certificado ICP-Brasil e ainda não tem
|
|
32
|
+
// onde morar. Um cron também não digita captcha. Negado até existir.
|
|
33
|
+
return {
|
|
34
|
+
...base,
|
|
35
|
+
state: 'NOT_CONFIGURED',
|
|
36
|
+
detail: 'portal municipal não tem credencial automatizável neste produto',
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
let rows;
|
|
40
|
+
try {
|
|
41
|
+
rows = await tx `
|
|
42
|
+
SELECT id, cert_type, status, expires_at, verified_at,
|
|
43
|
+
last_verification_error, vault_credential_id
|
|
44
|
+
FROM digital_certificate
|
|
45
|
+
WHERE client_id = ${input.clientId}
|
|
46
|
+
AND cert_type = ${kind === 'certificate_a3' ? 'A3' : 'A1'}
|
|
47
|
+
AND deleted_at IS NULL
|
|
48
|
+
ORDER BY expires_at DESC
|
|
49
|
+
LIMIT 1
|
|
50
|
+
`;
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
const code = err?.code;
|
|
54
|
+
if (code === '42P01' || code === '42703') {
|
|
55
|
+
return { ...base, state: 'NOT_CONFIGURED', detail: 'vertical contábil não aplicada' };
|
|
56
|
+
}
|
|
57
|
+
throw err;
|
|
58
|
+
}
|
|
59
|
+
const cert = rows[0];
|
|
60
|
+
if (!cert) {
|
|
61
|
+
return { ...base, state: 'NOT_CONFIGURED', detail: 'nenhum certificado cadastrado' };
|
|
62
|
+
}
|
|
63
|
+
const expiresOn = cert.expires_at ? isoDate(cert.expires_at) : null;
|
|
64
|
+
const verifiedAt = cert.verified_at?.toISOString() ?? null;
|
|
65
|
+
const withDates = { ...base, expiresOn, verifiedAt };
|
|
66
|
+
if (cert.status === 'revoked') {
|
|
67
|
+
return { ...withDates, state: 'INVALID', detail: 'certificado revogado' };
|
|
68
|
+
}
|
|
69
|
+
// Vencimento é fato do calendário, não do registro: um certificado marcado
|
|
70
|
+
// `active` cuja data passou está vencido mesmo que ninguém tenha corrido para
|
|
71
|
+
// atualizar a linha.
|
|
72
|
+
if (cert.expires_at && cert.expires_at < todayUtc()) {
|
|
73
|
+
return { ...withDates, state: 'EXPIRED', detail: `vencido em ${expiresOn}` };
|
|
74
|
+
}
|
|
75
|
+
if (cert.status === 'expired') {
|
|
76
|
+
return { ...withDates, state: 'EXPIRED', detail: 'marcado como vencido' };
|
|
77
|
+
}
|
|
78
|
+
if (cert.last_verification_error && DENIED_CLASSES.has(cert.last_verification_error)) {
|
|
79
|
+
return {
|
|
80
|
+
...withDates,
|
|
81
|
+
state: 'ACCESS_DENIED',
|
|
82
|
+
detail: `último acesso recusado (${cert.last_verification_error})`,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
if (kind === 'certificate_a3') {
|
|
86
|
+
// A3 vive em token ou cartão com PIN digitado por uma pessoa. Ele EXISTE, e
|
|
87
|
+
// dizer "não tem certificado" seria falso; o que ele não é, é automatizável.
|
|
88
|
+
return {
|
|
89
|
+
...withDates,
|
|
90
|
+
state: 'REQUIRES_REVIEW',
|
|
91
|
+
detail: 'A3 exige PIN presencial e não é automatizável por cron',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
if (!cert.vault_credential_id) {
|
|
95
|
+
// Cadastro sem material é uma promessa sem lastro: a tela diria "tem
|
|
96
|
+
// certificado" e o worker não teria o que apresentar no handshake.
|
|
97
|
+
return {
|
|
98
|
+
...withDates,
|
|
99
|
+
state: 'INVALID',
|
|
100
|
+
detail: 'certificado cadastrado sem material no cofre',
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
if (!cert.verified_at) {
|
|
104
|
+
return {
|
|
105
|
+
...withDates,
|
|
106
|
+
state: 'REQUIRES_REVIEW',
|
|
107
|
+
detail: 'cadastrado e nunca exercido contra o ambiente oficial',
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
// A autorização do provedor sai de execução OBSERVADA. Um `SELECT` sobre a
|
|
111
|
+
// trilha, e não uma dedução a partir do cadastro.
|
|
112
|
+
const [ok] = await tx `
|
|
113
|
+
SELECT count(*)::int AS n
|
|
114
|
+
FROM fiscal_sync_run
|
|
115
|
+
WHERE client_id = ${input.clientId}
|
|
116
|
+
AND source = ${input.source}
|
|
117
|
+
AND environment = ${input.environment}
|
|
118
|
+
AND outcome IN ('completed', 'no_documents')
|
|
119
|
+
`;
|
|
120
|
+
const established = (ok?.n ?? 0) > 0;
|
|
121
|
+
return {
|
|
122
|
+
...withDates,
|
|
123
|
+
state: 'READY',
|
|
124
|
+
usableByWorker: true,
|
|
125
|
+
selfHealing: true,
|
|
126
|
+
providerAuthorization: established ? 'established' : 'unknown',
|
|
127
|
+
detail: established
|
|
128
|
+
? 'pronta; o ambiente já aceitou esta credencial'
|
|
129
|
+
: 'pronta; o ambiente ainda não aceitou esta credencial nenhuma vez',
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
function todayUtc() {
|
|
133
|
+
const now = new Date();
|
|
134
|
+
return new Date(Date.UTC(now.getUTCFullYear(), now.getUTCMonth(), now.getUTCDate()));
|
|
135
|
+
}
|
|
136
|
+
function isoDate(d) {
|
|
137
|
+
return d.toISOString().slice(0, 10);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* O motivo de intervenção que este estado pede — ou `null` quando não pede.
|
|
141
|
+
*
|
|
142
|
+
* Aqui mora a regra de B2.36 que evita a fila ilegível: `REQUIRES_REVIEW` e
|
|
143
|
+
* `NOT_CONFIGURED` NÃO abrem tarefa. Não configurar automação é uma escolha
|
|
144
|
+
* legítima do escritório, e transformá-la em pendência encheria a fila de
|
|
145
|
+
* clientes que ninguém pediu para automatizar.
|
|
146
|
+
*/
|
|
147
|
+
export function interventionKindFor(state) {
|
|
148
|
+
switch (state) {
|
|
149
|
+
case 'EXPIRED':
|
|
150
|
+
return 'certificate_expired';
|
|
151
|
+
case 'INVALID':
|
|
152
|
+
return 'certificate_invalid';
|
|
153
|
+
case 'ACCESS_DENIED':
|
|
154
|
+
return 'auth_required';
|
|
155
|
+
default:
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=readiness.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"readiness.js","sourceRoot":"","sources":["../../../src/fiscal/credentials/readiness.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { Tx } from '../db/client.js';
|
|
2
|
+
/**
|
|
3
|
+
* Quem entra em automação fiscal — e, sobretudo, quem NÃO entra.
|
|
4
|
+
*
|
|
5
|
+
* ## O caso que dá nome a tudo
|
|
6
|
+
*
|
|
7
|
+
* Um job de ingestão fiscal escrito da forma óbvia selecionaria
|
|
8
|
+
* `WHERE deleted_at IS NULL`. No tenant da SC isso alcança hoje dois cadastros
|
|
9
|
+
* que foram criados em teste do próprio sistema — e alcançaria a carteira real
|
|
10
|
+
* inteira no dia seguinte a uma importação, sem que ninguém tivesse dito que
|
|
11
|
+
* aqueles clientes deviam ser acompanhados.
|
|
12
|
+
*
|
|
13
|
+
* Documento fiscal não é e-mail. Uma consulta indevida ao DF-e usa o
|
|
14
|
+
* certificado do CLIENTE contra a Receita, e o `cStat 656` que ela pode render
|
|
15
|
+
* bloqueia o CNPJ dele — não o nosso. O custo do falso positivo recai sobre um
|
|
16
|
+
* terceiro que não pediu nada.
|
|
17
|
+
*
|
|
18
|
+
* ## Quatro camadas, porque quatro coisas diferentes podem faltar
|
|
19
|
+
*
|
|
20
|
+
* escritório → ligou automação fiscal? em qual ambiente? (`tenant_fiscal_automation`)
|
|
21
|
+
* cliente → está inscrito, para ESTE tipo de documento? (`client_fiscal_enrollment`)
|
|
22
|
+
* credencial → existe insumo, e alguém o EXERCEU? (`digital_certificate`)
|
|
23
|
+
* operação → o ambiente pedido é real, e o piloto foi declarado? (0047)
|
|
24
|
+
*
|
|
25
|
+
* Nenhuma delas tem default permissivo. A ausência de linha nas três tabelas
|
|
26
|
+
* significa negado, e é isso que faz a migration 0055 não precisar de backfill
|
|
27
|
+
* nenhum para deixar todo mundo fora: ela cria as tabelas vazias, e vazio já é
|
|
28
|
+
* a barreira. É a mesma decisão da 0047 — omissão nunca vira autorização,
|
|
29
|
+
* porque omissão é o estado natural de quem acabou de entrar.
|
|
30
|
+
*
|
|
31
|
+
* ## Ambiente é parte da pergunta, não um detalhe
|
|
32
|
+
*
|
|
33
|
+
* `synthetic` e `production` não se substituem. Um escritório em `synthetic`
|
|
34
|
+
* NUNCA fica elegível para um job real, e um escritório em `production` NUNCA
|
|
35
|
+
* fica elegível para um job sintético. Não há fallback entre eles em nenhuma
|
|
36
|
+
* direção: fallback é exatamente como documento de homologação entra em
|
|
37
|
+
* carteira real, e como credencial real acaba exercida por um ensaio.
|
|
38
|
+
*/
|
|
39
|
+
/**
|
|
40
|
+
* Os três ambientes, e nenhum substitui outro.
|
|
41
|
+
*
|
|
42
|
+
* `homologation` é a produção restrita oficial — do ADN
|
|
43
|
+
* (`adn.producaorestrita.nfse.gov.br`) ou da SEFAZ. Ela não é laboratório: é o
|
|
44
|
+
* servidor de verdade, respondendo como o real, sobre documento sem valor
|
|
45
|
+
* fiscal. Colapsá-la em `production` faria alguém abrir a elegibilidade para
|
|
46
|
+
* ensaiar e, sem perceber, autorizar o ambiente real.
|
|
47
|
+
*/
|
|
48
|
+
export type FiscalEnvironment = 'synthetic' | 'homologation' | 'production';
|
|
49
|
+
export type FiscalDocumentType = 'nfe' | 'nfse' | 'cte' | 'nfce';
|
|
50
|
+
/** Prontidão da credencial. `no_credential` é a AUSÊNCIA de linha, não um valor. */
|
|
51
|
+
export type CredentialReadiness = 'no_credential' | 'configured_not_verified' | 'verified' | 'expired' | 'revoked';
|
|
52
|
+
/**
|
|
53
|
+
* Tipos de credencial fiscal.
|
|
54
|
+
*
|
|
55
|
+
* `certificate_a3` existe no vocabulário porque `digital_certificate` já o
|
|
56
|
+
* aceita — mas A3 vive em token ou cartão com PIN presencial, e por isso NÃO é
|
|
57
|
+
* automatizável por um cron. Nomeá-lo permite ao produto dizer "este cliente
|
|
58
|
+
* tem certificado, e ele não serve para automação" em vez de dizer que não tem.
|
|
59
|
+
*/
|
|
60
|
+
export type FiscalCredentialKind = 'certificate_a1' | 'certificate_a3' | 'municipal_portal';
|
|
61
|
+
export type FiscalDenialReason = 'tenant_automation_disabled' | 'environment_mismatch' | 'real_operation_not_declared' | 'client_not_found' | 'client_inactive' | 'client_not_enrolled' | 'credential_not_ready';
|
|
62
|
+
export interface FiscalEligibility {
|
|
63
|
+
eligible: boolean;
|
|
64
|
+
/** Vazio quando elegível. Todos os motivos, não só o primeiro. */
|
|
65
|
+
reasons: readonly FiscalDenialReason[];
|
|
66
|
+
environment: FiscalEnvironment | null;
|
|
67
|
+
credential: CredentialReadiness;
|
|
68
|
+
detail: string;
|
|
69
|
+
}
|
|
70
|
+
export interface TenantFiscalAutomation {
|
|
71
|
+
mode: 'disabled' | FiscalEnvironment;
|
|
72
|
+
enabledAt: string | null;
|
|
73
|
+
enabledBy: string | null;
|
|
74
|
+
}
|
|
75
|
+
/** Lê o modo do escritório. Ausência de linha é `disabled` — nunca "herda". */
|
|
76
|
+
export declare function getTenantFiscalAutomation(tx: Tx): Promise<TenantFiscalAutomation>;
|
|
77
|
+
/**
|
|
78
|
+
* Este cliente pode entrar em automação fiscal, neste ambiente, para este tipo?
|
|
79
|
+
*
|
|
80
|
+
* Devolve TODOS os motivos de recusa, e não só o primeiro: quem for habilitar
|
|
81
|
+
* um cliente precisa saber tudo o que falta de uma vez, e não descobrir a
|
|
82
|
+
* próxima pendência a cada tentativa.
|
|
83
|
+
*
|
|
84
|
+
* Precisa rodar dentro de `withContext` com o tenant: as três tabelas têm RLS
|
|
85
|
+
* FORCE, e é a GUC que decide de quem são as linhas lidas.
|
|
86
|
+
*/
|
|
87
|
+
export declare function evaluateFiscalEligibility(tx: Tx, input: {
|
|
88
|
+
clientId: string;
|
|
89
|
+
documentType: FiscalDocumentType;
|
|
90
|
+
environment: FiscalEnvironment;
|
|
91
|
+
/** Tipo de credencial exigido pelo documento. */
|
|
92
|
+
credentialKind?: FiscalCredentialKind;
|
|
93
|
+
}): Promise<FiscalEligibility>;
|
|
94
|
+
/**
|
|
95
|
+
* Os clientes elegíveis do tenant corrente.
|
|
96
|
+
*
|
|
97
|
+
* É esta função — e não uma consulta escrita à mão dentro do worker — que um
|
|
98
|
+
* job fiscal futuro deve usar para montar o lote. A regra vale porque o caminho
|
|
99
|
+
* óbvio (`SELECT id FROM client WHERE deleted_at IS NULL`) é justamente o
|
|
100
|
+
* defeito: ele existe, é fácil de escrever, e não pergunta nada do que importa.
|
|
101
|
+
*/
|
|
102
|
+
export declare function listFiscalEligibleClients(tx: Tx, input: {
|
|
103
|
+
documentType: FiscalDocumentType;
|
|
104
|
+
environment: FiscalEnvironment;
|
|
105
|
+
}): Promise<string[]>;
|
|
106
|
+
//# sourceMappingURL=eligibility.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eligibility.d.ts","sourceRoot":"","sources":["../../src/fiscal/eligibility.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,iBAAiB,CAAC;AAG1C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AAEH;;;;;;;;GAQG;AACH,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,cAAc,GAAG,YAAY,CAAC;AAC5E,MAAM,MAAM,kBAAkB,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAEjE,oFAAoF;AACpF,MAAM,MAAM,mBAAmB,GAC7B,eAAe,GAAG,yBAAyB,GAAG,UAAU,GAAG,SAAS,GAAG,SAAS,CAAC;AAEnF;;;;;;;GAOG;AACH,MAAM,MAAM,oBAAoB,GAAG,gBAAgB,GAAG,gBAAgB,GAAG,kBAAkB,CAAC;AAE5F,MAAM,MAAM,kBAAkB,GAC1B,4BAA4B,GAC5B,sBAAsB,GACtB,6BAA6B,GAC7B,kBAAkB,GAClB,iBAAiB,GACjB,qBAAqB,GACrB,sBAAsB,CAAC;AAE3B,MAAM,WAAW,iBAAiB;IAChC,QAAQ,EAAE,OAAO,CAAC;IAClB,kEAAkE;IAClE,OAAO,EAAE,SAAS,kBAAkB,EAAE,CAAC;IACvC,WAAW,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACtC,UAAU,EAAE,mBAAmB,CAAC;IAChC,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,UAAU,GAAG,iBAAiB,CAAC;IACrC,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;CAC1B;AAED,+EAA+E;AAC/E,wBAAsB,yBAAyB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,sBAAsB,CAAC,CAWvF;AAED;;;;;;;;;GASG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IACL,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,kBAAkB,CAAC;IACjC,WAAW,EAAE,iBAAiB,CAAC;IAC/B,iDAAiD;IACjD,cAAc,CAAC,EAAE,oBAAoB,CAAC;CACvC,GACA,OAAO,CAAC,iBAAiB,CAAC,CAyD5B;AA6ED;;;;;;;GAOG;AACH,wBAAsB,yBAAyB,CAC7C,EAAE,EAAE,EAAE,EACN,KAAK,EAAE;IAAE,YAAY,EAAE,kBAAkB,CAAC;IAAC,WAAW,EAAE,iBAAiB,CAAA;CAAE,GAC1E,OAAO,CAAC,MAAM,EAAE,CAAC,CA4BnB"}
|