@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
@@ -0,0 +1,192 @@
1
+ import { approveDirectConnectionRequest, cancelDirectConnectionRequest, confirmDirectConnection, createDirectConnectionRequest, pollDirectConnectionRequest, previewDirectConnectionRequest, } from "./generated/index.js";
2
+ import { createGeneratedOperationClient } from "./generated-operation-client.js";
3
+ import { throwGeneratedProblem } from "./generated-problem.js";
4
+ import { createStampServerHttpTransport } from "./stamp-server-http-transport.js";
5
+ const CREDENTIAL_KEY_BYTES = 16;
6
+ const CREDENTIAL_SECRET_BYTES = 32;
7
+ /** Generates the customer-managed bearer used by a direct Source connection. */
8
+ export function generateDirectConnectionCredential(environment) {
9
+ const key = new Uint8Array(CREDENTIAL_KEY_BYTES);
10
+ const secret = new Uint8Array(CREDENTIAL_SECRET_BYTES);
11
+ globalThis.crypto.getRandomValues(key);
12
+ globalThis.crypto.getRandomValues(secret);
13
+ return `tmb_${environment}_${encodeBase64Url(key)}.${encodeBase64Url(secret)}`;
14
+ }
15
+ /** Creates the unauthenticated create/poll/cancel client and credential-scoped confirm call. */
16
+ export function createDirectConnectionClient(options) {
17
+ const transportOptions = {
18
+ stampServerOrigin: options.baseUrl,
19
+ ...(options.fetch === undefined ? {} : { fetch: options.fetch }),
20
+ };
21
+ const anonymousClient = createGeneratedOperationClient(createStampServerHttpTransport({ ...transportOptions, authentication: { mode: "none" } }));
22
+ return {
23
+ create: async (body) => toRequest(await createDirectConnectionRequestResource(anonymousClient, await toGeneratedCreate(body))),
24
+ poll: (requestId, pollingSecret) => pollDirectConnectionRequestResource(anonymousClient, requestId, pollingSecret),
25
+ cancel: (requestId, pollingSecret) => cancelDirectConnectionRequestResource(anonymousClient, requestId, pollingSecret),
26
+ confirm: (sourceConnectionId, credential) => {
27
+ const credentialClient = createGeneratedOperationClient(createStampServerHttpTransport({
28
+ ...transportOptions,
29
+ authentication: { mode: "source_connection", credential },
30
+ }));
31
+ return confirmDirectConnectionResource(credentialClient, sourceConnectionId);
32
+ },
33
+ };
34
+ }
35
+ /** Adds Workspace-session preview and approval to the authenticated Workspace client. */
36
+ export function createDirectConnectionWorkspaceOperations(client) {
37
+ return {
38
+ preview: async (organizationId, userCode) => {
39
+ const response = await previewDirectConnectionRequest({
40
+ client,
41
+ path: { organization_id: organizationId, user_code: userCode },
42
+ });
43
+ if (response.status !== 200) {
44
+ throwGeneratedProblem(response, "Direct connection preview failed");
45
+ }
46
+ return toPreview(response.body);
47
+ },
48
+ approve: async (organizationId, userCode, body) => {
49
+ const response = await approveDirectConnectionRequest({
50
+ client,
51
+ path: { organization_id: organizationId, user_code: userCode },
52
+ body: { legal_issuer_id: body.legalIssuerId },
53
+ });
54
+ if (response.status !== 201) {
55
+ throwGeneratedProblem(response, "Direct connection approval failed");
56
+ }
57
+ return toApproval(response.body);
58
+ },
59
+ };
60
+ }
61
+ async function toGeneratedCreate(body) {
62
+ const { environment, keyId, secret } = parseCredential(body.credential, body.environment);
63
+ const digest = await globalThis.crypto.subtle.digest("SHA-256", new TextEncoder().encode(secret));
64
+ return {
65
+ client_request_id: body.clientRequestId,
66
+ installation_id: body.installationId,
67
+ database_id: body.databaseId,
68
+ company_id: body.companyId,
69
+ company_name: body.companyName,
70
+ company_tax_id: body.companyTaxId,
71
+ software_version: body.softwareVersion,
72
+ environment,
73
+ credential_proof: {
74
+ key_id: keyId,
75
+ secret_sha256: encodeBase64Url(new Uint8Array(digest)),
76
+ },
77
+ polling_secret: body.pollingSecret,
78
+ };
79
+ }
80
+ function parseCredential(credential, expectedEnvironment) {
81
+ const match = /^tmb_(sandbox|certification|production)_([A-Za-z0-9_-]{22})\.([A-Za-z0-9_-]{43})$/.exec(credential);
82
+ if (match === null || match[1] !== expectedEnvironment) {
83
+ throw new TypeError("credential must use the exact Timbro Source bearer grammar and environment");
84
+ }
85
+ const [, environment, keyId, secret] = match;
86
+ if (keyId === undefined || secret === undefined) {
87
+ throw new TypeError("credential is malformed");
88
+ }
89
+ const keyBytes = decodeBase64Url(keyId);
90
+ const secretBytes = decodeBase64Url(secret);
91
+ if (keyBytes.length !== CREDENTIAL_KEY_BYTES ||
92
+ secretBytes.length !== CREDENTIAL_SECRET_BYTES ||
93
+ encodeBase64Url(keyBytes) !== keyId ||
94
+ encodeBase64Url(secretBytes) !== secret) {
95
+ throw new TypeError("credential must use canonical base64url segments");
96
+ }
97
+ return {
98
+ environment: environment,
99
+ keyId,
100
+ secret,
101
+ };
102
+ }
103
+ function encodeBase64Url(bytes) {
104
+ let binary = "";
105
+ for (const byte of bytes) {
106
+ binary += String.fromCharCode(byte);
107
+ }
108
+ return globalThis.btoa(binary).replaceAll("+", "-").replaceAll("/", "_").replace(/[=]+$/, "");
109
+ }
110
+ function decodeBase64Url(value) {
111
+ const padding = "=".repeat((4 - (value.length % 4)) % 4);
112
+ const binary = globalThis.atob(value.replaceAll("-", "+").replaceAll("_", "/") + padding);
113
+ return Uint8Array.from(binary, (character) => character.charCodeAt(0));
114
+ }
115
+ async function createDirectConnectionRequestResource(client, body) {
116
+ const response = await createDirectConnectionRequest({ client, body });
117
+ if (response.status !== 201) {
118
+ throwGeneratedProblem(response, "Direct connection request failed");
119
+ }
120
+ return response.body;
121
+ }
122
+ function toRequest(resource) {
123
+ return {
124
+ requestId: resource.request_id,
125
+ userCode: resource.user_code,
126
+ verificationUri: resource.verification_uri,
127
+ expiresAt: resource.expires_at,
128
+ pollingSecret: resource.polling_secret,
129
+ };
130
+ }
131
+ function toPoll(resource) {
132
+ return {
133
+ requestId: resource.request_id,
134
+ state: resource.state,
135
+ sourceConnectionId: resource.source_connection_id,
136
+ expiresAt: resource.expires_at,
137
+ };
138
+ }
139
+ function toPreview(resource) {
140
+ return {
141
+ requestId: resource.request_id,
142
+ installationId: resource.installation_id,
143
+ companyId: resource.company_id,
144
+ companyName: resource.company_name,
145
+ companyTaxId: resource.company_tax_id,
146
+ softwareVersion: resource.software_version,
147
+ environment: resource.environment,
148
+ state: resource.state,
149
+ expiresAt: resource.expires_at,
150
+ };
151
+ }
152
+ function toApproval(resource) {
153
+ return {
154
+ requestId: resource.request_id,
155
+ sourceConnectionId: resource.source_connection_id,
156
+ state: resource.state,
157
+ };
158
+ }
159
+ async function pollDirectConnectionRequestResource(client, requestId, pollingSecret) {
160
+ const response = await pollDirectConnectionRequest({
161
+ client,
162
+ path: { request_id: requestId },
163
+ headers: { "X-Timbro-Polling-Secret": pollingSecret },
164
+ });
165
+ if (response.status !== 200) {
166
+ throwGeneratedProblem(response, "Direct connection polling failed");
167
+ }
168
+ return toPoll(response.body);
169
+ }
170
+ async function cancelDirectConnectionRequestResource(client, requestId, pollingSecret) {
171
+ const response = await cancelDirectConnectionRequest({
172
+ client,
173
+ path: { request_id: requestId },
174
+ headers: { "X-Timbro-Polling-Secret": pollingSecret },
175
+ });
176
+ if (response.status !== 204) {
177
+ throwGeneratedProblem(response, "Direct connection cancellation failed");
178
+ }
179
+ }
180
+ async function confirmDirectConnectionResource(client, sourceConnectionId) {
181
+ const response = await confirmDirectConnection({
182
+ client,
183
+ path: { source_connection_id: sourceConnectionId },
184
+ });
185
+ if (response.status !== 200) {
186
+ throwGeneratedProblem(response, "Direct connection confirmation failed");
187
+ }
188
+ return toConfirmation(response.body);
189
+ }
190
+ function toConfirmation(resource) {
191
+ return { sourceConnectionId: resource.source_connection_id, confirmed: resource.confirmed };
192
+ }
@@ -0,0 +1,15 @@
1
+ /** Options for the server-only Node document runtime bridge. */
2
+ export type NodeDocumentRuntimeOptions = {
3
+ /** Override the generated Wasm glue module, primarily for isolated hosts and tests. */
4
+ readonly glueModuleUrl?: string | URL;
5
+ /** Override the generated Wasm binary, primarily for isolated hosts and tests. */
6
+ readonly wasmModuleUrl?: string | URL;
7
+ };
8
+ /**
9
+ * Loads the generated browser-fiscal Wasm glue and binary for a Node host.
10
+ *
11
+ * This module is an explicit server-only package entrypoint. Do not import it from browser code:
12
+ * it imports Node's filesystem and URL modules by design.
13
+ */
14
+ export declare function createNodeDocumentRuntime(options?: NodeDocumentRuntimeOptions): (requestJson: string) => Promise<string>;
15
+ //# sourceMappingURL=document-node.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-node.d.ts","sourceRoot":"","sources":["../src/document-node.ts"],"names":[],"mappings":"AASA,gEAAgE;AAChE,MAAM,MAAM,0BAA0B,GAAG;IACvC,uFAAuF;IACvF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;IACtC,kFAAkF;IAClF,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CACvC,CAAC;AAOF;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,0BAA+B,GACvC,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,CAAC,CAyB1C"}
@@ -0,0 +1,67 @@
1
+ // biome-ignore-all lint/correctness/noNodejsModules: this is an explicitly server-only bridge.
2
+ // biome-ignore-all lint/correctness/useImportExtensions: package build rewrites TypeScript imports.
3
+ // biome-ignore-all lint/security/noSecrets: this module handles only public Wasm evaluator assets.
4
+ // biome-ignore-all lint/correctness/noUnusedVariables: runtime shape is validated at the bridge boundary.
5
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
6
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
7
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
8
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
9
+ });
10
+ }
11
+ return path;
12
+ };
13
+ import { readFile } from "node:fs/promises";
14
+ import { fileURLToPath } from "node:url";
15
+ import { FiscalDocumentEvaluatorError } from "./document.js";
16
+ /**
17
+ * Loads the generated browser-fiscal Wasm glue and binary for a Node host.
18
+ *
19
+ * This module is an explicit server-only package entrypoint. Do not import it from browser code:
20
+ * it imports Node's filesystem and URL modules by design.
21
+ */
22
+ export function createNodeDocumentRuntime(options = {}) {
23
+ let engine;
24
+ return async (requestJson) => {
25
+ try {
26
+ engine ??= loadEngine(options);
27
+ const loaded = await engine;
28
+ const response = loaded.evaluateFiscalDocument(requestJson);
29
+ if (typeof response !== "string") {
30
+ throw new Error("the fiscal document engine returned a non-string response");
31
+ }
32
+ return response;
33
+ }
34
+ catch (cause) {
35
+ if (cause instanceof FiscalDocumentEvaluatorError) {
36
+ throw cause;
37
+ }
38
+ const error = new FiscalDocumentEvaluatorError(cause instanceof Error
39
+ ? `the Node fiscal document runtime is unavailable: ${cause.message}`
40
+ : "the Node fiscal document runtime is unavailable", "runtime_unavailable");
41
+ error.cause = cause;
42
+ throw error;
43
+ }
44
+ };
45
+ }
46
+ async function loadEngine(options) {
47
+ const glueUrl = resolveModuleUrl(options.glueModuleUrl ?? new URL("./timbro_fiscal_engine.js", import.meta.url));
48
+ const wasmUrl = resolveModuleUrl(options.wasmModuleUrl ?? new URL("./timbro_fiscal_engine_bg.wasm", import.meta.url));
49
+ const loaded = await import(__rewriteRelativeImportExtension(glueUrl.href));
50
+ if (!isFiscalEngineGlue(loaded)) {
51
+ throw new Error("the fiscal document glue module is invalid");
52
+ }
53
+ const wasmBytes = await readFile(fileURLToPath(wasmUrl));
54
+ await loaded.default({ module_or_path: wasmBytes });
55
+ return loaded;
56
+ }
57
+ function resolveModuleUrl(value) {
58
+ return value instanceof URL ? value : new URL(value, import.meta.url);
59
+ }
60
+ function isFiscalEngineGlue(candidate) {
61
+ return (typeof candidate === "object" &&
62
+ candidate !== null &&
63
+ "default" in candidate &&
64
+ typeof candidate.default === "function" &&
65
+ "evaluateFiscalDocument" in candidate &&
66
+ typeof candidate.evaluateFiscalDocument === "function");
67
+ }
@@ -0,0 +1,30 @@
1
+ import type { SourceDocumentEvaluationResponse } from "./generated/index.ts";
2
+ export declare const DOCUMENT_WORKER_PROTOCOL: "timbro.fiscal-document-worker.v1";
3
+ export declare const DOCUMENT_EVALUATION_PROTOCOL: "timbro.fiscal-document-evaluation.v1";
4
+ export type DocumentWorkerCommand = {
5
+ readonly type: "evaluate";
6
+ readonly request_id: string;
7
+ readonly request: string;
8
+ } | {
9
+ readonly type: "initialize";
10
+ readonly glue_module_url: string;
11
+ readonly wasm_module_url: string;
12
+ };
13
+ export declare function decodeDocumentWorkerResponse(candidate: unknown, expectedRequestId: string): {
14
+ readonly outcome: "decoded";
15
+ readonly response: SourceDocumentEvaluationResponse;
16
+ } | {
17
+ readonly outcome: "protocol_mismatch";
18
+ readonly detail: string;
19
+ };
20
+ export declare function decodeDocumentWorkerEvent(candidate: unknown, expectedWorkerRequestId: string | null, expectedEvaluatorRequestId: string | null): {
21
+ readonly outcome: "evaluated";
22
+ readonly response: SourceDocumentEvaluationResponse;
23
+ } | {
24
+ readonly outcome: "failed";
25
+ readonly detail: string;
26
+ } | {
27
+ readonly outcome: "protocol_mismatch";
28
+ readonly detail: string;
29
+ };
30
+ //# sourceMappingURL=document-worker-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-worker-protocol.d.ts","sourceRoot":"","sources":["../src/document-worker-protocol.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gCAAgC,EAAE,MAAM,sBAAsB,CAAC;AAM7E,eAAO,MAAM,wBAAwB,EAAG,kCAA2C,CAAC;AACpF,eAAO,MAAM,4BAA4B,EAAG,sCAA+C,CAAC;AAO5F,MAAM,MAAM,qBAAqB,GAC7B;IACE,QAAQ,CAAC,IAAI,EAAE,UAAU,CAAC;IAC1B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC1B,GACD;IACE,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;CAClC,CAAC;AAEN,wBAAgB,4BAA4B,CAC1C,SAAS,EAAE,OAAO,EAClB,iBAAiB,EAAE,MAAM,GAEvB;IAAE,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,gCAAgC,CAAA;CAAE,GACpF;IAAE,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA0BrE;AAgGD,wBAAgB,yBAAyB,CACvC,SAAS,EAAE,OAAO,EAClB,uBAAuB,EAAE,MAAM,GAAG,IAAI,EACtC,0BAA0B,EAAE,MAAM,GAAG,IAAI,GAEvC;IAAE,QAAQ,CAAC,OAAO,EAAE,WAAW,CAAC;IAAC,QAAQ,CAAC,QAAQ,EAAE,gCAAgC,CAAA;CAAE,GACtF;IAAE,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACvD;IAAE,QAAQ,CAAC,OAAO,EAAE,mBAAmB,CAAC;IAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CA+CrE"}
@@ -0,0 +1,103 @@
1
+ import { zEvaluatedSourceDocumentResponse, zRejectedSourceDocumentResponse, } from "./generated/index.js";
2
+ export const DOCUMENT_WORKER_PROTOCOL = "timbro.fiscal-document-worker.v1";
3
+ export const DOCUMENT_EVALUATION_PROTOCOL = "timbro.fiscal-document-evaluation.v1";
4
+ const FISCAL_DOCUMENT_ENGINE_NAME = "timbro-fiscal-engine";
5
+ const FISCAL_DOCUMENT_RULES_VERSION = "timbro.fiscal-document-rules.v2";
6
+ const SHA256_PATTERN = /^[0-9a-f]{64}$/u;
7
+ const MONEY_PATTERN = /^(?:0|[1-9][0-9]*)\.[0-9]{2}$/u;
8
+ const DOCUMENT_PATH_PATTERN = /^\/document(?:\/[A-Za-z0-9_-]+)*$/u;
9
+ export function decodeDocumentWorkerResponse(candidate, expectedRequestId) {
10
+ const evaluated = zEvaluatedSourceDocumentResponse.safeParse(candidate);
11
+ if (evaluated.success && evaluated.data.outcome === "evaluated") {
12
+ const response = evaluated.data;
13
+ if (!(hasCommonIdentity(response, expectedRequestId, true) && hasValidTotals(response.totals))) {
14
+ return mismatch("the evaluated fiscal document response is incomplete or has an unexpected identity");
15
+ }
16
+ return { outcome: "decoded", response: response };
17
+ }
18
+ const rejected = zRejectedSourceDocumentResponse.safeParse(candidate);
19
+ if (rejected.success && rejected.data.outcome === "rejected") {
20
+ const response = rejected.data;
21
+ if (!(hasCommonIdentity(response, expectedRequestId, false) && hasProblems(response.problems))) {
22
+ return mismatch("the rejected fiscal document response is incomplete or has an unexpected identity");
23
+ }
24
+ return { outcome: "decoded", response: response };
25
+ }
26
+ return mismatch("the fiscal document evaluator returned an invalid response");
27
+ }
28
+ function isSha256(candidate) {
29
+ return typeof candidate === "string" && SHA256_PATTERN.test(candidate);
30
+ }
31
+ function hasCommonIdentity(response, expectedRequestId, requireHash) {
32
+ return (response.protocol === DOCUMENT_EVALUATION_PROTOCOL &&
33
+ response.request_id === expectedRequestId &&
34
+ response.engine.name === FISCAL_DOCUMENT_ENGINE_NAME &&
35
+ response.engine.version.length > 0 &&
36
+ response.rules_version === FISCAL_DOCUMENT_RULES_VERSION &&
37
+ (requireHash
38
+ ? isSha256(response.canonical_input_sha256)
39
+ : response.canonical_input_sha256 === undefined || isSha256(response.canonical_input_sha256)));
40
+ }
41
+ function hasProblems(problems) {
42
+ return (problems.length > 0 &&
43
+ problems.every((problem) => DOCUMENT_PATH_PATTERN.test(problem.path) &&
44
+ problem.code.length > 0 &&
45
+ problem.message.length > 0));
46
+ }
47
+ function hasValidTotals(totals) {
48
+ return ([totals.net, totals.tax, totals.total, totals.non_billable].every(isMoney) &&
49
+ totals.lines.length > 0 &&
50
+ totals.lines.every((line) => line.source_line_id.length > 0 && [line.net, line.tax, line.total].every(isMoney)));
51
+ }
52
+ function isMoney(value) {
53
+ return MONEY_PATTERN.test(value);
54
+ }
55
+ function mismatch(detail) {
56
+ return { outcome: "protocol_mismatch", detail };
57
+ }
58
+ export function decodeDocumentWorkerEvent(candidate, expectedWorkerRequestId, expectedEvaluatorRequestId) {
59
+ if (typeof candidate !== "object" || candidate === null) {
60
+ return {
61
+ outcome: "protocol_mismatch",
62
+ detail: "the fiscal document worker returned a malformed message",
63
+ };
64
+ }
65
+ const event = candidate;
66
+ if (event.protocol !== DOCUMENT_WORKER_PROTOCOL || event.request_id !== expectedWorkerRequestId) {
67
+ return {
68
+ outcome: "protocol_mismatch",
69
+ detail: "the fiscal document worker returned an unexpected identity",
70
+ };
71
+ }
72
+ if (event.type === "failed") {
73
+ if (typeof event.detail !== "string" || event.detail.length === 0) {
74
+ return {
75
+ outcome: "protocol_mismatch",
76
+ detail: "the fiscal document worker returned an invalid failure",
77
+ };
78
+ }
79
+ return { outcome: "failed", detail: event.detail };
80
+ }
81
+ if (event.type !== "evaluated") {
82
+ return {
83
+ outcome: "protocol_mismatch",
84
+ detail: "the fiscal document worker returned an unknown event",
85
+ };
86
+ }
87
+ if (expectedEvaluatorRequestId === null) {
88
+ return { outcome: "protocol_mismatch", detail: "the evaluated worker event has no request id" };
89
+ }
90
+ if (typeof event.response !== "object" ||
91
+ event.response === null ||
92
+ // biome-ignore lint/complexity/useLiteralKeys: response is narrowed from an unknown wire record.
93
+ typeof event.response["request_id"] !== "string") {
94
+ return {
95
+ outcome: "protocol_mismatch",
96
+ detail: "the evaluated worker event has no response request id",
97
+ };
98
+ }
99
+ const decoded = decodeDocumentWorkerResponse(event.response, expectedEvaluatorRequestId);
100
+ return decoded.outcome === "decoded"
101
+ ? { outcome: "evaluated", response: decoded.response }
102
+ : decoded;
103
+ }
@@ -0,0 +1,2 @@
1
+ export declare function installDocumentWorker(): void;
2
+ //# sourceMappingURL=document-worker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document-worker.d.ts","sourceRoot":"","sources":["../src/document-worker.ts"],"names":[],"mappings":"AAYA,wBAAgB,qBAAqB,IAAI,IAAI,CAI5C"}
@@ -0,0 +1,71 @@
1
+ var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
2
+ if (typeof path === "string" && /^\.\.?\//.test(path)) {
3
+ return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
4
+ return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
5
+ });
6
+ }
7
+ return path;
8
+ };
9
+ import { DOCUMENT_WORKER_PROTOCOL, } from "./document-worker-protocol.js";
10
+ let engine;
11
+ export function installDocumentWorker() {
12
+ addEventListener("message", (event) => {
13
+ void serve(event.data);
14
+ });
15
+ }
16
+ if (typeof addEventListener === "function" && typeof postMessage === "function") {
17
+ installDocumentWorker();
18
+ }
19
+ async function serve(command) {
20
+ if (command.type === "initialize") {
21
+ engine = loadEngine(command.glue_module_url, command.wasm_module_url);
22
+ return;
23
+ }
24
+ if (engine === undefined) {
25
+ publishFailure(command.request_id, "the fiscal document worker was not initialized");
26
+ return;
27
+ }
28
+ try {
29
+ const loaded = await engine;
30
+ const responseJson = loaded.evaluateFiscalDocument(command.request);
31
+ if (typeof responseJson !== "string") {
32
+ publishFailure(command.request_id, "the fiscal document engine returned a non-string response");
33
+ return;
34
+ }
35
+ const response = JSON.parse(responseJson);
36
+ publish({
37
+ protocol: DOCUMENT_WORKER_PROTOCOL,
38
+ type: "evaluated",
39
+ request_id: command.request_id,
40
+ response,
41
+ });
42
+ }
43
+ catch (failure) {
44
+ publishFailure(command.request_id, describeFailure(failure));
45
+ }
46
+ }
47
+ async function loadEngine(glueModuleUrl, wasmModuleUrl) {
48
+ const loaded = await import(__rewriteRelativeImportExtension(/* @vite-ignore */ glueModuleUrl));
49
+ if (!isFiscalEngineGlue(loaded)) {
50
+ throw new Error("the fiscal document glue module is invalid");
51
+ }
52
+ await loaded.default({ module_or_path: wasmModuleUrl });
53
+ return loaded;
54
+ }
55
+ function isFiscalEngineGlue(candidate) {
56
+ return (typeof candidate === "object" &&
57
+ candidate !== null &&
58
+ "default" in candidate &&
59
+ typeof candidate.default === "function" &&
60
+ "evaluateFiscalDocument" in candidate &&
61
+ typeof candidate.evaluateFiscalDocument === "function");
62
+ }
63
+ function publish(event) {
64
+ postMessage(event);
65
+ }
66
+ function publishFailure(request_id, detail) {
67
+ publish({ protocol: DOCUMENT_WORKER_PROTOCOL, type: "failed", request_id, detail });
68
+ }
69
+ function describeFailure(failure) {
70
+ return failure instanceof Error ? failure.message : "the fiscal document evaluator failed";
71
+ }
@@ -0,0 +1,38 @@
1
+ export type { SourceDocumentEvaluationResponse, SourceSalesDocumentDraft, } from "./generated/index.ts";
2
+ import type { SourceDocumentEvaluationResponse, SourceSalesDocumentDraft } from "./generated/index.ts";
3
+ export declare const DOCUMENT_EVALUATION_PROTOCOL: "timbro.fiscal-document-evaluation.v1";
4
+ export declare class FiscalDocumentEvaluatorError extends Error {
5
+ readonly code: "runtime_unavailable" | "protocol_mismatch" | "worker_failure";
6
+ constructor(message: string, code: FiscalDocumentEvaluatorError["code"]);
7
+ }
8
+ export type DocumentEvaluator = {
9
+ evaluate: (input: {
10
+ readonly document: SourceSalesDocumentDraft;
11
+ }) => Promise<SourceDocumentEvaluationResponse>;
12
+ /** Releases the worker and rejects any in-flight evaluations. */
13
+ readonly dispose: () => void;
14
+ };
15
+ export type DocumentEvaluatorOptions = {
16
+ /** Advanced native/Wasm bridge used by conformance harnesses and hosts with a worker already installed. */
17
+ readonly runtime?: (requestJson: string) => string | Promise<string>;
18
+ /** Advanced worker injection; ordinary callers should use evaluateFiscalDocument directly. */
19
+ readonly worker?: DocumentWorkerPort;
20
+ readonly glueModuleUrl?: string;
21
+ readonly wasmModuleUrl?: string;
22
+ readonly timeoutMs?: number;
23
+ };
24
+ export type DocumentWorkerPort = {
25
+ postMessage: (message: unknown) => void;
26
+ addEventListener: (type: "message" | "error" | "messageerror", listener: (event: MessageEvent<unknown> | ErrorEvent) => void) => void;
27
+ removeEventListener?: (type: "message" | "error" | "messageerror", listener: (event: MessageEvent<unknown> | ErrorEvent) => void) => void;
28
+ terminate?: () => void;
29
+ };
30
+ /** Evaluates a Source sales draft through the lazy browser-safe Rust/Wasm document runtime. */
31
+ export declare function evaluateFiscalDocument(input: {
32
+ readonly document: SourceSalesDocumentDraft;
33
+ }): Promise<SourceDocumentEvaluationResponse>;
34
+ /** Releases the lazily created default worker, if one has been created. */
35
+ export declare function disposeFiscalDocumentEvaluator(): void;
36
+ /** Creates an evaluator while keeping worker and artifact details out of the common call. */
37
+ export declare function createDocumentEvaluator(options?: DocumentEvaluatorOptions): DocumentEvaluator;
38
+ //# sourceMappingURL=document.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"document.d.ts","sourceRoot":"","sources":["../src/document.ts"],"names":[],"mappings":"AASA,YAAY,EACV,gCAAgC,EAChC,wBAAwB,GACzB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EACV,gCAAgC,EAChC,wBAAwB,EACzB,MAAM,sBAAsB,CAAC;AAE9B,eAAO,MAAM,4BAA4B,wCAAqC,CAAC;AAE/E,qBAAa,4BAA6B,SAAQ,KAAK;IACrD,QAAQ,CAAC,IAAI,EAAE,qBAAqB,GAAG,mBAAmB,GAAG,gBAAgB,CAAC;IAE9E,YAAY,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,4BAA4B,CAAC,MAAM,CAAC,EAItE;CACF;AAED,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,CAAC,KAAK,EAAE;QAChB,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;KAC7C,KAAK,OAAO,CAAC,gCAAgC,CAAC,CAAC;IAChD,iEAAiE;IACjE,QAAQ,CAAC,OAAO,EAAE,MAAM,IAAI,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,wBAAwB,GAAG;IACrC,2GAA2G;IAC3G,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;IACrE,8FAA8F;IAC9F,QAAQ,CAAC,MAAM,CAAC,EAAE,kBAAkB,CAAC;IACrC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,aAAa,CAAC,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,WAAW,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,gBAAgB,EAAE,CAChB,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,cAAc,EAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG,UAAU,KAAK,IAAI,KAC1D,IAAI,CAAC;IACV,mBAAmB,CAAC,EAAE,CACpB,IAAI,EAAE,SAAS,GAAG,OAAO,GAAG,cAAc,EAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,CAAC,OAAO,CAAC,GAAG,UAAU,KAAK,IAAI,KAC1D,IAAI,CAAC;IACV,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;CACxB,CAAC;AAIF,+FAA+F;AAC/F,wBAAgB,sBAAsB,CAAC,KAAK,EAAE;IAC5C,QAAQ,CAAC,QAAQ,EAAE,wBAAwB,CAAC;CAC7C,GAAG,OAAO,CAAC,gCAAgC,CAAC,CAG5C;AAED,2EAA2E;AAC3E,wBAAgB,8BAA8B,IAAI,IAAI,CAGrD;AAED,6FAA6F;AAC7F,wBAAgB,uBAAuB,CAAC,OAAO,GAAE,wBAA6B,GAAG,iBAAiB,CA8CjG"}