@timbro/invoices 0.7.0-next.30

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.
Files changed (144) hide show
  1. package/README.md +308 -0
  2. package/dist/artifact-headers.d.ts +9 -0
  3. package/dist/artifact-headers.d.ts.map +1 -0
  4. package/dist/artifact-headers.js +43 -0
  5. package/dist/certificate-custody-import.d.ts +13 -0
  6. package/dist/certificate-custody-import.d.ts.map +1 -0
  7. package/dist/certificate-custody-import.js +30 -0
  8. package/dist/certificate-custody-readiness.d.ts +6 -0
  9. package/dist/certificate-custody-readiness.d.ts.map +1 -0
  10. package/dist/certificate-custody-readiness.js +13 -0
  11. package/dist/collection.d.ts +13 -0
  12. package/dist/collection.d.ts.map +1 -0
  13. package/dist/collection.js +21 -0
  14. package/dist/direct-connection.d.ts +74 -0
  15. package/dist/direct-connection.d.ts.map +1 -0
  16. package/dist/direct-connection.js +192 -0
  17. package/dist/document-node.d.ts +15 -0
  18. package/dist/document-node.d.ts.map +1 -0
  19. package/dist/document-node.js +67 -0
  20. package/dist/document-worker-protocol.d.ts +30 -0
  21. package/dist/document-worker-protocol.d.ts.map +1 -0
  22. package/dist/document-worker-protocol.js +103 -0
  23. package/dist/document-worker.d.ts +2 -0
  24. package/dist/document-worker.d.ts.map +1 -0
  25. package/dist/document-worker.js +71 -0
  26. package/dist/document.d.ts +38 -0
  27. package/dist/document.d.ts.map +1 -0
  28. package/dist/document.js +204 -0
  29. package/dist/fiscal-delivery.d.ts +12 -0
  30. package/dist/fiscal-delivery.d.ts.map +1 -0
  31. package/dist/fiscal-delivery.js +45 -0
  32. package/dist/fiscal-engine-runtime.manifest.json +637 -0
  33. package/dist/fiscal-engine-runtime.provenance.json +1010 -0
  34. package/dist/fiscal-error.d.ts +23 -0
  35. package/dist/fiscal-error.d.ts.map +1 -0
  36. package/dist/fiscal-error.js +36 -0
  37. package/dist/fiscal-numbering-readiness.d.ts +6 -0
  38. package/dist/fiscal-numbering-readiness.d.ts.map +1 -0
  39. package/dist/fiscal-numbering-readiness.js +13 -0
  40. package/dist/fiscal-operation-timing.d.ts +9 -0
  41. package/dist/fiscal-operation-timing.d.ts.map +1 -0
  42. package/dist/fiscal-operation-timing.js +22 -0
  43. package/dist/fiscal-operation.d.ts +112 -0
  44. package/dist/fiscal-operation.d.ts.map +1 -0
  45. package/dist/fiscal-operation.js +193 -0
  46. package/dist/fiscal-receipt.d.ts +19 -0
  47. package/dist/fiscal-receipt.d.ts.map +1 -0
  48. package/dist/fiscal-receipt.js +66 -0
  49. package/dist/generated/index.d.ts +5 -0
  50. package/dist/generated/index.d.ts.map +1 -0
  51. package/dist/generated/index.js +4 -0
  52. package/dist/generated/problem-catalog.d.ts +7 -0
  53. package/dist/generated/problem-catalog.d.ts.map +1 -0
  54. package/dist/generated/problem-catalog.js +198 -0
  55. package/dist/generated/sdk.gen.d.ts +240 -0
  56. package/dist/generated/sdk.gen.d.ts.map +1 -0
  57. package/dist/generated/sdk.gen.js +4486 -0
  58. package/dist/generated/types.gen.d.ts +6906 -0
  59. package/dist/generated/types.gen.d.ts.map +1 -0
  60. package/dist/generated/types.gen.js +2 -0
  61. package/dist/generated/zod.gen.d.ts +146666 -0
  62. package/dist/generated/zod.gen.d.ts.map +1 -0
  63. package/dist/generated/zod.gen.js +25077 -0
  64. package/dist/generated-operation-client.d.ts +47 -0
  65. package/dist/generated-operation-client.d.ts.map +1 -0
  66. package/dist/generated-operation-client.js +112 -0
  67. package/dist/generated-problem.d.ts +12 -0
  68. package/dist/generated-problem.d.ts.map +1 -0
  69. package/dist/generated-problem.js +37 -0
  70. package/dist/hosted-tenant.d.ts +38 -0
  71. package/dist/hosted-tenant.d.ts.map +1 -0
  72. package/dist/hosted-tenant.js +67 -0
  73. package/dist/hosted-workspace-transport.d.ts +15 -0
  74. package/dist/hosted-workspace-transport.d.ts.map +1 -0
  75. package/dist/hosted-workspace-transport.js +15 -0
  76. package/dist/idempotency-key.d.ts +3 -0
  77. package/dist/idempotency-key.d.ts.map +1 -0
  78. package/dist/idempotency-key.js +11 -0
  79. package/dist/index.d.ts +42 -0
  80. package/dist/index.d.ts.map +1 -0
  81. package/dist/index.js +14 -0
  82. package/dist/printed-representation.d.ts +23 -0
  83. package/dist/printed-representation.d.ts.map +1 -0
  84. package/dist/printed-representation.js +135 -0
  85. package/dist/problem-contract.d.ts +265 -0
  86. package/dist/problem-contract.d.ts.map +1 -0
  87. package/dist/problem-contract.js +25 -0
  88. package/dist/public-case.d.ts +15 -0
  89. package/dist/public-case.d.ts.map +1 -0
  90. package/dist/public-case.js +26 -0
  91. package/dist/received-documents.d.ts +35 -0
  92. package/dist/received-documents.d.ts.map +1 -0
  93. package/dist/received-documents.js +83 -0
  94. package/dist/sha256.d.ts +2 -0
  95. package/dist/sha256.d.ts.map +1 -0
  96. package/dist/sha256.js +6 -0
  97. package/dist/signed-document.d.ts +15 -0
  98. package/dist/signed-document.d.ts.map +1 -0
  99. package/dist/signed-document.js +57 -0
  100. package/dist/source-command-validation.d.ts +3 -0
  101. package/dist/source-command-validation.d.ts.map +1 -0
  102. package/dist/source-command-validation.js +14 -0
  103. package/dist/source-connection-activation.d.ts +18 -0
  104. package/dist/source-connection-activation.d.ts.map +1 -0
  105. package/dist/source-connection-activation.js +41 -0
  106. package/dist/source-connection-transport.d.ts +8 -0
  107. package/dist/source-connection-transport.d.ts.map +1 -0
  108. package/dist/source-connection-transport.js +8 -0
  109. package/dist/source-connection.d.ts +18 -0
  110. package/dist/source-connection.d.ts.map +1 -0
  111. package/dist/source-connection.js +35 -0
  112. package/dist/stamp-server-http-transport.d.ts +23 -0
  113. package/dist/stamp-server-http-transport.d.ts.map +1 -0
  114. package/dist/stamp-server-http-transport.js +179 -0
  115. package/dist/timbro-client.d.ts +124 -0
  116. package/dist/timbro-client.d.ts.map +1 -0
  117. package/dist/timbro-client.js +72 -0
  118. package/dist/timbro_fiscal_engine.js +239 -0
  119. package/dist/timbro_fiscal_engine_bg.wasm +0 -0
  120. package/dist/transport-contract.d.ts +16 -0
  121. package/dist/transport-contract.d.ts.map +1 -0
  122. package/dist/transport-contract.js +1 -0
  123. package/dist/webhook-delivery.d.ts +14 -0
  124. package/dist/webhook-delivery.d.ts.map +1 -0
  125. package/dist/webhook-delivery.js +32 -0
  126. package/dist/webhook-event.d.ts +2711 -0
  127. package/dist/webhook-event.d.ts.map +1 -0
  128. package/dist/webhook-event.js +15 -0
  129. package/dist/webhook-registration.d.ts +12 -0
  130. package/dist/webhook-registration.d.ts.map +1 -0
  131. package/dist/webhook-registration.js +37 -0
  132. package/dist/webhook-replay.d.ts +12 -0
  133. package/dist/webhook-replay.d.ts.map +1 -0
  134. package/dist/webhook-replay.js +27 -0
  135. package/dist/webhook-verification.d.ts +25 -0
  136. package/dist/webhook-verification.d.ts.map +1 -0
  137. package/dist/webhook-verification.js +53 -0
  138. package/dist/workspace-session-transport.d.ts +8 -0
  139. package/dist/workspace-session-transport.d.ts.map +1 -0
  140. package/dist/workspace-session-transport.js +11 -0
  141. package/dist/workspace.d.ts +74 -0
  142. package/dist/workspace.d.ts.map +1 -0
  143. package/dist/workspace.js +278 -0
  144. package/package.json +73 -0
