@zanii/blackbox 0.11.0 → 0.12.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 CHANGED
@@ -83,6 +83,10 @@ verifyAnswerCredential(credential, lines, bodies, packs); // { ok, problems }: t
83
83
 
84
84
  The same checks run offline as pure functions: `toolHallucinations`, `groundingFindings`, `factsIn`, `loadReferencePacks`, `answerRisk`, `detectorAccuracy`.
85
85
 
86
+ ## New in 0.12.0
87
+
88
+ - Tax credit notes: `taxCreditNote` / `renderTaxCreditNote`, the document and printable copy behind gateway v0.14's `POST /v1/invoices/:number/credit-notes`.
89
+
86
90
  ## New in 0.11.0
87
91
 
88
92
  - Facts against the record compare currencies and units: `AED 500` in a tool result no longer grounds `USD 500` in the answer, nor `500 g` grounds `500 mg` (`currencyCodes`, `unitOf`). Dates written with an English or Arabic month (`3 March 2026`, `3 مارس 2026`) are facts too.
@@ -95,5 +95,51 @@ export declare function taxInvoice(input: TaxInvoiceInput): {
95
95
  export type TaxInvoice = ReturnType<typeof taxInvoice>;
96
96
  /** spec/billing.md §5: the printable copy. */
97
97
  export declare function renderTaxInvoice(d: TaxInvoice): string;
98
+ export interface TaxCreditNoteInput {
99
+ number: string;
100
+ issued_at: string;
101
+ /** The invoice it corrects, as issued. */
102
+ invoice: TaxInvoice;
103
+ reason: string;
104
+ /** What this note credits, before VAT. */
105
+ subtotal_fils: number;
106
+ /** What earlier notes on the invoice credited already. */
107
+ credited?: {
108
+ subtotal_fils: number;
109
+ vat_fils: number;
110
+ };
111
+ }
112
+ /** spec/billing.md §5a: a tax credit note. The note that credits what's left of the invoice takes
113
+ * the rest of its VAT exactly, so the notes never credit more VAT than was invoiced. */
114
+ export declare function taxCreditNote(input: TaxCreditNoteInput): {
115
+ v: 1;
116
+ title: "Tax Credit Note";
117
+ number: string;
118
+ issued_at: string;
119
+ invoice: {
120
+ number: string;
121
+ issued_at: string;
122
+ };
123
+ reason: string;
124
+ supplier: {
125
+ name: string;
126
+ address: string;
127
+ trn: string;
128
+ };
129
+ customer: {
130
+ legal_name: string;
131
+ address: string;
132
+ trn: string | null;
133
+ };
134
+ currency: "AED";
135
+ subtotal_fils: number;
136
+ vat_percent: number;
137
+ vat_fils: number;
138
+ total_fils: number;
139
+ total_aed: string;
140
+ };
141
+ export type TaxCreditNote = ReturnType<typeof taxCreditNote>;
142
+ /** spec/billing.md §5a: the printable copy. */
143
+ export declare function renderTaxCreditNote(d: TaxCreditNote): string;
98
144
  /** spec/billing.md §6: a `Stripe-Signature` header checked against the raw body. */
99
145
  export declare function stripeSignatureOk(header: string, rawBody: Uint8Array, secret: string, nowSeconds: number, toleranceSeconds?: number): boolean;
@@ -151,6 +151,64 @@ export function renderTaxInvoice(d) {
151
151
  ];
152
152
  return out.join("\n");
153
153
  }
154
+ /** spec/billing.md §5a: a tax credit note. The note that credits what's left of the invoice takes
155
+ * the rest of its VAT exactly, so the notes never credit more VAT than was invoiced. */
156
+ export function taxCreditNote(input) {
157
+ const inv = input.invoice;
158
+ const before = input.credited ?? { subtotal_fils: 0, vat_fils: 0 };
159
+ const last = input.subtotal_fils === inv.subtotal_fils - before.subtotal_fils;
160
+ const vat = last
161
+ ? inv.vat_fils - before.vat_fils
162
+ : Math.floor((input.subtotal_fils * inv.vat_percent + 50) / 100);
163
+ return {
164
+ v: 1,
165
+ title: "Tax Credit Note",
166
+ number: input.number,
167
+ issued_at: input.issued_at,
168
+ invoice: { number: inv.number, issued_at: inv.issued_at },
169
+ reason: input.reason,
170
+ supplier: inv.supplier,
171
+ customer: inv.customer,
172
+ currency: "AED",
173
+ subtotal_fils: input.subtotal_fils,
174
+ vat_percent: inv.vat_percent,
175
+ vat_fils: vat,
176
+ total_fils: input.subtotal_fils + vat,
177
+ total_aed: formatAed(input.subtotal_fils + vat),
178
+ };
179
+ }
180
+ /** spec/billing.md §5a: the printable copy. */
181
+ export function renderTaxCreditNote(d) {
182
+ return [
183
+ "# Tax Credit Note",
184
+ "",
185
+ "| Field | Value |",
186
+ "|---|---|",
187
+ `| Credit note number | ${cell(d.number)} |`,
188
+ `| Date of issue | ${d.issued_at} |`,
189
+ `| Corrects invoice | ${cell(d.invoice.number)} of ${d.invoice.issued_at} |`,
190
+ `| Reason | ${cell(oneLine(d.reason))} |`,
191
+ "",
192
+ "## Supplier",
193
+ "",
194
+ `${oneLine(d.supplier.name)} `,
195
+ `${oneLine(d.supplier.address)} `,
196
+ `TRN: ${d.supplier.trn}`,
197
+ "",
198
+ "## Customer",
199
+ "",
200
+ `${oneLine(d.customer.legal_name)} `,
201
+ `${oneLine(d.customer.address)} `,
202
+ `TRN: ${d.customer.trn ?? "not registered"}`,
203
+ "",
204
+ "| Credited | AED |",
205
+ "|---|---:|",
206
+ `| Subtotal | ${aed(d.subtotal_fils)} |`,
207
+ `| VAT ${d.vat_percent}% | ${aed(d.vat_fils)} |`,
208
+ `| **Total credited** | **${aed(d.total_fils)}** |`,
209
+ "",
210
+ ].join("\n");
211
+ }
154
212
  // ---------------------------------------------------------------- Stripe webhook signature (§6)
