noxctl 0.7.4 → 0.9.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.
Files changed (272) hide show
  1. package/README.md +50 -4
  2. package/dist/auth.d.ts +18 -1
  3. package/dist/auth.d.ts.map +1 -1
  4. package/dist/auth.js +129 -15
  5. package/dist/auth.js.map +1 -1
  6. package/dist/cli.d.ts.map +1 -1
  7. package/dist/cli.js +144 -33
  8. package/dist/cli.js.map +1 -1
  9. package/dist/credentials-store.d.ts +3 -0
  10. package/dist/credentials-store.d.ts.map +1 -1
  11. package/dist/credentials-store.js +54 -10
  12. package/dist/credentials-store.js.map +1 -1
  13. package/dist/embedded.d.ts +15 -0
  14. package/dist/embedded.d.ts.map +1 -0
  15. package/dist/embedded.js +11 -0
  16. package/dist/embedded.js.map +1 -0
  17. package/dist/fortnox-client.d.ts +40 -25
  18. package/dist/fortnox-client.d.ts.map +1 -1
  19. package/dist/fortnox-client.js +165 -51
  20. package/dist/fortnox-client.js.map +1 -1
  21. package/dist/index.d.ts +7 -2
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +50 -35
  24. package/dist/index.js.map +1 -1
  25. package/dist/keychain-target.d.ts +3 -0
  26. package/dist/keychain-target.d.ts.map +1 -1
  27. package/dist/keychain-target.js +28 -7
  28. package/dist/keychain-target.js.map +1 -1
  29. package/dist/operations/absencetransactions.d.ts +9 -6
  30. package/dist/operations/absencetransactions.d.ts.map +1 -1
  31. package/dist/operations/absencetransactions.js +42 -33
  32. package/dist/operations/absencetransactions.js.map +1 -1
  33. package/dist/operations/accounts.d.ts +6 -3
  34. package/dist/operations/accounts.d.ts.map +1 -1
  35. package/dist/operations/accounts.js +28 -24
  36. package/dist/operations/accounts.js.map +1 -1
  37. package/dist/operations/analytics.d.ts +35 -0
  38. package/dist/operations/analytics.d.ts.map +1 -1
  39. package/dist/operations/analytics.js +59 -35
  40. package/dist/operations/analytics.js.map +1 -1
  41. package/dist/operations/articles.d.ts +9 -6
  42. package/dist/operations/articles.d.ts.map +1 -1
  43. package/dist/operations/articles.js +36 -32
  44. package/dist/operations/articles.js.map +1 -1
  45. package/dist/operations/attendancetransactions.d.ts +9 -6
  46. package/dist/operations/attendancetransactions.d.ts.map +1 -1
  47. package/dist/operations/attendancetransactions.js +45 -36
  48. package/dist/operations/attendancetransactions.js.map +1 -1
  49. package/dist/operations/company.d.ts +5 -1
  50. package/dist/operations/company.d.ts.map +1 -1
  51. package/dist/operations/company.js +8 -4
  52. package/dist/operations/company.js.map +1 -1
  53. package/dist/operations/contracts.d.ts +12 -9
  54. package/dist/operations/contracts.d.ts.map +1 -1
  55. package/dist/operations/contracts.js +59 -47
  56. package/dist/operations/contracts.js.map +1 -1
  57. package/dist/operations/costcenters.d.ts +10 -7
  58. package/dist/operations/costcenters.d.ts.map +1 -1
  59. package/dist/operations/costcenters.js +39 -35
  60. package/dist/operations/costcenters.js.map +1 -1
  61. package/dist/operations/customers.d.ts +9 -6
  62. package/dist/operations/customers.d.ts.map +1 -1
  63. package/dist/operations/customers.js +46 -42
  64. package/dist/operations/customers.js.map +1 -1
  65. package/dist/operations/employees.d.ts +9 -6
  66. package/dist/operations/employees.d.ts.map +1 -1
  67. package/dist/operations/employees.js +35 -31
  68. package/dist/operations/employees.js.map +1 -1
  69. package/dist/operations/financial-reports.d.ts +7 -2
  70. package/dist/operations/financial-reports.d.ts.map +1 -1
  71. package/dist/operations/financial-reports.js +169 -165
  72. package/dist/operations/financial-reports.js.map +1 -1
  73. package/dist/operations/financial-years.d.ts +8 -5
  74. package/dist/operations/financial-years.d.ts.map +1 -1
  75. package/dist/operations/financial-years.js +33 -29
  76. package/dist/operations/financial-years.js.map +1 -1
  77. package/dist/operations/index.d.ts +311 -0
  78. package/dist/operations/index.d.ts.map +1 -0
  79. package/dist/operations/index.js +64 -0
  80. package/dist/operations/index.js.map +1 -0
  81. package/dist/operations/invoice-payments.d.ts +10 -7
  82. package/dist/operations/invoice-payments.d.ts.map +1 -1
  83. package/dist/operations/invoice-payments.js +45 -35
  84. package/dist/operations/invoice-payments.js.map +1 -1
  85. package/dist/operations/invoices.d.ts +34 -30
  86. package/dist/operations/invoices.d.ts.map +1 -1
  87. package/dist/operations/invoices.js +225 -113
  88. package/dist/operations/invoices.js.map +1 -1
  89. package/dist/operations/offers.d.ts +11 -8
  90. package/dist/operations/offers.d.ts.map +1 -1
  91. package/dist/operations/offers.js +54 -43
  92. package/dist/operations/offers.js.map +1 -1
  93. package/dist/operations/orders.d.ts +10 -7
  94. package/dist/operations/orders.d.ts.map +1 -1
  95. package/dist/operations/orders.js +43 -39
  96. package/dist/operations/orders.js.map +1 -1
  97. package/dist/operations/pricelists.d.ts +16 -10
  98. package/dist/operations/pricelists.d.ts.map +1 -1
  99. package/dist/operations/pricelists.js +56 -48
  100. package/dist/operations/pricelists.js.map +1 -1
  101. package/dist/operations/projects.d.ts +9 -6
  102. package/dist/operations/projects.d.ts.map +1 -1
  103. package/dist/operations/projects.js +34 -30
  104. package/dist/operations/projects.js.map +1 -1
  105. package/dist/operations/recurrings.d.ts +14 -10
  106. package/dist/operations/recurrings.d.ts.map +1 -1
  107. package/dist/operations/recurrings.js +74 -59
  108. package/dist/operations/recurrings.js.map +1 -1
  109. package/dist/operations/salarytransactions.d.ts +9 -6
  110. package/dist/operations/salarytransactions.d.ts.map +1 -1
  111. package/dist/operations/salarytransactions.js +41 -32
  112. package/dist/operations/salarytransactions.js.map +1 -1
  113. package/dist/operations/scheduletimes.d.ts +7 -3
  114. package/dist/operations/scheduletimes.d.ts.map +1 -1
  115. package/dist/operations/scheduletimes.js +26 -22
  116. package/dist/operations/scheduletimes.js.map +1 -1
  117. package/dist/operations/supplier-invoice-payments.d.ts +9 -6
  118. package/dist/operations/supplier-invoice-payments.d.ts.map +1 -1
  119. package/dist/operations/supplier-invoice-payments.js +38 -29
  120. package/dist/operations/supplier-invoice-payments.js.map +1 -1
  121. package/dist/operations/supplier-invoices.d.ts +9 -6
  122. package/dist/operations/supplier-invoices.d.ts.map +1 -1
  123. package/dist/operations/supplier-invoices.js +41 -32
  124. package/dist/operations/supplier-invoices.js.map +1 -1
  125. package/dist/operations/suppliers.d.ts +9 -6
  126. package/dist/operations/suppliers.d.ts.map +1 -1
  127. package/dist/operations/suppliers.js +36 -32
  128. package/dist/operations/suppliers.js.map +1 -1
  129. package/dist/operations/tax.d.ts +5 -1
  130. package/dist/operations/tax.d.ts.map +1 -1
  131. package/dist/operations/tax.js +43 -39
  132. package/dist/operations/tax.js.map +1 -1
  133. package/dist/operations/taxreductions.d.ts +8 -5
  134. package/dist/operations/taxreductions.d.ts.map +1 -1
  135. package/dist/operations/taxreductions.js +28 -24
  136. package/dist/operations/taxreductions.js.map +1 -1
  137. package/dist/operations/vouchers.d.ts +26 -8
  138. package/dist/operations/vouchers.d.ts.map +1 -1
  139. package/dist/operations/vouchers.js +174 -122
  140. package/dist/operations/vouchers.js.map +1 -1
  141. package/dist/schema-audit-mappings.d.ts +9 -0
  142. package/dist/schema-audit-mappings.d.ts.map +1 -0
  143. package/dist/schema-audit-mappings.js +45 -0
  144. package/dist/schema-audit-mappings.js.map +1 -0
  145. package/dist/schema-audit.d.ts +45 -0
  146. package/dist/schema-audit.d.ts.map +1 -0
  147. package/dist/schema-audit.js +132 -0
  148. package/dist/schema-audit.js.map +1 -0
  149. package/dist/scope-probes.d.ts.map +1 -1
  150. package/dist/scope-probes.js +1 -0
  151. package/dist/scope-probes.js.map +1 -1
  152. package/dist/strict-mcp-server.d.ts +17 -0
  153. package/dist/strict-mcp-server.d.ts.map +1 -0
  154. package/dist/strict-mcp-server.js +35 -0
  155. package/dist/strict-mcp-server.js.map +1 -0
  156. package/dist/tools/absencetransactions.d.ts +2 -1
  157. package/dist/tools/absencetransactions.d.ts.map +1 -1
  158. package/dist/tools/absencetransactions.js +3 -2
  159. package/dist/tools/absencetransactions.js.map +1 -1
  160. package/dist/tools/analytics.d.ts +2 -1
  161. package/dist/tools/analytics.d.ts.map +1 -1
  162. package/dist/tools/analytics.js +3 -2
  163. package/dist/tools/analytics.js.map +1 -1
  164. package/dist/tools/articles.d.ts +2 -1
  165. package/dist/tools/articles.d.ts.map +1 -1
  166. package/dist/tools/articles.js +3 -2
  167. package/dist/tools/articles.js.map +1 -1
  168. package/dist/tools/attendancetransactions.d.ts +2 -1
  169. package/dist/tools/attendancetransactions.d.ts.map +1 -1
  170. package/dist/tools/attendancetransactions.js +3 -2
  171. package/dist/tools/attendancetransactions.js.map +1 -1
  172. package/dist/tools/bookkeeping.d.ts +2 -1
  173. package/dist/tools/bookkeeping.d.ts.map +1 -1
  174. package/dist/tools/bookkeeping.js +83 -5
  175. package/dist/tools/bookkeeping.js.map +1 -1
  176. package/dist/tools/company.d.ts +2 -1
  177. package/dist/tools/company.d.ts.map +1 -1
  178. package/dist/tools/company.js +3 -2
  179. package/dist/tools/company.js.map +1 -1
  180. package/dist/tools/contracts.d.ts +2 -1
  181. package/dist/tools/contracts.d.ts.map +1 -1
  182. package/dist/tools/contracts.js +3 -2
  183. package/dist/tools/contracts.js.map +1 -1
  184. package/dist/tools/costcenters.d.ts +2 -1
  185. package/dist/tools/costcenters.d.ts.map +1 -1
  186. package/dist/tools/costcenters.js +3 -2
  187. package/dist/tools/costcenters.js.map +1 -1
  188. package/dist/tools/customers.d.ts +2 -1
  189. package/dist/tools/customers.d.ts.map +1 -1
  190. package/dist/tools/customers.js +3 -2
  191. package/dist/tools/customers.js.map +1 -1
  192. package/dist/tools/employees.d.ts +2 -1
  193. package/dist/tools/employees.d.ts.map +1 -1
  194. package/dist/tools/employees.js +3 -2
  195. package/dist/tools/employees.js.map +1 -1
  196. package/dist/tools/financial-reports.d.ts +2 -1
  197. package/dist/tools/financial-reports.d.ts.map +1 -1
  198. package/dist/tools/financial-reports.js +3 -2
  199. package/dist/tools/financial-reports.js.map +1 -1
  200. package/dist/tools/financial-years.d.ts +2 -1
  201. package/dist/tools/financial-years.d.ts.map +1 -1
  202. package/dist/tools/financial-years.js +3 -2
  203. package/dist/tools/financial-years.js.map +1 -1
  204. package/dist/tools/invoice-payments.d.ts +2 -1
  205. package/dist/tools/invoice-payments.d.ts.map +1 -1
  206. package/dist/tools/invoice-payments.js +3 -2
  207. package/dist/tools/invoice-payments.js.map +1 -1
  208. package/dist/tools/invoices.d.ts +2 -1
  209. package/dist/tools/invoices.d.ts.map +1 -1
  210. package/dist/tools/invoices.js +100 -21
  211. package/dist/tools/invoices.js.map +1 -1
  212. package/dist/tools/offers.d.ts +2 -1
  213. package/dist/tools/offers.d.ts.map +1 -1
  214. package/dist/tools/offers.js +50 -19
  215. package/dist/tools/offers.js.map +1 -1
  216. package/dist/tools/orders.d.ts +2 -1
  217. package/dist/tools/orders.d.ts.map +1 -1
  218. package/dist/tools/orders.js +58 -18
  219. package/dist/tools/orders.js.map +1 -1
  220. package/dist/tools/pricelists.d.ts +2 -1
  221. package/dist/tools/pricelists.d.ts.map +1 -1
  222. package/dist/tools/pricelists.js +3 -2
  223. package/dist/tools/pricelists.js.map +1 -1
  224. package/dist/tools/projects.d.ts +2 -1
  225. package/dist/tools/projects.d.ts.map +1 -1
  226. package/dist/tools/projects.js +3 -2
  227. package/dist/tools/projects.js.map +1 -1
  228. package/dist/tools/recurrings.d.ts +2 -1
  229. package/dist/tools/recurrings.d.ts.map +1 -1
  230. package/dist/tools/recurrings.js +3 -2
  231. package/dist/tools/recurrings.js.map +1 -1
  232. package/dist/tools/salarytransactions.d.ts +2 -1
  233. package/dist/tools/salarytransactions.d.ts.map +1 -1
  234. package/dist/tools/salarytransactions.js +3 -2
  235. package/dist/tools/salarytransactions.js.map +1 -1
  236. package/dist/tools/scheduletimes.d.ts +2 -1
  237. package/dist/tools/scheduletimes.d.ts.map +1 -1
  238. package/dist/tools/scheduletimes.js +3 -2
  239. package/dist/tools/scheduletimes.js.map +1 -1
  240. package/dist/tools/status.d.ts.map +1 -1
  241. package/dist/tools/status.js +5 -4
  242. package/dist/tools/status.js.map +1 -1
  243. package/dist/tools/supplier-invoice-payments.d.ts +2 -1
  244. package/dist/tools/supplier-invoice-payments.d.ts.map +1 -1
  245. package/dist/tools/supplier-invoice-payments.js +3 -2
  246. package/dist/tools/supplier-invoice-payments.js.map +1 -1
  247. package/dist/tools/supplier-invoices.d.ts +2 -1
  248. package/dist/tools/supplier-invoices.d.ts.map +1 -1
  249. package/dist/tools/supplier-invoices.js +47 -6
  250. package/dist/tools/supplier-invoices.js.map +1 -1
  251. package/dist/tools/suppliers.d.ts +2 -1
  252. package/dist/tools/suppliers.d.ts.map +1 -1
  253. package/dist/tools/suppliers.js +3 -2
  254. package/dist/tools/suppliers.js.map +1 -1
  255. package/dist/tools/tax.d.ts +2 -1
  256. package/dist/tools/tax.d.ts.map +1 -1
  257. package/dist/tools/tax.js +3 -2
  258. package/dist/tools/tax.js.map +1 -1
  259. package/dist/tools/taxreductions.d.ts +2 -1
  260. package/dist/tools/taxreductions.d.ts.map +1 -1
  261. package/dist/tools/taxreductions.js +3 -2
  262. package/dist/tools/taxreductions.js.map +1 -1
  263. package/dist/version.d.ts +2 -0
  264. package/dist/version.d.ts.map +1 -0
  265. package/dist/version.js +3 -0
  266. package/dist/version.js.map +1 -0
  267. package/dist/views.d.ts +2 -0
  268. package/dist/views.d.ts.map +1 -1
  269. package/dist/views.js +11 -0
  270. package/dist/views.js.map +1 -1
  271. package/docs/embedded.md +60 -0
  272. package/package.json +23 -4
