@cheqi/sdk 0.2.1 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +39 -0
- package/dist/download/index.d.ts +21 -8
- package/dist/download/index.js +29 -7
- package/dist/download/index.js.map +1 -1
- package/dist/http/client.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,3 +55,42 @@ const result = await sdk.receiptService.processCompleteReceipt(
|
|
|
55
55
|
- The package ships `.d.ts` declarations so it can be consumed directly from TypeScript.
|
|
56
56
|
- The full Java model class hierarchy is still not recreated as class-per-model; the payload contract is represented as typed object shapes instead.
|
|
57
57
|
- XML verification currently normalizes formatting whitespace and hashes the result. If strict XML C14N compatibility is required, that part should be hardened next.
|
|
58
|
+
## Deferred receipt download links
|
|
59
|
+
|
|
60
|
+
The SDK provides stateless primitives for creating a customer URL before Cheqi is
|
|
61
|
+
reachable. It does not store receipts, start background workers, or choose a retry
|
|
62
|
+
schedule. Your integration owns persistence and decides where and when deferred work
|
|
63
|
+
runs.
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
import {
|
|
67
|
+
buildDownloadEnvelope,
|
|
68
|
+
encryptDownloadEnvelope,
|
|
69
|
+
generateDownloadLink
|
|
70
|
+
} from "@cheqi/sdk/download";
|
|
71
|
+
|
|
72
|
+
const link = generateDownloadLink("https://receipt.cheqi.io");
|
|
73
|
+
|
|
74
|
+
// Persist the complete template request, link.downloadId, and protected
|
|
75
|
+
// link.contentKey using your own durable storage before exposing link.url.
|
|
76
|
+
await receiptJobs.create({ templateRequest, ...link });
|
|
77
|
+
printQr(link.url);
|
|
78
|
+
|
|
79
|
+
// Later, on compute and a schedule controlled by your integration:
|
|
80
|
+
const template = await sdk.receiptService.generateReceiptTemplate(templateRequest);
|
|
81
|
+
const envelope = buildDownloadEnvelope(template);
|
|
82
|
+
const ciphertext = await encryptDownloadEnvelope(envelope, link.contentKey);
|
|
83
|
+
|
|
84
|
+
// Persist the exact ciphertext before its first upload attempt. After an ambiguous
|
|
85
|
+
// result, every retry must reuse these bytes rather than encrypting again.
|
|
86
|
+
await receiptJobs.markReady(link.downloadId, ciphertext);
|
|
87
|
+
await sdk.receiptService.uploadClientEncryptedReceipt({
|
|
88
|
+
downloadId: link.downloadId,
|
|
89
|
+
ciphertext
|
|
90
|
+
});
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The customer may open the URL before the receipt is uploaded. The download page reports
|
|
94
|
+
that the receipt is not yet available and can be visited again later. Do not implement
|
|
95
|
+
receipt template generation locally: call the normal template endpoint after connectivity
|
|
96
|
+
returns so CHEQI, UBL, seller, and VAT behavior remains canonical.
|
package/dist/download/index.d.ts
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* ("Download Link Contract v1" — the offline-first QR route).
|
|
4
4
|
*
|
|
5
5
|
* The download id and AES-256-GCM content key are generated locally, with no network,
|
|
6
|
-
* so
|
|
7
|
-
* Cheqi API is unreachable.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* so an integration can render the QR `<baseUrl>/<downloadId>#<contentKey>` even while
|
|
7
|
+
* the Cheqi API is unreachable. Before exposing the URL, the integration is responsible
|
|
8
|
+
* for retaining the original template request, download id, and content key so it can
|
|
9
|
+
* finish issuance later. This SDK does not provide storage, scheduling, or background
|
|
10
|
+
* retry behavior.
|
|
11
|
+
*
|
|
12
|
+
* The content key travels only in the URL fragment, which browsers never send to any
|
|
13
|
+
* server: Cheqi stores ciphertext it can never decrypt, and decryption happens on the
|
|
14
|
+
* customer's device.
|
|
10
15
|
*
|
|
11
16
|
* This module is intentionally separate from {@link ../services/decryption.js | DecryptionService}
|
|
12
17
|
* (the Node-only RSA + AES path for receipts delivered to Cheqi wallets) and is
|
|
@@ -19,10 +24,11 @@
|
|
|
19
24
|
* used for wallet delivery, so no separate download-route model exists.
|
|
20
25
|
*/
|
|
21
26
|
import type { ReceiptEnvelope } from "../models/generated/ReceiptEnvelope.js";
|
|
27
|
+
import type { ReceiptTemplateResponse } from "../models/generated/ReceiptTemplateResponse.js";
|
|
22
28
|
export type { ReceiptEnvelope };
|
|
23
29
|
/** Download id length in bytes (128 bits — the enumeration defense on the public endpoint). */
|
|
24
30
|
export declare const DOWNLOAD_ID_LENGTH = 16;
|
|
25
|
-
/** A freshly generated download link
|
|
31
|
+
/** A freshly generated download link. The integration owns persistence and later processing. */
|
|
26
32
|
export interface DownloadLink {
|
|
27
33
|
/** base64url (unpadded) download id; the only part of the link the server ever sees. */
|
|
28
34
|
downloadId: string;
|
|
@@ -32,9 +38,10 @@ export interface DownloadLink {
|
|
|
32
38
|
url: string;
|
|
33
39
|
}
|
|
34
40
|
/**
|
|
35
|
-
* Generates a fresh download link locally — no network involved.
|
|
36
|
-
*
|
|
37
|
-
*
|
|
41
|
+
* Generates a fresh download link locally — no network involved. The URL does not depend
|
|
42
|
+
* on successful server issuance: a customer who opens it before upload sees the pending
|
|
43
|
+
* receipt page. The integration must retain the request, id, and key before exposing the
|
|
44
|
+
* URL so it can finish template generation, encryption, and upload later.
|
|
38
45
|
*/
|
|
39
46
|
export declare function generateDownloadLink(baseUrl: string): DownloadLink;
|
|
40
47
|
/** Builds the customer-facing URL. The content key MUST stay in the fragment. */
|
|
@@ -47,6 +54,12 @@ export declare function parseDownloadUrl(url: string): {
|
|
|
47
54
|
downloadId: string;
|
|
48
55
|
contentKey: string;
|
|
49
56
|
};
|
|
57
|
+
/**
|
|
58
|
+
* Converts the canonical response from `POST /receipt/template` to the standard envelope
|
|
59
|
+
* encrypted for a client-generated download link. Receipt content is never generated or
|
|
60
|
+
* normalized locally; all formats present in the server response are preserved.
|
|
61
|
+
*/
|
|
62
|
+
export declare function buildDownloadEnvelope(template: ReceiptTemplateResponse): ReceiptEnvelope;
|
|
50
63
|
/**
|
|
51
64
|
* Encrypts a receipt envelope with the content key. Returns `base64(iv || ciphertext || tag)` —
|
|
52
65
|
* the exact bytes to upload as `ciphertext` to `POST /receipt/download`. Encrypt once and
|
package/dist/download/index.js
CHANGED
|
@@ -3,10 +3,15 @@
|
|
|
3
3
|
* ("Download Link Contract v1" — the offline-first QR route).
|
|
4
4
|
*
|
|
5
5
|
* The download id and AES-256-GCM content key are generated locally, with no network,
|
|
6
|
-
* so
|
|
7
|
-
* Cheqi API is unreachable.
|
|
8
|
-
*
|
|
9
|
-
*
|
|
6
|
+
* so an integration can render the QR `<baseUrl>/<downloadId>#<contentKey>` even while
|
|
7
|
+
* the Cheqi API is unreachable. Before exposing the URL, the integration is responsible
|
|
8
|
+
* for retaining the original template request, download id, and content key so it can
|
|
9
|
+
* finish issuance later. This SDK does not provide storage, scheduling, or background
|
|
10
|
+
* retry behavior.
|
|
11
|
+
*
|
|
12
|
+
* The content key travels only in the URL fragment, which browsers never send to any
|
|
13
|
+
* server: Cheqi stores ciphertext it can never decrypt, and decryption happens on the
|
|
14
|
+
* customer's device.
|
|
10
15
|
*
|
|
11
16
|
* This module is intentionally separate from {@link ../services/decryption.js | DecryptionService}
|
|
12
17
|
* (the Node-only RSA + AES path for receipts delivered to Cheqi wallets) and is
|
|
@@ -73,9 +78,10 @@ async function importContentKey(contentKey, usage) {
|
|
|
73
78
|
return subtle().importKey("raw", keyBytes, "AES-GCM", false, [usage]);
|
|
74
79
|
}
|
|
75
80
|
/**
|
|
76
|
-
* Generates a fresh download link locally — no network involved.
|
|
77
|
-
*
|
|
78
|
-
*
|
|
81
|
+
* Generates a fresh download link locally — no network involved. The URL does not depend
|
|
82
|
+
* on successful server issuance: a customer who opens it before upload sees the pending
|
|
83
|
+
* receipt page. The integration must retain the request, id, and key before exposing the
|
|
84
|
+
* URL so it can finish template generation, encryption, and upload later.
|
|
79
85
|
*/
|
|
80
86
|
export function generateDownloadLink(baseUrl) {
|
|
81
87
|
const downloadId = toBase64Url(randomBytes(DOWNLOAD_ID_LENGTH));
|
|
@@ -104,6 +110,22 @@ export function parseDownloadUrl(url) {
|
|
|
104
110
|
}
|
|
105
111
|
return { downloadId, contentKey };
|
|
106
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Converts the canonical response from `POST /receipt/template` to the standard envelope
|
|
115
|
+
* encrypted for a client-generated download link. Receipt content is never generated or
|
|
116
|
+
* normalized locally; all formats present in the server response are preserved.
|
|
117
|
+
*/
|
|
118
|
+
export function buildDownloadEnvelope(template) {
|
|
119
|
+
if (!template) {
|
|
120
|
+
throw new EncryptionError("Receipt template response is required");
|
|
121
|
+
}
|
|
122
|
+
return {
|
|
123
|
+
cheqi: template.cheqi,
|
|
124
|
+
ublPurchaseReceipt: template.ublPurchaseReceipt,
|
|
125
|
+
ublInvoice: template.ublInvoice,
|
|
126
|
+
vatMetaData: template.vatMetadata
|
|
127
|
+
};
|
|
128
|
+
}
|
|
107
129
|
/**
|
|
108
130
|
* Encrypts a receipt envelope with the content key. Returns `base64(iv || ciphertext || tag)` —
|
|
109
131
|
* the exact bytes to upload as `ciphertext` to `POST /receipt/download`. Encrypt once and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/download/index.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/download/index.ts"],"names":[],"mappings":"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"}
|
package/dist/http/client.js
CHANGED