155
213
  /** spec/billing.md §6: a `Stripe-Signature` header checked against the raw body. */
156
214
  export function stripeSignatureOk(header, rawBody, secret, nowSeconds, toleranceSeconds = 300) {
package/dist/index.d.ts CHANGED
@@ -11,7 +11,7 @@ export { archiveParquet } from "./archive/parquet.ts";
11
11
  export { type Attestation, attest, isReadOnly, normalise, parseCommand } from "./attest/index.ts";
12
12
  export { type AuthorityFinding, authorityAt, authorityTimeline, automationSurprise, type Mode as AuthorityMode, type Span as AuthoritySpan, } from "./authority/index.ts";
13
13
  export { badgeSvg, RECORD_STATES, type RecordState, recordBadge, recordState, } from "./badge/index.ts";
14
- export { type Invoice, type InvoiceLine, invoice, loadPlans, type Plan, type Plans, renderTaxInvoice, stripeSignatureOk, type TaxInvoice, type TaxInvoiceInput, taxInvoice, } from "./billing/index.ts";
14
+ export { type Invoice, type InvoiceLine, invoice, loadPlans, type Plan, type Plans, renderTaxCreditNote, renderTaxInvoice, stripeSignatureOk, type TaxCreditNote, type TaxCreditNoteInput, type TaxInvoice, type TaxInvoiceInput, taxCreditNote, taxInvoice, } from "./billing/index.ts";
15
15
  export { type AgentIdentity, checkAgent, sessionBom } from "./bom/index.ts";
16
16
  export { BlackboxApiError, type Client, type ClientOptions, client, type SessionQuery, } from "./client/index.ts";
17
17
  export { ART12_MIN_RETENTION_DAYS, type Art12Check, type Art12Report, art12Check, } from "./compliance/art12.ts";
package/dist/index.js CHANGED
@@ -13,7 +13,7 @@ export { archiveParquet } from "./archive/parquet.js";
13
13
  export { attest, isReadOnly, normalise, parseCommand } from "./attest/index.js";
14
14
  export { authorityAt, authorityTimeline, automationSurprise, } from "./authority/index.js";
15
15
  export { badgeSvg, RECORD_STATES, recordBadge, recordState, } from "./badge/index.js";
16
- export { invoice, loadPlans, renderTaxInvoice, stripeSignatureOk, taxInvoice, } from "./billing/index.js";
16
+ export { invoice, loadPlans, renderTaxCreditNote, renderTaxInvoice, stripeSignatureOk, taxCreditNote, taxInvoice, } from "./billing/index.js";
17
17
  export { checkAgent, sessionBom } from "./bom/index.js";
18
18
  export { BlackboxApiError, client, } from "./client/index.js";
19
19
  export { ART12_MIN_RETENTION_DAYS, art12Check, } from "./compliance/art12.js";
package/dist/version.d.ts CHANGED
@@ -1 +1 @@
1
- export declare const VERSION = "0.11.0";
1
+ export declare const VERSION = "0.12.0";
package/dist/version.js CHANGED
@@ -1,2 +1,2 @@
1
1
  // The SDK version, on its own so the CLI can print it without loading the whole SDK.
2
- export const VERSION = "0.11.0";
2
+ export const VERSION = "0.12.0";
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@zanii/blackbox",
3
3
  "license": "Apache-2.0",
4
- "version": "0.11.0",
4
+ "version": "0.12.0",
5
5
  "description": "The flight recorder for AI agents: sessions, a zero-loss spool, framework hooks, approvals, and offline verification of the gateway's hash-chained record.",
6
6
  "keywords": [
7
7
  "ai-agents",