package/README.md ADDED
@@ -0,0 +1,308 @@
1
+ # @timbro/invoices
2
+
3
+ Issue Dominican electronic invoices (e-CF) from your application, ERP, or POS with one configured client. Invoice issuance and payment collection have separate lifecycles. Use `@timbro/payments` when you also need Timbro to collect money through Checkout.
4
+
5
+ Rust owns the fiscal wire contract. This SDK uses generated operation bindings and validators at every HTTP boundary.
6
+
7
+ ```ts
8
+ import { createTimbroClient } from "@timbro/invoices";
9
+ import type { FiscalDocument } from "@timbro/invoices";
10
+
11
+ const credential = process.env.TIMBRO_CREDENTIAL;
12
+ if (credential === undefined || credential.trim() === "") {
13
+ throw new Error("TIMBRO_CREDENTIAL is required");
14
+ }
15
+
16
+ const document: FiscalDocument = {
17
+ kind: "type31",
18
+ snapshot: {
19
+ currency: "DOP",
20
+ incomeType: "01",
21
+ paymentType: "1",
22
+ buyer: { taxId: "101234567", legalName: "Example Buyer" },
23
+ lines: [{
24
+ sourceLineId: "line-1",
25
+ name: "Example product",
26
+ quantity: "1.00",
27
+ measurementUnit: "31",
28
+ unitPrice: "118.00",
29
+ billingIndicator: "1",
30
+ goodsOrServiceIndicator: "1",
31
+ }],
32
+ paymentAllocations: [{ method: "1", amount: "118.00" }],
33
+ },
34
+ };
35
+
36
+ const timbro = createTimbroClient({
37
+ baseUrl: "https://stamp.example.test",
38
+ authentication: { mode: "source_connection", credential },
39
+ });
40
+
41
+ const operation = await timbro.fiscalDocuments.issue({
42
+ source: {
43
+ id: "checkout-order-1001",
44
+ version: "v1",
45
+ },
46
+ document,
47
+ numberingInstruction: { kind: "centralAssignment" },
48
+ printedRepresentation: { profile: "receipt_80mm" },
49
+ });
50
+
51
+ const page = await timbro.fiscalDocuments.list({ limit: 20 });
52
+
53
+ const numbering = await timbro.fiscalNumbering.getReadiness();
54
+ const type31 = numbering.documents.e31;
55
+ const custody = await timbro.certificateCustody.getReadiness();
56
+ ```
57
+
58
+ The repository includes complete, runnable issuance examples for both supported integration styles:
59
+
60
+ - [`examples/fiscal-document.ts`](examples/fiscal-document.ts) uses the typed SDK
61
+ - [`examples/fiscal_document.py`](examples/fiscal_document.py) uses Python's standard-library HTTP client and the raw snake-case wire contract
62
+
63
+ Set `TIMBRO_BASE_URL`, `TIMBRO_CREDENTIAL`, and a unique `TIMBRO_SOURCE_ID` before running either
64
+ example. `TIMBRO_SOURCE_VERSION` defaults to `v1`. Run the TypeScript example with
65
+ `node packages/sdk/examples/fiscal-document.ts` on the repository's Node 24 runtime, or run the
66
+ Python example with `python3 packages/sdk/examples/fiscal_document.py`. Use a Source connection in
67
+ the intended fiscal environment because either command submits an issuance task.
68
+
69
+ The immutable Source identity is the `{ id, version }` tuple; `version` is an opaque trimmed string chosen by the Source system. Timbro computes and retains the canonical digest internally. The caller does not send a digest or an idempotency header. Repeating an older tuple recovers its original operation even after another version becomes current.
70
+
71
+ To replace a request rejected before numbering, submit corrected content with a new Source version and `predecessorOperationId` set to the rejected operation's `fiscalOperationId`. The predecessor must still be current. An accepted document requires a separate legal correction; an unknown outcome requires reconciliation. After authority rejection, replacement also requires the existing administrator authorization. A missing or stale predecessor returns `source_predecessor_conflict` without issuing again.
72
+
73
+ Inspect `operation.outcome.outcome`, `operation.signedDocument.status` and `operation.printedRepresentation.status` independently. Authority acceptance can precede XML/PDF availability. The SDK preserves these owning-contract facts and exposes no derived top-level `status` or `issued` shortcut. Both immediate and pending admission responses return the resource. [Spanish retry and recovery guide](../../docs/integrations/source-submission-recovery.md)
74
+
75
+ `fiscalDocuments.issue` is the one issuance task for ordinary documents and corrections. A
76
+ correction names both the affected Timbro operation and the original Source identity explicitly:
77
+
78
+ ```ts
79
+ await timbro.fiscalDocuments.issue({
80
+ source: { id: "odoo-credit-1002", version: "v1" },
81
+ action: {
82
+ kind: "creditNote",
83
+ correction: "correctAmounts",
84
+ affectedFiscalOperationId: original.fiscalOperationId,
85
+ originalSource: { id: "odoo-invoice-1001", version: "v3" },
86
+ reason: "The taxable amount was corrected",
87
+ },
88
+ document,
89
+ numberingInstruction: { kind: "centralAssignment" },
90
+ printedRepresentation: { profile: "a4" },
91
+ });
92
+ ```
93
+
94
+ All issuance task boundaries return a retained operation when fiscal evaluation rejects it; inspect `operation.outcome` and its diagnostics just as you would after `get` or a webhook. Exceptions remain reserved for malformed or unsupported input, authentication and authorization failures, conflicts, transport failures, and other cases where no modeled result can be returned.
95
+
96
+ `fiscalDocuments.get({ fiscalOperationId })` recovers an operation and its actor-facing outcome, returning `undefined` for a typed not-found response. `fiscalDocuments.findBySource({ source: { id, version } })` arbitrates by the caller's source identity. Public resources use camelCase, keep every amount as an exact decimal string, and expose `fiscalOperationId` separately from the fiscal authority identity (`outcome.fiscalIdentity`) and its fiscal number. The status vocabulary preserves `requested`, `processing`, `delayed`, `unavailable`, `verifying`, `issued`, `rejected`, and `actionRequired`. Fiscal numbering and certificate-custody readiness are separate tasks from issuance, and artifact retrieval is exposed through `fiscalArtifacts`.
97
+
98
+ `fiscalDocuments.getTiming({ fiscalOperationId })` returns the bounded diagnostic projection of timing contract version 4. `stages` names each step of the operation as a `TimingStageId` occurrence with its clock, bound, duration, and exclusive time; `TIMING_STAGE_IDS` lists every published id. `workClaims` lists each executing claim on the operation's work, `drainRuns` the drains that made those claims, and `readAt` is Timbro's database clock at the read, so a reader on another clock can measure its skew. These fields are optional in the types: a version 3 report still parses and carries none of them, so branch on `timingContractVersion`. The row lists name work `dueToSettlementMs` and Webhook `queuedToSettlementMs` by their endpoints, and expose `fiscalDeliveries`, `fiscalDeliveryAttempts`, and `fiscalDeliveryEvents` so `submitted`, `delivered`, and `bounced` remain distinct. `attemptDurationMs` measures the stamp-side interval from delivery claim through recorded settlement, including local preparation; it does not isolate provider time. Event rows correlate through `fiscalDeliveryId`, and their provider-created and stamp-received times remain separate. The report omits recipient addresses and provider identifiers.
99
+
100
+ When `operation.signedDocument.status` is `ready`, its `artifactKind` is `signed_complete_document` and its `artifactId` identifies the immutable artifact. Retrieve and verify it with `fiscalArtifacts.downloadSignedDocument({ fiscalOperationId: operation.fiscalOperationId })`.
101
+
102
+ An `outcome_unknown` submission remains `pending` while Timbro reconciles the same fiscal identity with DGII. Continue observing it without resubmitting the document. Only `intervention_required` means automatic reconciliation exhausted its bounded budget and an operator must take over.
103
+
104
+ `fiscalArtifacts.downloadPrintedRepresentation({ fiscalOperationId })` retrieves the operation-addressed immutable PDF and verifies every published identity header, profile/version, renderer identity, digest, signed-source digest, pagination-plan digest, length, page count, creation time, media type, and the actual bytes. The result exposes one content digest as `contentSha256`; storage keys and compatibility aliases are not exposed.
105
+
106
+ ### Share an already-issued receipt
107
+
108
+ The development contract in `0.7.0-next.30` lets the issuing Source share an accepted operation without issuing another invoice or sending email. Registry availability is a separate release requirement. Keep the returned reference in protected server-side storage and pass it through an authenticated service handoff:
109
+
110
+ ```ts
111
+ const receipt = await issuer.fiscalDocuments.shareReceipt({ fiscalOperationId });
112
+ const metadata = await receiver.fiscalReceipts.get({ receipt });
113
+ if (metadata?.printedRepresentation.status === "ready") {
114
+ const pdf = await receiver.fiscalReceipts.downloadPrintedRepresentation({ receipt });
115
+ // Deliver pdf.bytes through the receiving service's authorized receipt route.
116
+ }
117
+ ```
118
+
119
+ Both clients use the existing `createTimbroClient` setup. Receipt reads apply only the reference's bearer token, even if the receiving client normally uses workload authentication. The receiver obtains the verified issuer RNC, environment, Source revision, fiscal identity, DOP totals, acceptance timestamp, and PDF readiness. It receives neither XML nor diagnostics. A missing or revoked receipt returns `undefined`; a pending PDF returns `fiscal_artifact_not_found`. Use the [Spanish receipt guide](../../docs/integrations/source-receipts.md) for handoff and payment checks.
120
+
121
+ Source credentials can also operate the received-document namespace. The server infers the
122
+ Organization, Legal issuer, and Fiscal environment from that credential, so the list cannot be
123
+ widened with a tenant or issuer path parameter:
124
+
125
+ ```ts
126
+ const received = await timbro.receivedDocuments.list({ limit: 50, recovery: "pending" });
127
+ const document = await timbro.receivedDocuments.get({
128
+ fiscalReceptionId: received.data[0].fiscalReceptionId,
129
+ });
130
+ await timbro.receivedDocuments.respond({
131
+ fiscalReceptionId: document.summary.fiscalReceptionId,
132
+ response: { decision: "accepted" },
133
+ });
134
+ const signedXml = await timbro.receivedDocuments.downloadSignedDocument({
135
+ fiscalReceptionId: document.summary.fiscalReceptionId,
136
+ });
137
+ ```
138
+
139
+ `receivedDocuments.respond` accepts `accepted` or `rejected` with a non-blank `motive` for a
140
+ rejected response; an exact
141
+ replay returns the recorded response and a changed decision or motive raises a conflict. The
142
+ downloaded XML is retained inbound evidence and the SDK verifies its media type, length, and
143
+ SHA-256 digest. If the Evidence Vault is unavailable, the download returns the typed
144
+ `fiscal_artifact_unavailable` problem with HTTP 503.
145
+
146
+ Buyer delivery is independent of representation readiness:
147
+
148
+ ```ts
149
+ const delivery = await timbro.fiscalDeliveries.create({
150
+ fiscalOperationId: operation.fiscalOperationId,
151
+ recipientEmail: "buyer@example.test",
152
+ accountClaimUrl: "https://checkout.example.test/account?receipt=order-1001",
153
+ idempotencyKey: "checkout-order-1001-email",
154
+ });
155
+ ```
156
+
157
+ The email is in Spanish and names the Legal issuer and the e-NCF. `accountClaimUrl` is optional;
158
+ when present, the email also offers "Guardar en Cuenta Timbro" with that `https` URL. The URL
159
+ grants nothing by itself, because delivery emails are often forwarded.
160
+
161
+ ### Webhooks and recovery
162
+
163
+ An approved direct Source registers its HTTPS callback with the same scoped credential:
164
+
165
+ ```ts
166
+ const registration = await timbro.webhooks.register({
167
+ url: "https://erp.example.com/timbro/webhook",
168
+ idempotencyKey: "odoo-company-42-callback-v1",
169
+ });
170
+ ```
171
+
172
+ Persist that key before setup, and store `registration.signingSecret` in your server's secret
173
+ store. The exact key and body recover the same endpoint and original secret for 24 hours while
174
+ the endpoint remains active and unrotated. Later retries return the endpoint with a null secret;
175
+ they never issue another secret. A different registration key or changed body returns a conflict.
176
+ Hosted and provider-managed callbacks retain their own setup lifecycle.
177
+
178
+ The complete `node packages/sdk/examples/register-webhook.ts` example reads `TIMBRO_BASE_URL`,
179
+ `TIMBRO_CREDENTIAL`, `TIMBRO_CALLBACK_URL`, `TIMBRO_CALLBACK_REGISTRATION_KEY`, and
180
+ `TIMBRO_WEBHOOK_SECRET_FILE`. It saves the secret in a private file and prints only endpoint
181
+ metadata. See [Recibe avisos del e-CF](../../docs/integrations/source-webhooks.md) for setup and recovery.
182
+
183
+ After a receiver outage, inspect `webhookDeliveries.list` for pending or dead-letter deliveries
184
+ and replay selected retained fiscal events:
185
+
186
+ ```ts
187
+ const replay = await timbro.webhooks.replay({
188
+ webhookEndpointId: registration.webhookEndpoint.id,
189
+ eventIds: [delivery.webhook_event_id],
190
+ idempotencyKey: "odoo-company-42-replay-20261001",
191
+ });
192
+ ```
193
+
194
+ Persist the key and selection first. An exact retry returns the same `webhookReplayId` without
195
+ creating another delivery. Replay preserves the original event ID, sequence, and payload;
196
+ deduplicate it alongside automatic retries. Select 1–100 outbound fiscal events from your Source.
197
+ Supplier reception events are outside this method's scope.
198
+
199
+ The complete `node packages/sdk/examples/replay-webhook.ts` example reads `TIMBRO_BASE_URL`,
200
+ `TIMBRO_CREDENTIAL`, `TIMBRO_WEBHOOK_ENDPOINT_ID`, comma-separated `TIMBRO_WEBHOOK_EVENT_IDS`,
201
+ and `TIMBRO_WEBHOOK_REPLAY_KEY`. It prints replay metadata only.
202
+
203
+ Deliveries follow the [Standard Webhooks](https://www.standardwebhooks.com) contract. Each request
204
+ carries `webhook-id`, `webhook-timestamp`, and `webhook-signature`, and the signature covers
205
+ `<webhook-id>.<webhook-timestamp>.<body>`. Verify it against the exact request body bytes before
206
+ parsing. Do not parse, reserialize, or pretty-print the body first; the signed payload is the
207
+ original UTF-8 text.
208
+
209
+ `webhooks.verify` checks the headers and returns the typed event, so a receiver never parses an
210
+ unverified body:
211
+
212
+ ```ts
213
+ const event = await timbro.webhooks.verify({
214
+ body: requestBodyText,
215
+ headers: Object.fromEntries(request.headers),
216
+ secret: webhookSecret,
217
+ });
218
+ if (event.type === "source_connection.verification_requested") {
219
+ // Build and submit the signed activation proof before acknowledging this event.
220
+ // See examples/webhook-receiver.ts for the complete server-runtime flow.
221
+ throw new Error("activation verification must complete before acknowledgement");
222
+ }
223
+ const recovered =
224
+ event.type === "fiscal_reception.received" || event.type === "fiscal_reception.not_received"
225
+ ? undefined
226
+ : await timbro.fiscalDocuments.get({ fiscalOperationId: event.data.fiscal_operation_id });
227
+ ```
228
+
229
+ The operation's `source.id` and `source.version` identify the caller's retained invoice even if
230
+ the callback arrives before the caller records the issuance response. Retrieve current state
231
+ under the same Source credential, then apply it to that invoice through your existing processor.
232
+
233
+ A rejected delivery throws `WebhookVerificationError`, whose `rejection` names the cause:
234
+ `invalid_secret`, `missing_header`, `malformed_header`, `stale_timestamp`, `future_timestamp`,
235
+ `signature_mismatch`, `unreadable_envelope`, or `id_mismatch`. Answer a delivery you cannot trust
236
+ with a 4xx and no side effect. `invalid_secret` is the one exception: the secret you configured is
237
+ unusable, the delivery itself is intact, so answer 500 and let Timbro retry the event while you
238
+ repair the secret.
239
+
240
+ ```ts
241
+ import { WebhookVerificationError } from "@timbro/invoices";
242
+
243
+ try {
244
+ await timbro.webhooks.verify({ body, headers, secrets: [nextSecret, retiredSecret] });
245
+ } catch (cause) {
246
+ if (cause instanceof WebhookVerificationError) {
247
+ return new Response(cause.rejection, {
248
+ status: cause.rejection === "invalid_secret" ? 500 : 400,
249
+ });
250
+ }
251
+ throw cause;
252
+ }
253
+ ```
254
+
255
+ The signing secret is issued as `whsec_<base64>`; the HMAC key is the base64-decoded remainder, and
256
+ a secret that is not that shape is rejected rather than used as literal bytes. `webhook-signature`
257
+ carries one space-separated `v1,` entry per valid secret, and a delivery is verified when any entry
258
+ matches any secret you hold. A timestamp more than five minutes from the receiver's clock is refused
259
+ in both directions. `verify` refuses a delivery whose `webhook-id` is not the envelope `id`, and
260
+ that id is the key you deduplicate on. `sequence` stays a decimal string so JavaScript cannot lose
261
+ bigint precision. If an operation-event delivery is missed, recover the current actor-facing outcome
262
+ with `fiscalDocuments.get` using its operation ID.
263
+
264
+ Every public list returns one page: `object: list`, `data`, `hasMore`, and an opaque `nextCursor`
265
+ bound to the Organization and the list that minted it, down to the Webhook endpoint for a
266
+ delivery cursor.
267
+ Presenting a cursor anywhere else answers 400 `invalid_collection_cursor`. `limit` accepts 1 to
268
+ 100 and defaults to 20, and a multi-value filter repeats its parameter. `list` returns a single
269
+ page, while `listAll` follows every cursor for you:
270
+
271
+ ```ts
272
+ const page = await timbro.webhookDeliveries.list({
273
+ webhookEndpointId,
274
+ states: ["pending", "dead_lettered"],
275
+ limit: 50,
276
+ });
277
+
278
+ for await (const delivery of timbro.webhookDeliveries.listAll({ webhookEndpointId })) {
279
+ await reconcile(delivery);
280
+ }
281
+ ```
282
+
283
+ `webhookDeliveries`, `fiscalDocuments`, and `receivedDocuments` are the credential-scoped lists this
284
+ client wraps. The operation timeline is read with a Workspace session instead of a credential,
285
+ so a Workspace consumer reads those pages through its own session-authenticated request and walks
286
+ them with the exported `walkCollectionPages`:
287
+
288
+ ```ts
289
+ import { walkCollectionPages } from "@timbro/invoices";
290
+ import { zWorkspaceFiscalOperationPage } from "@timbro/invoices/generated";
291
+
292
+ for await (const operation of walkCollectionPages(async (cursor) => {
293
+ const query = cursor === undefined ? "?limit=100" : `?limit=100&cursor=${cursor}`;
294
+ const response = await fetch(
295
+ `${stampServerOrigin}/v1/organizations/${organizationId}/fiscal-operations${query}`,
296
+ { credentials: "include" },
297
+ );
298
+ return zWorkspaceFiscalOperationPage.parse(await response.json());
299
+ })) {
300
+ await render(operation);
301
+ }
302
+ ```
303
+
304
+ The walk throws a `FiscalError` when a page reports more resources without a cursor to resume
305
+ from, or returns the cursor it was read with, because neither page can be walked to the end of
306
+ the list.
307
+
308
+ Credentials belong on a trusted application server or native-assisted client. The package does not establish DGII approval, printer compatibility or legibility, hosted Checkout cutover, production capacity, or certification.
@@ -0,0 +1,9 @@
1
+ type HeaderFailure = (message: string) => never;
2
+ export declare function createArtifactHeaderReader(headers: ReadonlyMap<string, string>, subject?: string, fail?: HeaderFailure): {
3
+ readonly digest: (name: string) => string;
4
+ readonly positiveInteger: (name: string) => number;
5
+ readonly required: (name: string) => string;
6
+ readonly uuid: (name: string) => string;
7
+ };
8
+ export {};
9
+ //# sourceMappingURL=artifact-headers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"artifact-headers.d.ts","sourceRoot":"","sources":["../src/artifact-headers.ts"],"names":[],"mappings":"AAKA,KAAK,aAAa,GAAG,CAAC,OAAO,EAAE,MAAM,KAAK,KAAK,CAAC;AAEhD,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,WAAW,CAAC,MAAM,EAAE,MAAM,CAAC,EACpC,OAAO,SAAa,EACpB,IAAI,GAAE,aAA8B;4BAYd,MAAM,KAAG,MAAM;qCAgBN,MAAM,KAAG,MAAM;8BA1BtB,MAAM,KAAG,MAAM;0BAkBnB,MAAM,KAAG,MAAM;EAqBpC"}
@@ -0,0 +1,43 @@
1
+ const SHA256_PATTERN = /^[0-9a-f]{64}$/;
2
+ const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
3
+ const POSITIVE_INTEGER_PATTERN = /^[0-9]+$/;
4
+ const POSITIVE_INT32_MAX = 2_147_483_647;
5
+ export function createArtifactHeaderReader(headers, subject = "artifact", fail = throwTypeError) {
6
+ function required(name) {
7
+ const direct = headers.get(name);
8
+ const value = direct ?? Array.from(headers).find(([key]) => key.toLowerCase() === name.toLowerCase())?.[1];
9
+ if (value === undefined || value === "") {
10
+ fail(`Timbro omitted required ${subject} header ${name}`);
11
+ }
12
+ return value;
13
+ }
14
+ function digest(name) {
15
+ const value = required(name);
16
+ if (!SHA256_PATTERN.test(value)) {
17
+ fail(`Timbro returned an invalid digest header ${name}`);
18
+ }
19
+ return value;
20
+ }
21
+ function uuid(name) {
22
+ const value = required(name);
23
+ if (!UUID_PATTERN.test(value)) {
24
+ fail(`Timbro returned an invalid UUID header ${name}`);
25
+ }
26
+ return value;
27
+ }
28
+ function positiveInteger(name) {
29
+ const value = required(name);
30
+ if (!POSITIVE_INTEGER_PATTERN.test(value)) {
31
+ fail(`Timbro returned a non-integer header ${name}`);
32
+ }
33
+ const parsed = Number(value);
34
+ if (!Number.isSafeInteger(parsed) || parsed < 1 || parsed > POSITIVE_INT32_MAX) {
35
+ fail(`Timbro returned an out-of-range header ${name}`);
36
+ }
37
+ return parsed;
38
+ }
39
+ return { digest, positiveInteger, required, uuid };
40
+ }
41
+ function throwTypeError(message) {
42
+ throw new TypeError(message);
43
+ }
@@ -0,0 +1,13 @@
1
+ import type { HostedFiscalTenant } from "./fiscal-operation.ts";
2
+ import { type HostedImportResponse } from "./generated/index.ts";
3
+ import type { Client } from "./generated-operation-client.ts";
4
+ import { type ReadonlyCamelCase } from "./public-case.ts";
5
+ export type CertificateCustodyImportCommand = {
6
+ readonly certificateP12Base64: string;
7
+ readonly password: string;
8
+ readonly hosted: Pick<HostedFiscalTenant, "checkoutTenantId"> & Partial<Pick<HostedFiscalTenant, "environment">>;
9
+ readonly signal?: AbortSignal;
10
+ };
11
+ export type CertificateCustodyImportResult = ReadonlyCamelCase<HostedImportResponse>;
12
+ export declare function importHostedCertificateCustodyResource(client: Client, command: CertificateCustodyImportCommand): Promise<CertificateCustodyImportResult>;
13
+ //# sourceMappingURL=certificate-custody-import.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate-custody-import.d.ts","sourceRoot":"","sources":["../src/certificate-custody-import.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,KAAK,oBAAoB,EAAkC,MAAM,sBAAsB,CAAC;AACjG,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,KAAK,iBAAiB,EAAgB,MAAM,kBAAkB,CAAC;AAExE,MAAM,MAAM,+BAA+B,GAAG;IAC5C,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAC;IACtC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,kBAAkB,EAAE,kBAAkB,CAAC,GAC3D,OAAO,CAAC,IAAI,CAAC,kBAAkB,EAAE,aAAa,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B,CAAC;AAEF,MAAM,MAAM,8BAA8B,GAAG,iBAAiB,CAAC,oBAAoB,CAAC,CAAC;AAErF,wBAAsB,sCAAsC,CAC1D,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,+BAA+B,GACvC,OAAO,CAAC,8BAA8B,CAAC,CA0BzC"}
@@ -0,0 +1,30 @@
1
+ import { importHostedCertificateCustody } from "./generated/index.js";
2
+ import { throwGeneratedProblem } from "./generated-problem.js";
3
+ import { toPublicCase } from "./public-case.js";
4
+ export async function importHostedCertificateCustodyResource(client, command) {
5
+ if (command.certificateP12Base64.trim() === "") {
6
+ throw new TypeError("certificateP12Base64 must not be blank");
7
+ }
8
+ if (command.password.length === 0) {
9
+ throw new TypeError("password must not be blank");
10
+ }
11
+ if (command.hosted.checkoutTenantId.trim() === "") {
12
+ throw new TypeError("hosted.checkoutTenantId must not be blank");
13
+ }
14
+ const response = await importHostedCertificateCustody({
15
+ client,
16
+ body: {
17
+ checkout_tenant_id: command.hosted.checkoutTenantId,
18
+ certificate_p12_base64: command.certificateP12Base64,
19
+ password: command.password,
20
+ ...(command.hosted.environment === undefined
21
+ ? {}
22
+ : { environment: command.hosted.environment }),
23
+ },
24
+ ...(command.signal === undefined ? {} : { signal: command.signal }),
25
+ });
26
+ if (response.status !== 200) {
27
+ throwGeneratedProblem(response, "Certificate custody import failed");
28
+ }
29
+ return toPublicCase(response.body);
30
+ }
@@ -0,0 +1,6 @@
1
+ import { type CertificateCustodyReadiness as GeneratedCertificateCustodyReadiness } from "./generated/index.ts";
2
+ import type { Client } from "./generated-operation-client.ts";
3
+ import { type ReadonlyCamelCase } from "./public-case.ts";
4
+ export type CertificateCustodyReadiness = ReadonlyCamelCase<GeneratedCertificateCustodyReadiness>;
5
+ export declare function readCertificateCustodyReadinessResource(client: Client, signal: AbortSignal | undefined): Promise<CertificateCustodyReadiness>;
6
+ //# sourceMappingURL=certificate-custody-readiness.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"certificate-custody-readiness.d.ts","sourceRoot":"","sources":["../src/certificate-custody-readiness.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,2BAA2B,IAAI,oCAAoC,EAEzE,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,iCAAiC,CAAC;AAE9D,OAAO,EAAE,KAAK,iBAAiB,EAAgB,MAAM,kBAAkB,CAAC;AAExE,MAAM,MAAM,2BAA2B,GAAG,iBAAiB,CAAC,oCAAoC,CAAC,CAAC;AAElG,wBAAsB,uCAAuC,CAC3D,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,WAAW,GAAG,SAAS,GAC9B,OAAO,CAAC,2BAA2B,CAAC,CAStC"}
@@ -0,0 +1,13 @@
1
+ import { readCertificateCustodyReadiness, } from "./generated/index.js";
2
+ import { throwGeneratedProblem } from "./generated-problem.js";
3
+ import { toPublicCase } from "./public-case.js";
4
+ export async function readCertificateCustodyReadinessResource(client, signal) {
5
+ const response = await readCertificateCustodyReadiness({
6
+ client,
7
+ ...(signal === undefined ? {} : { signal }),
8
+ });
9
+ if (response.status !== 200) {
10
+ throwGeneratedProblem(response, "Certificate-custody readiness read failed");
11
+ }
12
+ return toPublicCase(response.body);
13
+ }
@@ -0,0 +1,13 @@
1
+ import { type CursorPage, type CursorPageWalkOptions } from "@timbro/protocol";
2
+ /** One page of a Timbro Collection, as every list operation returns it. */
3
+ export type CollectionPage<TResource> = CursorPage<TResource>;
4
+ export type CollectionWalkOptions = CursorPageWalkOptions;
5
+ /**
6
+ * Yields every resource in a Collection, following `next_cursor` until `has_more` is false.
7
+ *
8
+ * A page that reports more resources without a cursor, or that returns the cursor it was read
9
+ * with, cannot be walked to the end of the Collection, so the walk throws rather than stopping
10
+ * short of resources the caller asked for or replaying the page it already yielded.
11
+ */
12
+ export declare function walkCollectionPages<TResource>(readPage: (cursor: string | undefined, signal: AbortSignal | undefined) => Promise<CollectionPage<TResource>>, options?: CollectionWalkOptions): AsyncGenerator<TResource, void, undefined>;
13
+ //# sourceMappingURL=collection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collection.d.ts","sourceRoot":"","sources":["../src/collection.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,UAAU,EAEf,KAAK,qBAAqB,EAE3B,MAAM,kBAAkB,CAAC;AAG1B,2EAA2E;AAC3E,MAAM,MAAM,cAAc,CAAC,SAAS,IAAI,UAAU,CAAC,SAAS,CAAC,CAAC;AAC9D,MAAM,MAAM,qBAAqB,GAAG,qBAAqB,CAAC;AAE1D;;;;;;GAMG;AACH,wBAAuB,mBAAmB,CAAC,SAAS,EAClD,QAAQ,EAAE,CACR,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,MAAM,EAAE,WAAW,GAAG,SAAS,KAC5B,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,EACvC,OAAO,CAAC,EAAE,qBAAqB,GAC9B,cAAc,CAAC,SAAS,EAAE,IAAI,EAAE,SAAS,CAAC,CAc5C"}
@@ -0,0 +1,21 @@
1
+ import { CursorPageWalkError, walkCursorPages, } from "@timbro/protocol";
2
+ import { FiscalError } from "./fiscal-error.js";
3
+ /**
4
+ * Yields every resource in a Collection, following `next_cursor` until `has_more` is false.
5
+ *
6
+ * A page that reports more resources without a cursor, or that returns the cursor it was read
7
+ * with, cannot be walked to the end of the Collection, so the walk throws rather than stopping
8
+ * short of resources the caller asked for or replaying the page it already yielded.
9
+ */
10
+ export async function* walkCollectionPages(readPage, options) {
11
+ try {
12
+ yield* walkCursorPages(readPage, options);
13
+ }
14
+ catch (cause) {
15
+ if (!(cause instanceof CursorPageWalkError)) {
16
+ throw cause;
17
+ }
18
+ // biome-ignore lint/style/useErrorCause: FiscalError already exposes the bounded protocol failure detail.
19
+ throw new FiscalError(cause.message, { failure: cause.rejection === "aborted" ? "cancelled" : "server_processing" }, { cause });
20
+ }
21
+ }
@@ -0,0 +1,74 @@
1
+ import { type CreateDirectConnectionRequest, type DirectConnectionPreviewResource, type DirectConnectionRequestState } from "./generated/index.ts";
2
+ import type { Client } from "./generated-operation-client.ts";
3
+ export type DirectConnectionEnvironment = CreateDirectConnectionRequest["environment"];
4
+ export type DirectConnectionCreateCommand = {
5
+ readonly clientRequestId: string;
6
+ readonly installationId: string;
7
+ readonly databaseId: string;
8
+ readonly companyId: string;
9
+ readonly companyName: string;
10
+ readonly companyTaxId: string;
11
+ readonly softwareVersion: string;
12
+ readonly environment: DirectConnectionEnvironment;
13
+ /** A customer-managed Source bearer provisioned before authorization begins. */
14
+ readonly credential: string;
15
+ readonly pollingSecret: string;
16
+ };
17
+ export type DirectConnectionRequestCommand = DirectConnectionCreateCommand;
18
+ export type DirectConnectionApprovalCommand = {
19
+ readonly legalIssuerId: string;
20
+ };
21
+ export type DirectConnectionRequest = {
22
+ readonly requestId: string;
23
+ readonly userCode: string;
24
+ readonly verificationUri: string;
25
+ readonly expiresAt: string;
26
+ readonly pollingSecret: string;
27
+ };
28
+ export type DirectConnectionPoll = {
29
+ readonly requestId: string;
30
+ readonly state: DirectConnectionRequestState;
31
+ readonly sourceConnectionId?: string | null | undefined;
32
+ readonly expiresAt: string;
33
+ };
34
+ export type DirectConnectionPreview = {
35
+ readonly requestId: string;
36
+ readonly installationId: string;
37
+ readonly companyId: string;
38
+ readonly companyName: string;
39
+ readonly companyTaxId: string;
40
+ readonly softwareVersion: string;
41
+ readonly environment: DirectConnectionPreviewResource["environment"];
42
+ readonly state: DirectConnectionRequestState;
43
+ readonly expiresAt: string;
44
+ };
45
+ export type DirectConnectionApproval = {
46
+ readonly requestId: string;
47
+ readonly sourceConnectionId: string;
48
+ readonly state: DirectConnectionRequestState;
49
+ };
50
+ export type DirectConnectionConfirmation = {
51
+ readonly sourceConnectionId: string;
52
+ readonly confirmed: boolean;
53
+ };
54
+ export type DirectConnectionClientOptions = {
55
+ readonly baseUrl: string;
56
+ readonly fetch?: typeof globalThis.fetch;
57
+ };
58
+ export type DirectConnectionClient = {
59
+ readonly create: (body: DirectConnectionCreateCommand) => Promise<DirectConnectionRequest>;
60
+ readonly poll: (requestId: string, pollingSecret: string) => Promise<DirectConnectionPoll>;
61
+ readonly cancel: (requestId: string, pollingSecret: string) => Promise<void>;
62
+ readonly confirm: (sourceConnectionId: string, credential: string) => Promise<DirectConnectionConfirmation>;
63
+ };
64
+ /** Generates the customer-managed bearer used by a direct Source connection. */
65
+ export declare function generateDirectConnectionCredential(environment: DirectConnectionEnvironment): string;
66
+ /** Creates the unauthenticated create/poll/cancel client and credential-scoped confirm call. */
67
+ export declare function createDirectConnectionClient(options: DirectConnectionClientOptions): DirectConnectionClient;
68
+ export type DirectConnectionWorkspaceOperations = {
69
+ readonly preview: (organizationId: string, userCode: string) => Promise<DirectConnectionPreview>;
70
+ readonly approve: (organizationId: string, userCode: string, body: DirectConnectionApprovalCommand) => Promise<DirectConnectionApproval>;
71
+ };
72
+ /** Adds Workspace-session preview and approval to the authenticated Workspace client. */
73
+ export declare function createDirectConnectionWorkspaceOperations(client: Client): DirectConnectionWorkspaceOperations;
74
+ //# sourceMappingURL=direct-connection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"direct-connection.d.ts","sourceRoot":"","sources":["../src/direct-connection.ts"],"names":[],"mappings":"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"}