@ekwo-ai/mcp 0.4.1 → 0.6.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 (45) hide show
  1. package/README.md +36 -9
  2. package/dist/backend.d.ts.map +1 -1
  3. package/dist/backend.js +26 -2
  4. package/dist/backend.js.map +1 -1
  5. package/dist/bin.js +10 -17
  6. package/dist/bin.js.map +1 -1
  7. package/dist/index.d.ts +2 -0
  8. package/dist/index.d.ts.map +1 -1
  9. package/dist/index.js +2 -0
  10. package/dist/index.js.map +1 -1
  11. package/dist/schema.d.ts +1 -1
  12. package/dist/schema.js +1 -1
  13. package/dist/server.d.ts +1 -1
  14. package/dist/server.d.ts.map +1 -1
  15. package/dist/server.js +23 -5
  16. package/dist/server.js.map +1 -1
  17. package/dist/start.d.ts +17 -0
  18. package/dist/start.d.ts.map +1 -0
  19. package/dist/start.js +48 -0
  20. package/dist/start.js.map +1 -0
  21. package/dist/tools/import-books.d.ts +63 -0
  22. package/dist/tools/import-books.d.ts.map +1 -0
  23. package/dist/tools/import-books.js +84 -0
  24. package/dist/tools/import-books.js.map +1 -0
  25. package/dist/tools/write.d.ts +23 -2
  26. package/dist/tools/write.d.ts.map +1 -1
  27. package/dist/tools/write.js +35 -57
  28. package/dist/tools/write.js.map +1 -1
  29. package/dist/unconfigured.d.ts +26 -0
  30. package/dist/unconfigured.d.ts.map +1 -0
  31. package/dist/unconfigured.js +57 -0
  32. package/dist/unconfigured.js.map +1 -0
  33. package/package.json +6 -8
  34. package/dist/columns.d.ts +0 -59
  35. package/dist/columns.d.ts.map +0 -1
  36. package/dist/columns.js +0 -422
  37. package/dist/columns.js.map +0 -1
  38. package/dist/format.d.ts +0 -21
  39. package/dist/format.d.ts.map +0 -1
  40. package/dist/format.js +0 -49
  41. package/dist/format.js.map +0 -1
  42. package/dist/rounding.d.ts +0 -25
  43. package/dist/rounding.d.ts.map +0 -1
  44. package/dist/rounding.js +0 -35
  45. package/dist/rounding.js.map +0 -1