@@ -1,138 +1,190 @@
1
1
  import { readFileSync, existsSync, statSync } from 'node:fs';
2
2
  import { basename, extname } from 'node:path';
3
- import { fortnoxRequest, fetchAllPages } from '../fortnox-client.js';
3
+ import { defaultFortnoxTransport } from '../fortnox-client.js';
4
4
  import { voucherSeriesSegment } from '../identifiers.js';
5
- import { listFinancialYears } from './financial-years.js';
6
- export async function listVouchers(params = {}) {
7
- const subpath = params.series ? `sublist/${voucherSeriesSegment(params.series)}` : '';
8
- const endpoint = `vouchers/${subpath}`;
9
- const queryParams = {
10
- financialyear: params.financialYear,
11
- fromdate: params.fromDate,
12
- todate: params.toDate,
13
- };
14
- if (params.all) {
15
- const { items, totalResources } = await fetchAllPages(endpoint, 'Vouchers', queryParams);
16
- return {
17
- Vouchers: items,
18
- MetaInformation: { '@TotalResources': totalResources, '@TotalPages': 1, '@CurrentPage': 1 },
5
+ import { createFinancialYearOperations } from './financial-years.js';
6
+ export function createVoucherOperations(transport) {
7
+ const { listFinancialYears } = createFinancialYearOperations(transport);
8
+ async function listVouchers(params = {}) {
9
+ const subpath = params.series ? `sublist/${voucherSeriesSegment(params.series)}` : '';
10
+ const endpoint = `vouchers/${subpath}`;
11
+ const queryParams = {
12
+ financialyear: params.financialYear,
13
+ fromdate: params.fromDate,
14
+ todate: params.toDate,
19
15
  };
16
+ if (params.all) {
17
+ const { items, totalResources } = await transport.fetchAllPages(endpoint, 'Vouchers', queryParams);
18
+ return {
19
+ Vouchers: items,
20
+ MetaInformation: { '@TotalResources': totalResources, '@TotalPages': 1, '@CurrentPage': 1 },
21
+ };
22
+ }
23
+ return transport.request(endpoint, {
24
+ params: { ...queryParams, page: params.page || 1, limit: params.limit || 100 },
25
+ });
20
26
  }
21
- return fortnoxRequest(endpoint, {
22
- params: { ...queryParams, page: params.page || 1, limit: params.limit || 100 },
23
- });
24
- }
25
- export async function getVoucher(series, voucherNumber, financialYear) {
26
- const params = {};
27
- if (financialYear)
28
- params.financialyear = financialYear;
29
- const data = await fortnoxRequest(`vouchers/${voucherSeriesSegment(series)}/${encodeURIComponent(voucherNumber)}`, { params });
30
- return data.Voucher;
31
- }
32
- export async function createVoucher(params) {
33
- const data = await fortnoxRequest('vouchers', {
34
- method: 'POST',
35
- body: {
36
- Voucher: {
37
- ...params,
38
- VoucherSeries: params.VoucherSeries || 'A',
39
- },
40
- },
41
- });
42
- return data.Voucher;
43
- }
44
- const MIME_BY_EXT = {
45
- '.pdf': 'application/pdf',
46
- '.png': 'image/png',
47
- '.jpg': 'image/jpeg',
48
- '.jpeg': 'image/jpeg',
49
- '.gif': 'image/gif',
50
- '.webp': 'image/webp',
51
- '.heic': 'image/heic',
52
- '.tif': 'image/tiff',
53
- '.tiff': 'image/tiff',
54
- '.txt': 'text/plain',
55
- '.csv': 'text/csv',
56
- '.xml': 'application/xml',
57
- };
58
- function mimeForFile(filePath) {
59
- return MIME_BY_EXT[extname(filePath).toLowerCase()] ?? 'application/octet-stream';
60
- }
61
- // Upload a single file to the Fortnox inbox; returns the archived File object (has .Id).
62
- export async function uploadInboxFile(filePath) {
63
- const buf = readFileSync(filePath);
64
- const form = new FormData();
65
- form.append('file', new Blob([buf], { type: mimeForFile(filePath) }), basename(filePath));
66
- const data = await fortnoxRequest('inbox', { method: 'POST', rawBody: form });
67
- return data.File;
68
- }
69
- // Link an already-uploaded file (by id) to a voucher. The financial year goes in
70
- // the `financialyear` query param, NOT the body: Fortnox treats VoucherYear in
71
- // the body as read-only (rejects it with error 2000321) and derives it from the
72
- // voucher itself.
73
- export async function createVoucherFileConnection(series, voucherNumber, fileId, financialYear) {
74
- const data = await fortnoxRequest('voucherfileconnections', {
75
- method: 'POST',
76
- body: {
77
- VoucherFileConnection: {
78
- FileId: fileId,
79
- VoucherSeries: series,
80
- VoucherNumber: voucherNumber,
27
+ async function getVoucher(series, voucherNumber, financialYear) {
28
+ const params = {};
29
+ if (financialYear)
30
+ params.financialyear = financialYear;
31
+ const data = await transport.request(`vouchers/${voucherSeriesSegment(series)}/${encodeURIComponent(voucherNumber)}`, { params });
32
+ return data.Voucher;
33
+ }
34
+ async function createVoucher(params) {
35
+ const data = await transport.request('vouchers', {
36
+ method: 'POST',
37
+ body: {
38
+ Voucher: {
39
+ ...params,
40
+ VoucherSeries: params.VoucherSeries || 'A',
41
+ },
81
42
  },
82
- },
83
- params: financialYear !== undefined ? { financialyear: financialYear } : undefined,
84
- });
85
- return data.VoucherFileConnection;
86
- }
87
- // Resolve the financial year from the voucher's transaction date when not given.
88
- // Throws (rather than silently leaving the year undefined) when it can't be
89
- // determined, so the user knows to pass --year explicitly — e.g. for a voucher
90
- // in a past financial year, which getVoucher can't fetch without the year.
91
- async function resolveVoucherFinancialYear(series, voucherNumber) {
92
- const voucher = await getVoucher(series, voucherNumber);
93
- const date = voucher.TransactionDate;
94
- if (!date) {
95
- throw new Error(`Could not determine the financial year: voucher ${series}/${voucherNumber} has no TransactionDate. Pass --year explicitly.`);
43
+ });
44
+ return data.Voucher;
96
45
  }
97
- const fy = await listFinancialYears({ date });
98
- const list = (fy.FinancialYears ?? []);
99
- if (!list.length) {
100
- throw new Error(`No financial year found for voucher date ${date}. Pass --year explicitly.`);
46
+ const MIME_BY_EXT = {
47
+ '.pdf': 'application/pdf',
48
+ '.png': 'image/png',
49
+ '.jpg': 'image/jpeg',
50
+ '.jpeg': 'image/jpeg',
51
+ '.gif': 'image/gif',
52
+ '.webp': 'image/webp',
53
+ '.heic': 'image/heic',
54
+ '.tif': 'image/tiff',
55
+ '.tiff': 'image/tiff',
56
+ '.txt': 'text/plain',
57
+ '.csv': 'text/csv',
58
+ '.xml': 'application/xml',
59
+ };
60
+ function mimeForFile(filePath) {
61
+ return MIME_BY_EXT[extname(filePath).toLowerCase()] ?? 'application/octet-stream';
101
62
  }
102
- return Number(list[0].Id);
103
- }
104
- // Orchestrate: resolve year if omitted, then upload+connect each file in order.
105
- export async function attachVoucherFiles(params) {
106
- // Pre-flight: confirm every file exists before uploading any of them, so a
107
- // typo in a later path can't leave earlier files orphaned in the inbox.
108
- for (const filePath of params.filePaths) {
109
- if (!existsSync(filePath)) {
110
- throw new Error(`File not found: ${filePath}`);
63
+ // Best-effort reverse of MIME_BY_EXT, for naming a downloaded file when the
64
+ // caller doesn't specify an output path.
65
+ const EXT_BY_MIME = Object.fromEntries(Object.entries(MIME_BY_EXT).map(([ext, mime]) => [mime, ext]));
66
+ function extensionForMime(contentType) {
67
+ return EXT_BY_MIME[contentType] ?? '';
68
+ }
69
+ // Upload a single file to the Fortnox inbox; returns the archived File object (has .Id).
70
+ async function uploadInboxFile(filePath) {
71
+ const buf = readFileSync(filePath);
72
+ const form = new FormData();
73
+ form.append('file', new Blob([buf], { type: mimeForFile(filePath) }), basename(filePath));
74
+ const data = await transport.request('inbox', {
75
+ method: 'POST',
76
+ rawBody: form,
77
+ });
78
+ return data.File;
79
+ }
80
+ // Link an already-uploaded file (by id) to a voucher. The financial year goes in
81
+ // the `financialyear` query param, NOT the body: Fortnox treats VoucherYear in
82
+ // the body as read-only (rejects it with error 2000321) and derives it from the
83
+ // voucher itself.
84
+ async function createVoucherFileConnection(series, voucherNumber, fileId, financialYear) {
85
+ const data = await transport.request('voucherfileconnections', {
86
+ method: 'POST',
87
+ body: {
88
+ VoucherFileConnection: {
89
+ FileId: fileId,
90
+ VoucherSeries: series,
91
+ VoucherNumber: voucherNumber,
92
+ },
93
+ },
94
+ params: financialYear !== undefined ? { financialyear: financialYear } : undefined,
95
+ });
96
+ return data.VoucherFileConnection;
97
+ }
98
+ // Resolve the financial year from the voucher's transaction date when not given.
99
+ // Throws (rather than silently leaving the year undefined) when it can't be
100
+ // determined, so the user knows to pass --year explicitly — e.g. for a voucher
101
+ // in a past financial year, which getVoucher can't fetch without the year.
102
+ async function resolveVoucherFinancialYear(series, voucherNumber) {
103
+ const voucher = await getVoucher(series, voucherNumber);
104
+ const date = voucher.TransactionDate;
105
+ if (!date) {
106
+ throw new Error(`Could not determine the financial year: voucher ${series}/${voucherNumber} has no TransactionDate. Pass --year explicitly.`);
111
107
  }
112
- if (!statSync(filePath).isFile()) {
113
- throw new Error(`Not a file: ${filePath}`);
108
+ const fy = await listFinancialYears({ date });
109
+ const list = (fy.FinancialYears ?? []);
110
+ if (!list.length) {
111
+ throw new Error(`No financial year found for voucher date ${date}. Pass --year explicitly.`);
114
112
  }
113
+ return Number(list[0].Id);
115
114
  }
116
- const year = params.financialYear ??
117
- (await resolveVoucherFinancialYear(params.series, params.voucherNumber));
118
- const results = [];
119
- for (const filePath of params.filePaths) {
120
- try {
121
- const file = await uploadInboxFile(filePath);
122
- // Per Fortnox docs (best-practices/vouchers): use the uploaded file's
123
- // `Id` as the VoucherFileConnection FileId — NOT ArchiveFileId.
124
- const fileId = String(file.Id);
125
- const connection = await createVoucherFileConnection(params.series, params.voucherNumber, fileId, year);
126
- results.push({ fileName: basename(filePath), fileId, voucherYear: year, connection });
115
+ // Orchestrate: resolve year if omitted, then upload+connect each file in order.
116
+ async function attachVoucherFiles(params) {
117
+ // Pre-flight: confirm every file exists before uploading any of them, so a
118
+ // typo in a later path can't leave earlier files orphaned in the inbox.
119
+ for (const filePath of params.filePaths) {
120
+ if (!existsSync(filePath)) {
121
+ throw new Error(`File not found: ${filePath}`);
122
+ }
123
+ if (!statSync(filePath).isFile()) {
124
+ throw new Error(`Not a file: ${filePath}`);
125
+ }
127
126
  }
128
- catch (err) {
129
- // Surface what already succeeded so the user can locate/clean up any files
130
- // uploaded to the inbox before this failure.
131
- const done = results.map((r) => r.fileName).join(', ') || 'none';
132
- const detail = err instanceof Error ? err.message : String(err);
133
- throw new Error(`Failed attaching "${basename(filePath)}" to voucher ${params.series}/${params.voucherNumber}: ${detail}. Files already attached this run: ${done}.`);
127
+ const year = params.financialYear ??
128
+ (await resolveVoucherFinancialYear(params.series, params.voucherNumber));
129
+ const results = [];
130
+ for (const filePath of params.filePaths) {
131
+ try {
132
+ const file = await uploadInboxFile(filePath);
133
+ // Per Fortnox docs (best-practices/vouchers): use the uploaded file's
134
+ // `Id` as the VoucherFileConnection FileId — NOT ArchiveFileId.
135
+ const fileId = String(file.Id);
136
+ const connection = await createVoucherFileConnection(params.series, params.voucherNumber, fileId, year);
137
+ results.push({ fileName: basename(filePath), fileId, voucherYear: year, connection });
138
+ }
139
+ catch (err) {
140
+ // Surface what already succeeded so the user can locate/clean up any files
141
+ // uploaded to the inbox before this failure.
142
+ const done = results.map((r) => r.fileName).join(', ') || 'none';
143
+ const detail = err instanceof Error ? err.message : String(err);
144
+ throw new Error(`Failed attaching "${basename(filePath)}" to voucher ${params.series}/${params.voucherNumber}: ${detail}. Files already attached this run: ${done}.`);
145
+ }
134
146
  }
147
+ return results;
148
+ }
149
+ // List the files already attached to a voucher — the read counterpart to
150
+ // attachVoucherFiles. `financialYear` is optional (Fortnox will match across
151
+ // years without it) but recommended: voucher numbers reset every financial
152
+ // year, so series+number alone can be ambiguous.
153
+ async function listVoucherAttachments(series, voucherNumber, financialYear) {
154
+ const data = await transport.request('voucherfileconnections', {
155
+ params: {
156
+ voucherseries: series,
157
+ vouchernumber: voucherNumber,
158
+ voucheryear: financialYear,
159
+ },
160
+ });
161
+ return (data.VoucherFileConnections ?? []).map((c) => ({
162
+ fileName: String(c.Name ?? ''),
163
+ fileId: String(c.FileId),
164
+ voucherSeries: String(c.VoucherSeries ?? series),
165
+ voucherNumber: String(c.VoucherNumber ?? voucherNumber),
166
+ voucherYear: c.VoucherYear !== undefined ? Number(c.VoucherYear) : undefined,
167
+ }));
135
168
  }
136
- return results;
169
+ // Download the actual bytes of a file attached to a voucher (or sitting in
170
+ // the inbox generally) — the read counterpart to uploadInboxFile. fileId
171
+ // comes from listVoucherAttachments (its `fileId`) or from a prior
172
+ // uploadInboxFile/attachVoucherFiles call.
173
+ async function getVoucherFile(fileId) {
174
+ const { buffer, contentType } = await transport.requestFile(`inbox/${encodeURIComponent(fileId)}`);
175
+ return { fileId, contentType, buffer };
176
+ }
177
+ return {
178
+ listVouchers,
179
+ getVoucher,
180
+ createVoucher,
181
+ uploadInboxFile,
182
+ createVoucherFileConnection,
183
+ attachVoucherFiles,
184
+ listVoucherAttachments,
185
+ getVoucherFile,
186
+ extensionForMime,
187
+ };
137
188
  }
189
+ export const { listVouchers, getVoucher, createVoucher, uploadInboxFile, createVoucherFileConnection, attachVoucherFiles, listVoucherAttachments, getVoucherFile, extensionForMime, } = createVoucherOperations(defaultFortnoxTransport);
138
190
  //# sourceMappingURL=vouchers.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"vouchers.js","sourceRoot":"","sources":["../../src/operations/vouchers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAqB1D,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,SAA6B,EAAE;IAChE,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IACtF,MAAM,QAAQ,GAAG,YAAY,OAAO,EAAE,CAAC;IACvC,MAAM,WAAW,GAAgD;QAC/D,aAAa,EAAE,MAAM,CAAC,aAAa;QACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;QACzB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;IAEF,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;QACf,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,aAAa,CACnD,QAAQ,EACR,UAAU,EACV,WAAW,CACZ,CAAC;QACF,OAAO;YACL,QAAQ,EAAE,KAAK;YACf,eAAe,EAAE,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE;SAC5F,CAAC;IACJ,CAAC;IAED,OAAO,cAAc,CAAmB,QAAQ,EAAE;QAChD,MAAM,EAAE,EAAE,GAAG,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE;KAC/E,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,MAAc,EACd,aAAqB,EACrB,aAAsB;IAEtB,MAAM,MAAM,GAAgD,EAAE,CAAC;IAC/D,IAAI,aAAa;QAAE,MAAM,CAAC,aAAa,GAAG,aAAa,CAAC;IACxD,MAAM,IAAI,GAAG,MAAM,cAAc,CAC/B,YAAY,oBAAoB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,aAAa,CAAC,EAAE,EAC/E,EAAE,MAAM,EAAE,CACX,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,MAA+B;IAE/B,MAAM,IAAI,GAAG,MAAM,cAAc,CAAkB,UAAU,EAAE;QAC7D,MAAM,EAAE,MAAM;QACd,IAAI,EAAE;YACJ,OAAO,EAAE;gBACP,GAAG,MAAM;gBACT,aAAa,EAAG,MAAM,CAAC,aAAwB,IAAI,GAAG;aACvD;SACF;KACF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC;AASD,MAAM,WAAW,GAA2B;IAC1C,MAAM,EAAE,iBAAiB;IACzB,MAAM,EAAE,WAAW;IACnB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,WAAW;IACnB,OAAO,EAAE,YAAY;IACrB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;IACpB,OAAO,EAAE,YAAY;IACrB,MAAM,EAAE,YAAY;IACpB,MAAM,EAAE,UAAU;IAClB,MAAM,EAAE,iBAAiB;CAC1B,CAAC;AAEF,SAAS,WAAW,CAAC,QAAgB;IACnC,OAAO,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,0BAA0B,CAAC;AACpF,CAAC;AAED,yFAAyF;AACzF,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,QAAgB;IACpD,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IACnC,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC1F,MAAM,IAAI,GAAG,MAAM,cAAc,CAAoB,OAAO,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IACjG,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,iFAAiF;AACjF,+EAA+E;AAC/E,gFAAgF;AAChF,kBAAkB;AAClB,MAAM,CAAC,KAAK,UAAU,2BAA2B,CAC/C,MAAc,EACd,aAAqB,EACrB,MAAc,EACd,aAAsB;IAEtB,MAAM,IAAI,GAAG,MAAM,cAAc,CAAgC,wBAAwB,EAAE;QACzF,MAAM,EAAE,MAAM;QACd,IAAI,EAAE;YACJ,qBAAqB,EAAE;gBACrB,MAAM,EAAE,MAAM;gBACd,aAAa,EAAE,MAAM;gBACrB,aAAa,EAAE,aAAa;aAC7B;SACF;QACD,MAAM,EAAE,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS;KACnF,CAAC,CAAC;IACH,OAAO,IAAI,CAAC,qBAAqB,CAAC;AACpC,CAAC;AAeD,iFAAiF;AACjF,4EAA4E;AAC5E,+EAA+E;AAC/E,2EAA2E;AAC3E,KAAK,UAAU,2BAA2B,CAAC,MAAc,EAAE,aAAqB;IAC9E,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;IACxD,MAAM,IAAI,GAAI,OAAmC,CAAC,eAAqC,CAAC;IACxF,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,IAAI,aAAa,kDAAkD,CAC7H,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,GAAG,MAAM,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,cAAc,IAAI,EAAE,CAA8B,CAAC;IACpE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;QACjB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,2BAA2B,CAAC,CAAC;IAC/F,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC;AAC7B,CAAC;AAED,gFAAgF;AAChF,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,MAAgC;IAEhC,2EAA2E;IAC3E,wEAAwE;IACxE,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;QACjD,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;QAC7C,CAAC;IACH,CAAC;IAED,MAAM,IAAI,GACR,MAAM,CAAC,aAAa;QACpB,CAAC,MAAM,2BAA2B,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;IAE3E,MAAM,OAAO,GAA4B,EAAE,CAAC;IAC5C,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;QACxC,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;YAC7C,sEAAsE;YACtE,gEAAgE;YAChE,MAAM,MAAM,GAAG,MAAM,CAAE,IAAgC,CAAC,EAAE,CAAC,CAAC;YAC5D,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAClD,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,aAAa,EACpB,MAAM,EACN,IAAI,CACL,CAAC;YACF,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;QACxF,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,2EAA2E;YAC3E,6CAA6C;YAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;YACjE,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YAChE,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,aAAa,KAAK,MAAM,sCAAsC,IAAI,GAAG,CACrJ,CAAC;QACJ,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"vouchers.js","sourceRoot":"","sources":["../../src/operations/vouchers.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAC9C,OAAO,EAAE,uBAAuB,EAAyB,MAAM,sBAAsB,CAAC;AACtF,OAAO,EAAE,oBAAoB,EAAE,MAAM,mBAAmB,CAAC;AACzD,OAAO,EAAE,6BAA6B,EAAE,MAAM,sBAAsB,CAAC;AAiDrE,MAAM,UAAU,uBAAuB,CAAC,SAA2B;IACjE,MAAM,EAAE,kBAAkB,EAAE,GAAG,6BAA6B,CAAC,SAAS,CAAC,CAAC;IAExE,KAAK,UAAU,YAAY,CAAC,SAA6B,EAAE;QACzD,MAAM,OAAO,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,oBAAoB,CAAC,MAAM,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,MAAM,QAAQ,GAAG,YAAY,OAAO,EAAE,CAAC;QACvC,MAAM,WAAW,GAAgD;YAC/D,aAAa,EAAE,MAAM,CAAC,aAAa;YACnC,QAAQ,EAAE,MAAM,CAAC,QAAQ;YACzB,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC;QAEF,IAAI,MAAM,CAAC,GAAG,EAAE,CAAC;YACf,MAAM,EAAE,KAAK,EAAE,cAAc,EAAE,GAAG,MAAM,SAAS,CAAC,aAAa,CAC7D,QAAQ,EACR,UAAU,EACV,WAAW,CACZ,CAAC;YACF,OAAO;gBACL,QAAQ,EAAE,KAAK;gBACf,eAAe,EAAE,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,CAAC,EAAE,cAAc,EAAE,CAAC,EAAE;aAC5F,CAAC;QACJ,CAAC;QAED,OAAO,SAAS,CAAC,OAAO,CAAmB,QAAQ,EAAE;YACnD,MAAM,EAAE,EAAE,GAAG,WAAW,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,GAAG,EAAE;SAC/E,CAAC,CAAC;IACL,CAAC;IAED,KAAK,UAAU,UAAU,CACvB,MAAc,EACd,aAAqB,EACrB,aAAsB;QAEtB,MAAM,MAAM,GAAgD,EAAE,CAAC;QAC/D,IAAI,aAAa;YAAE,MAAM,CAAC,aAAa,GAAG,aAAa,CAAC;QACxD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAClC,YAAY,oBAAoB,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,aAAa,CAAC,EAAE,EAC/E,EAAE,MAAM,EAAE,CACX,CAAC;QACF,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,KAAK,UAAU,aAAa,CAAC,MAA+B;QAC1D,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAkB,UAAU,EAAE;YAChE,MAAM,EAAE,MAAM;YACd,IAAI,EAAE;gBACJ,OAAO,EAAE;oBACP,GAAG,MAAM;oBACT,aAAa,EAAG,MAAM,CAAC,aAAwB,IAAI,GAAG;iBACvD;aACF;SACF,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,OAAO,CAAC;IACtB,CAAC;IAYD,MAAM,WAAW,GAA2B;QAC1C,MAAM,EAAE,iBAAiB;QACzB,MAAM,EAAE,WAAW;QACnB,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,WAAW;QACnB,OAAO,EAAE,YAAY;QACrB,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,YAAY;QACpB,OAAO,EAAE,YAAY;QACrB,MAAM,EAAE,YAAY;QACpB,MAAM,EAAE,UAAU;QAClB,MAAM,EAAE,iBAAiB;KAC1B,CAAC;IAEF,SAAS,WAAW,CAAC,QAAgB;QACnC,OAAO,WAAW,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,WAAW,EAAE,CAAC,IAAI,0BAA0B,CAAC;IACpF,CAAC;IAED,4EAA4E;IAC5E,yCAAyC;IACzC,MAAM,WAAW,GAA2B,MAAM,CAAC,WAAW,CAC5D,MAAM,CAAC,OAAO,CAAC,WAAW,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,CAC9D,CAAC;IAEF,SAAS,gBAAgB,CAAC,WAAmB;QAC3C,OAAO,WAAW,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC;IACxC,CAAC;IAED,yFAAyF;IACzF,KAAK,UAAU,eAAe,CAAC,QAAgB;QAC7C,MAAM,GAAG,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,CAAC,GAAG,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC,QAAQ,CAAC,CAAC,CAAC;QAC1F,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAoB,OAAO,EAAE;YAC/D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,IAAI;SACd,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,iFAAiF;IACjF,+EAA+E;IAC/E,gFAAgF;IAChF,kBAAkB;IAClB,KAAK,UAAU,2BAA2B,CACxC,MAAc,EACd,aAAqB,EACrB,MAAc,EACd,aAAsB;QAEtB,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAAgC,wBAAwB,EAAE;YAC5F,MAAM,EAAE,MAAM;YACd,IAAI,EAAE;gBACJ,qBAAqB,EAAE;oBACrB,MAAM,EAAE,MAAM;oBACd,aAAa,EAAE,MAAM;oBACrB,aAAa,EAAE,aAAa;iBAC7B;aACF;YACD,MAAM,EAAE,aAAa,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,aAAa,EAAE,aAAa,EAAE,CAAC,CAAC,CAAC,SAAS;SACnF,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,qBAAqB,CAAC;IACpC,CAAC;IAED,iFAAiF;IACjF,4EAA4E;IAC5E,+EAA+E;IAC/E,2EAA2E;IAC3E,KAAK,UAAU,2BAA2B,CACxC,MAAc,EACd,aAAqB;QAErB,MAAM,OAAO,GAAG,MAAM,UAAU,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC;QACxD,MAAM,IAAI,GAAI,OAAmC,CAAC,eAAqC,CAAC;QACxF,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,IAAI,aAAa,kDAAkD,CAC7H,CAAC;QACJ,CAAC;QACD,MAAM,EAAE,GAAG,MAAM,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;QAC9C,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC,cAAc,IAAI,EAAE,CAA8B,CAAC;QACpE,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,CAAC;YACjB,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,2BAA2B,CAAC,CAAC;QAC/F,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,CAAE,CAAC,EAAE,CAAC,CAAC;IAC7B,CAAC;IAED,gFAAgF;IAChF,KAAK,UAAU,kBAAkB,CAC/B,MAAgC;QAEhC,2EAA2E;QAC3E,wEAAwE;QACxE,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;gBAC1B,MAAM,IAAI,KAAK,CAAC,mBAAmB,QAAQ,EAAE,CAAC,CAAC;YACjD,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBACjC,MAAM,IAAI,KAAK,CAAC,eAAe,QAAQ,EAAE,CAAC,CAAC;YAC7C,CAAC;QACH,CAAC;QAED,MAAM,IAAI,GACR,MAAM,CAAC,aAAa;YACpB,CAAC,MAAM,2BAA2B,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC;QAE3E,MAAM,OAAO,GAA4B,EAAE,CAAC;QAC5C,KAAK,MAAM,QAAQ,IAAI,MAAM,CAAC,SAAS,EAAE,CAAC;YACxC,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;gBAC7C,sEAAsE;gBACtE,gEAAgE;gBAChE,MAAM,MAAM,GAAG,MAAM,CAAE,IAAgC,CAAC,EAAE,CAAC,CAAC;gBAC5D,MAAM,UAAU,GAAG,MAAM,2BAA2B,CAClD,MAAM,CAAC,MAAM,EACb,MAAM,CAAC,aAAa,EACpB,MAAM,EACN,IAAI,CACL,CAAC;gBACF,OAAO,CAAC,IAAI,CAAC,EAAE,QAAQ,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,CAAC;YACxF,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,2EAA2E;gBAC3E,6CAA6C;gBAC7C,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,MAAM,CAAC;gBACjE,MAAM,MAAM,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChE,MAAM,IAAI,KAAK,CACb,qBAAqB,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,aAAa,KAAK,MAAM,sCAAsC,IAAI,GAAG,CACrJ,CAAC;YACJ,CAAC;QACH,CAAC;QACD,OAAO,OAAO,CAAC;IACjB,CAAC;IAED,yEAAyE;IACzE,6EAA6E;IAC7E,2EAA2E;IAC3E,iDAAiD;IACjD,KAAK,UAAU,sBAAsB,CACnC,MAAc,EACd,aAAqB,EACrB,aAAsB;QAEtB,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,OAAO,CAClC,wBAAwB,EACxB;YACE,MAAM,EAAE;gBACN,aAAa,EAAE,MAAM;gBACrB,aAAa,EAAE,aAAa;gBAC5B,WAAW,EAAE,aAAa;aAC3B;SACF,CACF,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,sBAAsB,IAAI,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YACrD,QAAQ,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC;YAC9B,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC;YACxB,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,IAAI,MAAM,CAAC;YAChD,aAAa,EAAE,MAAM,CAAC,CAAC,CAAC,aAAa,IAAI,aAAa,CAAC;YACvD,WAAW,EAAE,CAAC,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,SAAS;SAC7E,CAAC,CAAC,CAAC;IACN,CAAC;IAED,2EAA2E;IAC3E,yEAAyE;IACzE,mEAAmE;IACnE,2CAA2C;IAC3C,KAAK,UAAU,cAAc,CAAC,MAAc;QAC1C,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,SAAS,CAAC,WAAW,CACzD,SAAS,kBAAkB,CAAC,MAAM,CAAC,EAAE,CACtC,CAAC;QACF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,CAAC;IACzC,CAAC;IAED,OAAO;QACL,YAAY;QACZ,UAAU;QACV,aAAa;QACb,eAAe;QACf,2BAA2B;QAC3B,kBAAkB;QAClB,sBAAsB;QACtB,cAAc;QACd,gBAAgB;KACjB,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,EACX,YAAY,EACZ,UAAU,EACV,aAAa,EACb,eAAe,EACf,2BAA2B,EAC3B,kBAAkB,EAClB,sBAAsB,EACtB,cAAc,EACd,gBAAgB,GACjB,GAAG,uBAAuB,CAAC,uBAAuB,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { SchemaAuditMapping } from './schema-audit.js';
2
+ /**
3
+ * First-wave write-schema coverage mappings.
4
+ *
5
+ * Component names are already part of the committed opaque API fingerprint. The
6
+ * OpenAPI document and its property names remain in the git-ignored local cache.
7
+ */
8
+ export declare const SCHEMA_AUDIT_MAPPINGS: readonly SchemaAuditMapping[];
9
+ //# sourceMappingURL=schema-audit-mappings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-audit-mappings.d.ts","sourceRoot":"","sources":["../src/schema-audit-mappings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAE5D;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,EAAE,SAAS,kBAAkB,EAqC9D,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * First-wave write-schema coverage mappings.
3
+ *
4
+ * Component names are already part of the committed opaque API fingerprint. The
5
+ * OpenAPI document and its property names remain in the git-ignored local cache.
6
+ */
7
+ export const SCHEMA_AUDIT_MAPPINGS = [
8
+ {
9
+ id: 'invoice-row',
10
+ toolName: 'fortnox_create_invoice',
11
+ toolSchemaPointer: '/properties/InvoiceRows/items',
12
+ specSchemaName: 'fortnox_Kf_InvoiceRowSinglePayloadItem',
13
+ },
14
+ {
15
+ id: 'offer-row',
16
+ toolName: 'fortnox_create_offer',
17
+ toolSchemaPointer: '/properties/OfferRows/items',
18
+ specSchemaName: 'fortnox_Offer_OfferRowSinglePayloadItem',
19
+ },
20
+ {
21
+ id: 'order-row',
22
+ toolName: 'fortnox_create_order',
23
+ toolSchemaPointer: '/properties/OrderRows/items',
24
+ specSchemaName: 'fortnox_Order_OrderRowSinglePayloadItem',
25
+ },
26
+ {
27
+ id: 'supplier',
28
+ toolName: 'fortnox_create_supplier',
29
+ toolSchemaPointer: '',
30
+ specSchemaName: 'fortnox_Lf_SupplierSinglePayloadItem',
31
+ },
32
+ {
33
+ id: 'supplier-invoice-row',
34
+ toolName: 'fortnox_create_supplier_invoice',
35
+ toolSchemaPointer: '/properties/SupplierInvoiceRows/items',
36
+ specSchemaName: 'fortnox_Lf_SupplierInvoiceRowSinglePayloadItem',
37
+ },
38
+ {
39
+ id: 'voucher-row',
40
+ toolName: 'fortnox_create_voucher',
41
+ toolSchemaPointer: '/properties/VoucherRows/items',
42
+ specSchemaName: 'fortnox_Bf_VoucherRowSinglePayloadItem',
43
+ },
44
+ ];
45
+ //# sourceMappingURL=schema-audit-mappings.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-audit-mappings.js","sourceRoot":"","sources":["../src/schema-audit-mappings.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAkC;IAClE;QACE,EAAE,EAAE,aAAa;QACjB,QAAQ,EAAE,wBAAwB;QAClC,iBAAiB,EAAE,+BAA+B;QAClD,cAAc,EAAE,wCAAwC;KACzD;IACD;QACE,EAAE,EAAE,WAAW;QACf,QAAQ,EAAE,sBAAsB;QAChC,iBAAiB,EAAE,6BAA6B;QAChD,cAAc,EAAE,yCAAyC;KAC1D;IACD;QACE,EAAE,EAAE,WAAW;QACf,QAAQ,EAAE,sBAAsB;QAChC,iBAAiB,EAAE,6BAA6B;QAChD,cAAc,EAAE,yCAAyC;KAC1D;IACD;QACE,EAAE,EAAE,UAAU;QACd,QAAQ,EAAE,yBAAyB;QACnC,iBAAiB,EAAE,EAAE;QACrB,cAAc,EAAE,sCAAsC;KACvD;IACD;QACE,EAAE,EAAE,sBAAsB;QAC1B,QAAQ,EAAE,iCAAiC;QAC3C,iBAAiB,EAAE,uCAAuC;QAC1D,cAAc,EAAE,gDAAgD;KACjE;IACD;QACE,EAAE,EAAE,aAAa;QACjB,QAAQ,EAAE,wBAAwB;QAClC,iBAAiB,EAAE,+BAA+B;QAClD,cAAc,EAAE,wCAAwC;KACzD;CACF,CAAC"}
@@ -0,0 +1,45 @@
1
+ type JsonObject = Record<string, unknown>;
2
+ export interface DiscoveredToolSchema {
3
+ name: string;
4
+ inputSchema: JsonObject;
5
+ }
6
+ export interface SchemaAuditMapping {
7
+ /** Stable public identifier used in logs and the opaque baseline. */
8
+ id: string;
9
+ toolName: string;
10
+ /** JSON Pointer from the tool's inputSchema to the object being compared. */
11
+ toolSchemaPointer: string;
12
+ /** Component name under components.schemas in the local OpenAPI cache. */
13
+ specSchemaName: string;
14
+ ignoredProperties?: readonly string[];
15
+ }
16
+ export interface SchemaAuditResult {
17
+ id: string;
18
+ declaredPropertyCount: number;
19
+ specificationPropertyCount: number;
20
+ ignoredProperties: string[];
21
+ missingProperties: string[];
22
+ stateHash: string;
23
+ }
24
+ export interface SchemaAuditBaselineRecord {
25
+ id: string;
26
+ declaredPropertyCount: number;
27
+ specificationPropertyCount: number;
28
+ missingPropertyCount: number;
29
+ stateHash: string;
30
+ }
31
+ export interface SchemaAuditBaseline {
32
+ formatVersion: 1;
33
+ records: SchemaAuditBaselineRecord[];
34
+ }
35
+ export interface SchemaAuditComparison {
36
+ matches: boolean;
37
+ changedMappingIds: string[];
38
+ }
39
+ export declare function auditSchemaCoverage(spec: unknown, tools: readonly DiscoveredToolSchema[], mappings: readonly SchemaAuditMapping[]): SchemaAuditResult[];
40
+ export declare function toAuditBaseline(results: readonly SchemaAuditResult[]): SchemaAuditBaseline;
41
+ export declare function compareAuditBaselines(expected: SchemaAuditBaseline, current: SchemaAuditBaseline): SchemaAuditComparison;
42
+ export declare function formatAuditSummary(results: readonly SchemaAuditResult[], comparison?: SchemaAuditComparison): string;
43
+ export declare function formatAuditFields(results: readonly SchemaAuditResult[]): string;
44
+ export {};
45
+ //# sourceMappingURL=schema-audit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-audit.d.ts","sourceRoot":"","sources":["../src/schema-audit.ts"],"names":[],"mappings":"AAIA,KAAK,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAE1C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,UAAU,CAAC;CACzB;AAED,MAAM,WAAW,kBAAkB;IACjC,qEAAqE;IACrE,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,6EAA6E;IAC7E,iBAAiB,EAAE,MAAM,CAAC;IAC1B,0EAA0E;IAC1E,cAAc,EAAE,MAAM,CAAC;IACvB,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACvC;AAED,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB,EAAE,MAAM,CAAC;IAC9B,0BAA0B,EAAE,MAAM,CAAC;IACnC,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,iBAAiB,EAAE,MAAM,EAAE,CAAC;IAC5B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,EAAE,EAAE,MAAM,CAAC;IACX,qBAAqB,EAAE,MAAM,CAAC;IAC9B,0BAA0B,EAAE,MAAM,CAAC;IACnC,oBAAoB,EAAE,MAAM,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,aAAa,EAAE,CAAC,CAAC;IACjB,OAAO,EAAE,yBAAyB,EAAE,CAAC;CACtC;AAED,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,MAAM,EAAE,CAAC;CAC7B;AAmDD,wBAAgB,mBAAmB,CACjC,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,SAAS,oBAAoB,EAAE,EACtC,QAAQ,EAAE,SAAS,kBAAkB,EAAE,GACtC,iBAAiB,EAAE,CAgDrB;AAED,wBAAgB,eAAe,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GAAG,mBAAmB,CAa1F;AAMD,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,mBAAmB,EAC7B,OAAO,EAAE,mBAAmB,GAC3B,qBAAqB,CAevB;AAED,wBAAgB,kBAAkB,CAChC,OAAO,EAAE,SAAS,iBAAiB,EAAE,EACrC,UAAU,CAAC,EAAE,qBAAqB,GACjC,MAAM,CASR;AAED,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,SAAS,iBAAiB,EAAE,GAAG,MAAM,CAU/E"}
@@ -0,0 +1,132 @@
1
+ import { createHash } from 'node:crypto';
2
+ const HASH_DOMAIN = 'noxctl-openapi-tool-schema-audit/v1';
3
+ function asObject(value, description) {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
5
+ throw new Error(`${description} is not an object`);
6
+ }
7
+ return value;
8
+ }
9
+ function compareText(left, right) {
10
+ return left < right ? -1 : left > right ? 1 : 0;
11
+ }
12
+ function decodePointerSegment(segment) {
13
+ return segment.replaceAll('~1', '/').replaceAll('~0', '~');
14
+ }
15
+ function resolvePointer(root, pointer, description) {
16
+ if (pointer === '')
17
+ return root;
18
+ if (!pointer.startsWith('/')) {
19
+ throw new Error(`${description} pointer must be empty or start with "/"`);
20
+ }
21
+ let current = root;
22
+ for (const encodedSegment of pointer.slice(1).split('/')) {
23
+ const segment = decodePointerSegment(encodedSegment);
24
+ const object = asObject(current, `${description} pointer parent`);
25
+ if (!Object.hasOwn(object, segment)) {
26
+ throw new Error(`${description} pointer not found`);
27
+ }
28
+ current = object[segment];
29
+ }
30
+ return current;
31
+ }
32
+ function sortedPropertyNames(schema, description) {
33
+ const object = asObject(schema, description);
34
+ const properties = asObject(object['properties'], `${description} properties`);
35
+ return Object.keys(properties).sort(compareText);
36
+ }
37
+ function stateHash(mappingId, ignored, missing) {
38
+ const canonical = JSON.stringify({
39
+ domain: HASH_DOMAIN,
40
+ mappingId,
41
+ ignored,
42
+ missing,
43
+ });
44
+ return createHash('sha256').update(canonical, 'utf8').digest('hex');
45
+ }
46
+ export function auditSchemaCoverage(spec, tools, mappings) {
47
+ const specObject = asObject(spec, 'OpenAPI document');
48
+ const components = asObject(specObject['components'], 'OpenAPI components');
49
+ const schemas = asObject(components['schemas'], 'OpenAPI component schemas');
50
+ const toolsByName = new Map(tools.map((tool) => [tool.name, tool]));
51
+ const seenIds = new Set();
52
+ const results = mappings.map((mapping) => {
53
+ if (seenIds.has(mapping.id)) {
54
+ throw new Error(`Duplicate schema-audit mapping id: ${mapping.id}`);
55
+ }
56
+ seenIds.add(mapping.id);
57
+ const tool = toolsByName.get(mapping.toolName);
58
+ if (!tool)
59
+ throw new Error(`Mapped tool not found: ${mapping.id}`);
60
+ if (!Object.hasOwn(schemas, mapping.specSchemaName)) {
61
+ throw new Error(`Mapped OpenAPI schema not found: ${mapping.id}`);
62
+ }
63
+ const toolSchema = resolvePointer(tool.inputSchema, mapping.toolSchemaPointer, `Tool schema for ${mapping.id}`);
64
+ const declared = sortedPropertyNames(toolSchema, `Tool schema for ${mapping.id}`);
65
+ const specification = sortedPropertyNames(schemas[mapping.specSchemaName], `OpenAPI schema for ${mapping.id}`);
66
+ const ignored = [...new Set(mapping.ignoredProperties ?? [])].sort(compareText);
67
+ const declaredSet = new Set(declared);
68
+ const ignoredSet = new Set(ignored);
69
+ const missing = specification.filter((property) => !declaredSet.has(property) && !ignoredSet.has(property));
70
+ return {
71
+ id: mapping.id,
72
+ declaredPropertyCount: declared.length,
73
+ specificationPropertyCount: specification.length,
74
+ ignoredProperties: ignored,
75
+ missingProperties: missing,
76
+ stateHash: stateHash(mapping.id, ignored, missing),
77
+ };
78
+ });
79
+ return results.sort((a, b) => compareText(a.id, b.id));
80
+ }
81
+ export function toAuditBaseline(results) {
82
+ return {
83
+ formatVersion: 1,
84
+ records: [...results]
85
+ .sort((a, b) => compareText(a.id, b.id))
86
+ .map((result) => ({
87
+ id: result.id,
88
+ declaredPropertyCount: result.declaredPropertyCount,
89
+ specificationPropertyCount: result.specificationPropertyCount,
90
+ missingPropertyCount: result.missingProperties.length,
91
+ stateHash: result.stateHash,
92
+ })),
93
+ };
94
+ }
95
+ function recordsById(baseline) {
96
+ return new Map(baseline.records.map((record) => [record.id, record]));
97
+ }
98
+ export function compareAuditBaselines(expected, current) {
99
+ const expectedById = recordsById(expected);
100
+ const currentById = recordsById(current);
101
+ const ids = new Set([...expectedById.keys(), ...currentById.keys()]);
102
+ const changedMappingIds = [...ids]
103
+ .filter((id) => JSON.stringify(expectedById.get(id)) !== JSON.stringify(currentById.get(id)))
104
+ .sort(compareText);
105
+ return {
106
+ matches: expected.formatVersion === current.formatVersion && changedMappingIds.length === 0,
107
+ changedMappingIds: expected.formatVersion === current.formatVersion
108
+ ? changedMappingIds
109
+ : ['$format', ...changedMappingIds],
110
+ };
111
+ }
112
+ export function formatAuditSummary(results, comparison) {
113
+ const status = comparison ? (comparison.matches ? 'ok' : 'drift') : 'generated';
114
+ const lines = [`Schema audit: ${status}`];
115
+ for (const result of [...results].sort((a, b) => compareText(a.id, b.id))) {
116
+ lines.push(`${result.id}: declared=${result.declaredPropertyCount} spec=${result.specificationPropertyCount} missing=${result.missingProperties.length} state=${result.stateHash}`);
117
+ }
118
+ return `${lines.join('\n')}\n`;
119
+ }
120
+ export function formatAuditFields(results) {
121
+ const lines = [];
122
+ for (const result of [...results].sort((a, b) => compareText(a.id, b.id))) {
123
+ lines.push(`${result.id}:`);
124
+ // Property names originate in a fetched document. JSON quoting preserves
125
+ // their exact value while preventing terminal control-sequence injection.
126
+ lines.push(...result.missingProperties.map((property) => ` - ${JSON.stringify(property)}`));
127
+ if (result.missingProperties.length === 0)
128
+ lines.push(' (none)');
129
+ }
130
+ return `${lines.join('\n')}\n`;
131
+ }
132
+ //# sourceMappingURL=schema-audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema-audit.js","sourceRoot":"","sources":["../src/schema-audit.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"scope-probes.d.ts","sourceRoot":"","sources":["../src/scope-probes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAkBtD,CAAC"}
1
+ {"version":3,"file":"scope-probes.d.ts","sourceRoot":"","sources":["../src/scope-probes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,eAAO,MAAM,mBAAmB,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAmBtD,CAAC"}
@@ -26,5 +26,6 @@ export const scopeProbeEndpoints = {
26
26
  inbox: 'inbox',
27
27
  connectfile: 'voucherfileconnections?limit=1',
28
28
  salary: 'employees?limit=1',
29
+ archive: 'archive',
29
30
  };
30
31
  //# sourceMappingURL=scope-probes.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"scope-probes.js","sourceRoot":"","sources":["../src/scope-probes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,OAAO,EAAE,kBAAkB;IAC3B,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EAAE,yBAAyB;IAClC,KAAK,EAAE,gBAAgB;IACvB,KAAK,EAAE,gBAAgB;IACvB,QAAQ,EAAE,mBAAmB;IAC7B,eAAe,EAAE,0BAA0B;IAC3C,WAAW,EAAE,kBAAkB;IAC/B,kBAAkB,EAAE,oBAAoB;IACxC,QAAQ,EAAE,kBAAkB;IAC5B,OAAO,EAAE,kBAAkB;IAC3B,UAAU,EAAE,qBAAqB;IACjC,KAAK,EAAE,oBAAoB;IAC3B,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,gCAAgC;IAC7C,MAAM,EAAE,mBAAmB;CAC5B,CAAC"}
1
+ {"version":3,"file":"scope-probes.js","sourceRoot":"","sources":["../src/scope-probes.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAA2B;IACzD,OAAO,EAAE,kBAAkB;IAC3B,QAAQ,EAAE,mBAAmB;IAC7B,OAAO,EAAE,kBAAkB;IAC3B,OAAO,EAAE,yBAAyB;IAClC,KAAK,EAAE,gBAAgB;IACvB,KAAK,EAAE,gBAAgB;IACvB,QAAQ,EAAE,mBAAmB;IAC7B,eAAe,EAAE,0BAA0B;IAC3C,WAAW,EAAE,kBAAkB;IAC/B,kBAAkB,EAAE,oBAAoB;IACxC,QAAQ,EAAE,kBAAkB;IAC5B,OAAO,EAAE,kBAAkB;IAC3B,UAAU,EAAE,qBAAqB;IACjC,KAAK,EAAE,oBAAoB;IAC3B,KAAK,EAAE,OAAO;IACd,WAAW,EAAE,gCAAgC;IAC7C,MAAM,EAAE,mBAAmB;IAC3B,OAAO,EAAE,SAAS;CACnB,CAAC"}