package/package.json CHANGED
@@ -1,7 +1,8 @@
1
1
  {
2
2
  "name": "@ekwo-ai/mcp",
3
- "version": "0.4.1",
4
- "description": "MCP server for Ekwo OS: let an AI assistant keep the books, under the user's own row level security.",
3
+ "version": "0.6.0",
4
+ "description": "MCP server for Ekwo OS: let an AI assistant work on the books, under the user's own row level security.",
5
+ "mcpName": "ai.ekwo/mcp",
5
6
  "keywords": [
6
7
  "mcp",
7
8
  "model-context-protocol",
@@ -27,7 +28,7 @@
27
28
  "node": ">=20"
28
29
  },
29
30
  "ekwo": {
30
- "schemaMin": "0.4.0"
31
+ "schemaMin": "0.6.0"
31
32
  },
32
33
  "files": [
33
34
  "dist",
@@ -49,11 +50,8 @@
49
50
  "typecheck": "tsc -p tsconfig.json --noEmit"
50
51
  },
51
52
  "dependencies": {
52
- "@ekwo-ai/camt053": "^0.4.0",
53
- "@ekwo-ai/cfonb120": "^0.4.0",
54
- "@ekwo-ai/coda": "^0.4.0",
55
- "@ekwo-ai/core": "^0.4.0",
56
- "@ekwo-ai/fec": "^0.4.0",
53
+ "@ekwo-ai/core": "^0.6.0",
54
+ "@ekwo-ai/fec": "^0.6.0",
57
55
  "@modelcontextprotocol/sdk": "^1.30.0",
58
56
  "@supabase/supabase-js": "^2.58.0",
59
57
  "zod": "^4.6.2"
package/dist/columns.d.ts DELETED
@@ -1,59 +0,0 @@
1
- /**
2
- * What each tool reads back, written once.
3
- *
4
- * Two rules run through every list. A `numeric` column is asked for as
5
- * `amount::text`, so the exact decimal arrives rather than a float; a `date`
6
- * or a timestamp likewise, so `2026-06-15` is a string on both routes instead
7
- * of whatever a driver decided a date object should be. Everything else —
8
- * uuid, text, boolean, integer — crosses unchanged.
9
- */
10
- export declare const COMPANY: string[];
11
- export declare const FISCAL_YEAR: string[];
12
- export declare const ACCOUNT: string[];
13
- export declare const JOURNAL: string[];
14
- export declare const CONTACT: string[];
15
- export declare const TAX: string[];
16
- export declare const DOCUMENT: string[];
17
- /**
18
- * The mentions the law of a country puts on one document, from the view that
19
- * decides which of them apply. `text_i18n` crosses as it is: a renderer picks
20
- * the language, and the server has no business choosing one.
21
- */
22
- export declare const DOCUMENT_LEGAL_MENTION: string[];
23
- /**
24
- * What the country of a document requires of it, beside the mentions: the
25
- * payment term the law sets, how the number is built, when the tax falls due
26
- * and how the document is exchanged. Read from `country_defaults`, which
27
- * holds null wherever the pack has said nothing — and null is the answer, not
28
- * an invitation to substitute another country's.
29
- */
30
- export declare const COUNTRY_DOCUMENT_RULES: string[];
31
- /**
32
- * The header of a document, from the view that assembles it: the seller, the
33
- * buyer, the amounts, where it is paid and what the country of the document
34
- * requires. `document_line_items` is the lines and `document_legal_mentions`
35
- * the sentences — three reads, and no client holding a copy of the
36
- * letterhead.
37
- */
38
- export declare const DOCUMENT_HEADER: string[];
39
- export declare const PRODUCT: string[];
40
- export declare const DOCUMENT_LINE: string[];
41
- export declare const ENTRY: string[];
42
- export declare const ENTRY_LINE: string[];
43
- export declare const BANK_ACCOUNT: string[];
44
- export declare const BANK_TRANSACTION: string[];
45
- export declare const PAYMENT: string[];
46
- /**
47
- * An invitation, without its secret. `token_hash` is deliberately absent: it
48
- * is of no use to a client, and a list of hashes is a thing to leak rather
49
- * than a thing to show.
50
- */
51
- /** What one person chose for themselves. Null everywhere is the fresh state. */
52
- export declare const USER_PREFERENCES: string[];
53
- export declare const INVITATION: string[];
54
- /** A machine key, without its hash. The secret is returned once, elsewhere. */
55
- export declare const API_KEY: string[];
56
- export declare const INSTANCE: string[];
57
- export declare const RECONCILIATION: string[];
58
- export declare const AUDIT_LOG: string[];
59
- //# sourceMappingURL=columns.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"columns.d.ts","sourceRoot":"","sources":["../src/columns.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,eAAO,MAAM,OAAO,UAqCnB,CAAC;AAEF,eAAO,MAAM,WAAW,UAAoE,CAAC;AAE7F,eAAO,MAAM,OAAO,UASnB,CAAC;AAEF,eAAO,MAAM,OAAO,UAAmD,CAAC;AAExE,eAAO,MAAM,OAAO,UAYnB,CAAC;AAEF,eAAO,MAAM,GAAG,UAsBf,CAAC;AAEF,eAAO,MAAM,QAAQ,UAqBpB,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,UAOlC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,UAWlC,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,UAmE3B,CAAC;AAEF,eAAO,MAAM,OAAO,UAgBnB,CAAC;AAEF,eAAO,MAAM,aAAa,UAiBzB,CAAC;AAEF,eAAO,MAAM,KAAK,UAejB,CAAC;AAEF,eAAO,MAAM,UAAU,UAsBtB,CAAC;AAEF,eAAO,MAAM,YAAY,UAUxB,CAAC;AAEF,eAAO,MAAM,gBAAgB,UAiB5B,CAAC;AAEF,eAAO,MAAM,OAAO,UAcnB,CAAC;AAEF;;;;GAIG;AACH,gFAAgF;AAChF,eAAO,MAAM,gBAAgB,UAS5B,CAAC;AAEF,eAAO,MAAM,UAAU,UAYtB,CAAC;AAEF,+EAA+E;AAC/E,eAAO,MAAM,OAAO,UAWnB,CAAC;AAEF,eAAO,MAAM,QAAQ,UAQpB,CAAC;AAEF,eAAO,MAAM,cAAc,UAa1B,CAAC;AAEF,eAAO,MAAM,SAAS,UAarB,CAAC"}
package/dist/columns.js DELETED
@@ -1,422 +0,0 @@
1
- /**
2
- * What each tool reads back, written once.
3
- *
4
- * Two rules run through every list. A `numeric` column is asked for as
5
- * `amount::text`, so the exact decimal arrives rather than a float; a `date`
6
- * or a timestamp likewise, so `2026-06-15` is a string on both routes instead
7
- * of whatever a driver decided a date object should be. Everything else —
8
- * uuid, text, boolean, integer — crosses unchanged.
9
- */
10
- export const COMPANY = [
11
- 'id',
12
- 'name',
13
- 'trade_name',
14
- 'legal_name',
15
- 'legal_form',
16
- 'country',
17
- 'fiscal_country',
18
- 'vat_number',
19
- 'registration_number',
20
- 'address_line1',
21
- 'address_line2',
22
- 'postal_code',
23
- 'city',
24
- 'country',
25
- 'region',
26
- 'email',
27
- 'phone',
28
- 'website',
29
- 'logo_url',
30
- 'share_capital::text',
31
- 'share_capital_currency',
32
- 'activity_code',
33
- 'activity_scheme',
34
- 'document_template',
35
- 'default_bank_account_id',
36
- 'language',
37
- 'currency_code',
38
- 'lock_date::text',
39
- 'tax_lock_date::text',
40
- 'receivable_account_id',
41
- 'payable_account_id',
42
- 'suspense_account_id',
43
- 'retained_earnings_account_id',
44
- 'sales_journal_id',
45
- 'purchase_journal_id',
46
- 'miscellaneous_journal_id',
47
- ];
48
- export const FISCAL_YEAR = ['id', 'name', 'start_date::text', 'end_date::text', 'is_closed'];
49
- export const ACCOUNT = [
50
- 'id',
51
- 'code',
52
- 'name',
53
- 'account_type',
54
- 'internal_group',
55
- 'reconcilable',
56
- 'currency_code',
57
- 'deprecated',
58
- ];
59
- export const JOURNAL = ['id', 'code', 'name', 'journal_type', 'active'];
60
- export const CONTACT = [
61
- 'id',
62
- 'name',
63
- 'contact_type',
64
- 'vat_number',
65
- 'auxiliary_code',
66
- 'email',
67
- 'country',
68
- 'payment_terms_days',
69
- 'receivable_account_id',
70
- 'payable_account_id',
71
- 'active',
72
- ];
73
- export const TAX = [
74
- 'id',
75
- 'code',
76
- 'name',
77
- 'amount::text',
78
- 'amount_type',
79
- 'applies_to',
80
- 'treatment',
81
- 'vat_category',
82
- 'valid_from::text',
83
- 'valid_to::text',
84
- 'legal_reference',
85
- // The generalised engine. `tax_kind` and `jurisdiction` say what a tax is
86
- // where the code alone would have to be guessed at; `recoverable` and
87
- // `price_include` change what a client should show; `cash_basis` is here so
88
- // a reader is not surprised by it once cash-basis VAT starts writing it.
89
- 'tax_kind',
90
- 'recoverable',
91
- 'jurisdiction',
92
- 'price_include',
93
- 'cash_basis',
94
- 'active',
95
- ];
96
- export const DOCUMENT = [
97
- 'id',
98
- 'company_id',
99
- 'doc_type',
100
- 'state',
101
- 'payment_state',
102
- 'number',
103
- 'supplier_reference',
104
- 'contact_id',
105
- 'journal_id',
106
- 'document_date::text',
107
- 'accounting_date::text',
108
- 'due_date::text',
109
- 'currency_code',
110
- 'amount_untaxed::text',
111
- 'amount_tax::text',
112
- 'amount_total::text',
113
- 'amount_paid::text',
114
- 'amount_residual::text',
115
- 'entry_id',
116
- 'sent_at::text',
117
- ];
118
- /**
119
- * The mentions the law of a country puts on one document, from the view that
120
- * decides which of them apply. `text_i18n` crosses as it is: a renderer picks
121
- * the language, and the server has no business choosing one.
122
- */
123
- export const DOCUMENT_LEGAL_MENTION = [
124
- 'code',
125
- 'applies_when',
126
- 'text',
127
- 'text_i18n',
128
- 'sequence',
129
- 'legal_reference',
130
- ];
131
- /**
132
- * What the country of a document requires of it, beside the mentions: the
133
- * payment term the law sets, how the number is built, when the tax falls due
134
- * and how the document is exchanged. Read from `country_defaults`, which
135
- * holds null wherever the pack has said nothing — and null is the answer, not
136
- * an invitation to substitute another country's.
137
- */
138
- export const COUNTRY_DOCUMENT_RULES = [
139
- 'country',
140
- 'numbering_gapless',
141
- 'number_format',
142
- 'legal_payment_days',
143
- 'late_payment_reference',
144
- 'tax_point_rule',
145
- 'einvoice_profile',
146
- 'einvoice_mandatory_from::text',
147
- 'party_scheme',
148
- 'vat_scheme',
149
- ];
150
- /**
151
- * The header of a document, from the view that assembles it: the seller, the
152
- * buyer, the amounts, where it is paid and what the country of the document
153
- * requires. `document_line_items` is the lines and `document_legal_mentions`
154
- * the sentences — three reads, and no client holding a copy of the
155
- * letterhead.
156
- */
157
- export const DOCUMENT_HEADER = [
158
- 'document_id',
159
- 'company_id',
160
- 'doc_type',
161
- 'state',
162
- 'payment_state',
163
- 'number',
164
- 'supplier_reference',
165
- 'document_date::text',
166
- 'accounting_date::text',
167
- 'due_date::text',
168
- 'delivery_date::text',
169
- 'currency_code',
170
- 'amount_untaxed::text',
171
- 'amount_tax::text',
172
- 'amount_total::text',
173
- 'amount_paid::text',
174
- 'amount_residual::text',
175
- 'payment_terms',
176
- 'payment_means_code',
177
- 'payment_reference',
178
- 'buyer_reference',
179
- 'order_reference',
180
- 'contract_reference',
181
- 'project_reference',
182
- 'note',
183
- 'payee_iban',
184
- 'payee_bic',
185
- 'seller_name',
186
- 'seller_legal_name',
187
- 'seller_legal_form',
188
- 'seller_vat_number',
189
- 'seller_registration_number',
190
- 'seller_address_line1',
191
- 'seller_address_line2',
192
- 'seller_postal_code',
193
- 'seller_city',
194
- 'seller_country',
195
- 'seller_email',
196
- 'seller_phone',
197
- 'seller_website',
198
- 'seller_logo_url',
199
- 'seller_share_capital::text',
200
- 'seller_share_capital_currency',
201
- 'seller_activity_code',
202
- 'seller_activity_scheme',
203
- 'document_template',
204
- 'buyer_id',
205
- 'buyer_name',
206
- 'buyer_vat_number',
207
- 'buyer_registration_number',
208
- 'buyer_address_line1',
209
- 'buyer_address_line2',
210
- 'buyer_postal_code',
211
- 'buyer_city',
212
- 'buyer_country',
213
- 'buyer_email',
214
- 'country',
215
- 'number_format',
216
- 'numbering_gapless',
217
- 'legal_payment_days',
218
- 'late_payment_reference',
219
- 'tax_point_rule',
220
- 'einvoice_profile',
221
- 'einvoice_mandatory_from::text',
222
- 'party_scheme',
223
- 'vat_scheme',
224
- ];
225
- export const PRODUCT = [
226
- 'id',
227
- 'company_id',
228
- 'code',
229
- 'name',
230
- 'description',
231
- 'kind',
232
- 'unit_code',
233
- 'currency_code',
234
- 'sale_price::text',
235
- 'purchase_price::text',
236
- 'sale_account_id',
237
- 'purchase_account_id',
238
- 'sale_tax_id',
239
- 'purchase_tax_id',
240
- 'active',
241
- ];
242
- export const DOCUMENT_LINE = [
243
- 'id',
244
- 'document_id',
245
- 'sequence',
246
- 'line_type',
247
- 'name',
248
- 'description',
249
- 'product_id',
250
- 'quantity::text',
251
- 'unit_code',
252
- 'unit_price::text',
253
- 'discount_percent::text',
254
- 'tax_id',
255
- 'account_id',
256
- 'vat_category',
257
- 'vat_rate::text',
258
- 'amount_untaxed::text',
259
- ];
260
- export const ENTRY = [
261
- 'id',
262
- 'company_id',
263
- 'journal_id',
264
- 'number',
265
- 'entry_date::text',
266
- 'reference',
267
- 'description',
268
- 'state',
269
- 'kind',
270
- 'document_id',
271
- 'total_debit::text',
272
- 'total_credit::text',
273
- 'is_balanced',
274
- 'posted_at::text',
275
- ];
276
- export const ENTRY_LINE = [
277
- 'id',
278
- 'entry_id',
279
- 'account_id',
280
- 'sequence',
281
- 'name',
282
- 'debit::text',
283
- 'credit::text',
284
- 'balance::text',
285
- 'contact_id',
286
- 'date_maturity::text',
287
- 'tax_id',
288
- 'tax_line',
289
- 'declaration_box',
290
- 'box_amount::text',
291
- 'matching_number',
292
- 'matched_amount::text',
293
- // The currency of the line and its amount in it, written whenever that
294
- // currency is not the company's. A client matching two foreign lines needs
295
- // both: that is the scale the matching is worked out on.
296
- 'currency_code',
297
- 'amount_currency::text',
298
- ];
299
- export const BANK_ACCOUNT = [
300
- 'id',
301
- 'name',
302
- 'iban',
303
- 'bic',
304
- 'bank_name',
305
- 'currency_code',
306
- 'account_id',
307
- 'journal_id',
308
- 'active',
309
- ];
310
- export const BANK_TRANSACTION = [
311
- 'id',
312
- 'company_id',
313
- 'bank_account_id',
314
- 'statement_id',
315
- 'transaction_date::text',
316
- 'value_date::text',
317
- 'amount::text',
318
- 'currency_code',
319
- 'description',
320
- 'counterpart_name',
321
- 'counterpart_iban',
322
- 'reference',
323
- 'structured_reference',
324
- 'contact_id',
325
- 'entry_id',
326
- 'state',
327
- ];
328
- export const PAYMENT = [
329
- 'id',
330
- 'company_id',
331
- 'direction',
332
- 'payment_date::text',
333
- 'amount::text',
334
- 'currency_code',
335
- 'contact_id',
336
- 'journal_id',
337
- 'bank_account_id',
338
- 'entry_id',
339
- 'reference',
340
- 'memo',
341
- 'state',
342
- ];
343
- /**
344
- * An invitation, without its secret. `token_hash` is deliberately absent: it
345
- * is of no use to a client, and a list of hashes is a thing to leak rather
346
- * than a thing to show.
347
- */
348
- /** What one person chose for themselves. Null everywhere is the fresh state. */
349
- export const USER_PREFERENCES = [
350
- 'user_id',
351
- 'preferred_company_id',
352
- 'language',
353
- 'timezone',
354
- 'date_display_format',
355
- 'number_display_format',
356
- 'theme',
357
- 'updated_at::text',
358
- ];
359
- export const INVITATION = [
360
- 'id',
361
- 'company_id',
362
- 'email',
363
- 'role',
364
- 'capabilities_granted',
365
- 'invited_by',
366
- 'created_at::text',
367
- 'expires_at::text',
368
- 'accepted_at::text',
369
- 'accepted_by',
370
- 'revoked_at::text',
371
- ];
372
- /** A machine key, without its hash. The secret is returned once, elsewhere. */
373
- export const API_KEY = [
374
- 'id',
375
- 'company_id',
376
- 'name',
377
- 'prefix',
378
- 'capabilities',
379
- 'created_by',
380
- 'created_at::text',
381
- 'expires_at::text',
382
- 'last_used_at::text',
383
- 'revoked_at::text',
384
- ];
385
- export const INSTANCE = [
386
- 'instance_id',
387
- 'organization_name',
388
- 'country',
389
- 'edition',
390
- 'schema_version',
391
- 'installed_at::text',
392
- 'registered_at::text',
393
- ];
394
- export const RECONCILIATION = [
395
- 'id',
396
- 'debit_line_id',
397
- 'credit_line_id',
398
- 'amount::text',
399
- 'matching_number',
400
- 'matched_at::text',
401
- // What the matching revealed, when it revealed something: the entry that
402
- // booked the realised exchange difference, and the one that moved the share
403
- // of a cash-basis tax the settlement made due. A client that shows a
404
- // matching shows what it caused.
405
- 'fx_entry_id',
406
- 'tax_transfer_entry_id',
407
- ];
408
- export const AUDIT_LOG = [
409
- 'id',
410
- 'occurred_at::text',
411
- 'actor_id',
412
- 'api_key_id',
413
- 'company_id',
414
- 'table_name',
415
- 'record_id',
416
- 'record_key',
417
- 'operation',
418
- 'action',
419
- 'old_values',
420
- 'new_values',
421
- ];
422
- //# sourceMappingURL=columns.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"columns.js","sourceRoot":"","sources":["../src/columns.ts"],"names":[],"mappings":"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"}
package/dist/format.d.ts DELETED
@@ -1,21 +0,0 @@
1
- /**
2
- * Amounts as decimal strings, everywhere, in both directions.
3
- *
4
- * Postgres holds `numeric` exactly and hands it over as text; a table read
5
- * asks for `amount::text` so that is what arrives. The one place a float can
6
- * appear is a function result crossing PostgREST as JSON, where `1210.00`
7
- * becomes a number before any code of ours sees it. `money()` puts it back to
8
- * two decimals, which is exact for every amount a ledger holds, and a model
9
- * reading `"1210.00"` never has to wonder whether `1210.0000000001` was the
10
- * VAT rounding or the transport.
11
- */
12
- export type Decimal = string;
13
- /** A numeric, as the decimal string the ledger holds. */
14
- export declare function money(value: unknown): Decimal | null;
15
- /** The same, for a quantity or a rate, where two decimals would be a lie. */
16
- export declare function decimal(value: unknown): Decimal | null;
17
- /** Applies `money()` to the named keys of every row. */
18
- export declare function moneyFields<T extends Record<string, unknown>>(rows: T[], keys: string[]): T[];
19
- /** An amount on its way into the database: `"1210.00"`, never 1210.0000001. */
20
- export declare function amountIn(value: string | number): string;
21
- //# sourceMappingURL=format.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.d.ts","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,MAAM,MAAM,OAAO,GAAG,MAAM,CAAC;AAE7B,yDAAyD;AACzD,wBAAgB,KAAK,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAKpD;AAED,6EAA6E;AAC7E,wBAAgB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,OAAO,GAAG,IAAI,CAItD;AAED,wDAAwD;AACxD,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,CAQ7F;AAED,+EAA+E;AAC/E,wBAAgB,QAAQ,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAMvD"}
package/dist/format.js DELETED
@@ -1,49 +0,0 @@
1
- /**
2
- * Amounts as decimal strings, everywhere, in both directions.
3
- *
4
- * Postgres holds `numeric` exactly and hands it over as text; a table read
5
- * asks for `amount::text` so that is what arrives. The one place a float can
6
- * appear is a function result crossing PostgREST as JSON, where `1210.00`
7
- * becomes a number before any code of ours sees it. `money()` puts it back to
8
- * two decimals, which is exact for every amount a ledger holds, and a model
9
- * reading `"1210.00"` never has to wonder whether `1210.0000000001` was the
10
- * VAT rounding or the transport.
11
- */
12
- import { EkwoMcpError } from './backend.js';
13
- import { roundCurrency } from './rounding.js';
14
- /** A numeric, as the decimal string the ledger holds. */
15
- export function money(value) {
16
- if (value === null || value === undefined)
17
- return null;
18
- if (typeof value === 'number')
19
- return roundCurrency(value, 2).toFixed(2);
20
- const text = String(value);
21
- return text.length === 0 ? null : text;
22
- }
23
- /** The same, for a quantity or a rate, where two decimals would be a lie. */
24
- export function decimal(value) {
25
- if (value === null || value === undefined)
26
- return null;
27
- const text = String(value);
28
- return text.length === 0 ? null : text;
29
- }
30
- /** Applies `money()` to the named keys of every row. */
31
- export function moneyFields(rows, keys) {
32
- return rows.map((row) => {
33
- const out = { ...row };
34
- for (const key of keys) {
35
- if (key in out)
36
- out[key] = money(out[key]);
37
- }
38
- return out;
39
- });
40
- }
41
- /** An amount on its way into the database: `"1210.00"`, never 1210.0000001. */
42
- export function amountIn(value) {
43
- const text = typeof value === 'number' ? roundCurrency(value, 2).toFixed(2) : value.trim();
44
- if (!/^-?\d+(\.\d+)?$/.test(text)) {
45
- throw new EkwoMcpError(`bad_amount: ${String(value)} is not a decimal amount`);
46
- }
47
- return text;
48
- }
49
- //# sourceMappingURL=format.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format.js","sourceRoot":"","sources":["../src/format.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAI9C,yDAAyD;AACzD,MAAM,UAAU,KAAK,CAAC,KAAc;IAClC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACvD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;IACzE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,6EAA6E;AAC7E,MAAM,UAAU,OAAO,CAAC,KAAc;IACpC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACvD,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC3B,OAAO,IAAI,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC;AACzC,CAAC;AAED,wDAAwD;AACxD,MAAM,UAAU,WAAW,CAAoC,IAAS,EAAE,IAAc;IACtF,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;QACtB,MAAM,GAAG,GAA4B,EAAE,GAAG,GAAG,EAAE,CAAC;QAChD,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;YACvB,IAAI,GAAG,IAAI,GAAG;gBAAE,GAAG,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;QAC7C,CAAC;QACD,OAAO,GAAQ,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC;AAED,+EAA+E;AAC/E,MAAM,UAAU,QAAQ,CAAC,KAAsB;IAC7C,MAAM,IAAI,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,aAAa,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;IAC3F,IAAI,CAAC,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,YAAY,CAAC,eAAe,MAAM,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACjF,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -1,25 +0,0 @@
1
- /**
2
- * The one rounding rule of Ekwo: **half up, on the absolute value, at the
3
- * currency's decimals**.
4
- *
5
- * Three packages used to answer this differently — `Math.round((v + EPSILON) *
6
- * 100) / 100`, `Math.round(v * 100) / 100` and `Number.prototype.toFixed(2)` —
7
- * and the three disagreed on the two cases that matter: a negative half, where
8
- * `Math.round` goes towards positive infinity and turns -0.005 into -0.00, and
9
- * a value a binary float cannot hold, where 2.675 becomes 2.67 because
10
- * `2.675 * 100` is really 267.49999999999994. A credit note is a sale with the
11
- * sign flipped; a rule that treats the two differently puts a cent between an
12
- * invoice and its credit note, and the cent is found by the person filing the
13
- * return.
14
- *
15
- * Half up on the absolute value is what an invoice, a VAT return and a set of
16
- * annual accounts are written with, and it is symmetric by construction: the
17
- * rounding of -x is the rounding of x with the sign put back.
18
- *
19
- * The file is deliberately identical in every package that holds a copy. A
20
- * format brick may not import the core or another brick, so the rule is
21
- * duplicated rather than shared — and `tests/rounding.test.ts` reads the
22
- * copies and refuses one that has drifted. See `docs/decisions.md`.
23
- */
24
- export declare function roundCurrency(value: number, decimals?: number): number;
25
- //# sourceMappingURL=rounding.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rounding.d.ts","sourceRoot":"","sources":["../src/rounding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAUjE"}
package/dist/rounding.js DELETED
@@ -1,35 +0,0 @@
1
- /**
2
- * The one rounding rule of Ekwo: **half up, on the absolute value, at the
3
- * currency's decimals**.
4
- *
5
- * Three packages used to answer this differently — `Math.round((v + EPSILON) *
6
- * 100) / 100`, `Math.round(v * 100) / 100` and `Number.prototype.toFixed(2)` —
7
- * and the three disagreed on the two cases that matter: a negative half, where
8
- * `Math.round` goes towards positive infinity and turns -0.005 into -0.00, and
9
- * a value a binary float cannot hold, where 2.675 becomes 2.67 because
10
- * `2.675 * 100` is really 267.49999999999994. A credit note is a sale with the
11
- * sign flipped; a rule that treats the two differently puts a cent between an
12
- * invoice and its credit note, and the cent is found by the person filing the
13
- * return.
14
- *
15
- * Half up on the absolute value is what an invoice, a VAT return and a set of
16
- * annual accounts are written with, and it is symmetric by construction: the
17
- * rounding of -x is the rounding of x with the sign put back.
18
- *
19
- * The file is deliberately identical in every package that holds a copy. A
20
- * format brick may not import the core or another brick, so the rule is
21
- * duplicated rather than shared — and `tests/rounding.test.ts` reads the
22
- * copies and refuses one that has drifted. See `docs/decisions.md`.
23
- */
24
- export function roundCurrency(value, decimals = 2) {
25
- const factor = 10 ** decimals;
26
- const scaled = Math.abs(value) * factor;
27
- // The nudge is proportional to the number, which is what makes it work at
28
- // 1.005 and at 1000000.005 alike, and far too small to move a value that is
29
- // not already within a bit of the halfway point.
30
- const rounded = Math.round(scaled + Number.EPSILON * scaled);
31
- // `-0` is a value of its own in JavaScript and it prints as "-0.00".
32
- // Adding zero turns it back into `0`.
33
- return (value < 0 ? -rounded : rounded) / factor + 0;
34
- }
35
- //# sourceMappingURL=rounding.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"rounding.js","sourceRoot":"","sources":["../src/rounding.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,QAAQ,GAAG,CAAC;IACvD,MAAM,MAAM,GAAG,EAAE,IAAI,QAAQ,CAAC;IAC9B,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC;IACxC,0EAA0E;IAC1E,4EAA4E;IAC5E,iDAAiD;IACjD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,OAAO,GAAG,MAAM,CAAC,CAAC;IAC7D,qEAAqE;IACrE,sCAAsC;IACtC,OAAO,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,MAAM,GAAG,CAAC,CAAC;AACvD,CAAC"}