@yolk-sdk/emulators 0.1.0-canary.96

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 (333) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +2135 -0
  3. package/dist/anthropic.d.mts +269 -0
  4. package/dist/anthropic.d.mts.map +1 -0
  5. package/dist/anthropic.mjs +177 -0
  6. package/dist/anthropic.mjs.map +1 -0
  7. package/dist/chat-completions.d.mts +288 -0
  8. package/dist/chat-completions.d.mts.map +1 -0
  9. package/dist/chat-completions.mjs +451 -0
  10. package/dist/chat-completions.mjs.map +1 -0
  11. package/dist/codex.d.mts +265 -0
  12. package/dist/codex.d.mts.map +1 -0
  13. package/dist/codex.mjs +199 -0
  14. package/dist/codex.mjs.map +1 -0
  15. package/dist/dropbox/api.d.mts +63 -0
  16. package/dist/dropbox/api.d.mts.map +1 -0
  17. package/dist/dropbox/api.mjs +565 -0
  18. package/dist/dropbox/api.mjs.map +1 -0
  19. package/dist/dropbox/state.d.mts +136 -0
  20. package/dist/dropbox/state.d.mts.map +1 -0
  21. package/dist/dropbox/state.mjs +209 -0
  22. package/dist/dropbox/state.mjs.map +1 -0
  23. package/dist/dropbox.d.mts +79 -0
  24. package/dist/dropbox.d.mts.map +1 -0
  25. package/dist/dropbox.mjs +124 -0
  26. package/dist/dropbox.mjs.map +1 -0
  27. package/dist/email-fixtures.d.mts +36 -0
  28. package/dist/email-fixtures.d.mts.map +1 -0
  29. package/dist/email-fixtures.mjs +1080 -0
  30. package/dist/email-fixtures.mjs.map +1 -0
  31. package/dist/email.d.mts +160 -0
  32. package/dist/email.d.mts.map +1 -0
  33. package/dist/email.mjs +608 -0
  34. package/dist/email.mjs.map +1 -0
  35. package/dist/emulator-compose.d.mts +40 -0
  36. package/dist/emulator-compose.d.mts.map +1 -0
  37. package/dist/emulator-compose.mjs +91 -0
  38. package/dist/emulator-compose.mjs.map +1 -0
  39. package/dist/emulator-http.d.mts +53 -0
  40. package/dist/emulator-http.d.mts.map +1 -0
  41. package/dist/emulator-http.mjs +117 -0
  42. package/dist/emulator-http.mjs.map +1 -0
  43. package/dist/emulator-kernel.d.mts +176 -0
  44. package/dist/emulator-kernel.d.mts.map +1 -0
  45. package/dist/emulator-kernel.mjs +413 -0
  46. package/dist/emulator-kernel.mjs.map +1 -0
  47. package/dist/fixture-route.d.mts +129 -0
  48. package/dist/fixture-route.d.mts.map +1 -0
  49. package/dist/fixture-route.mjs +257 -0
  50. package/dist/fixture-route.mjs.map +1 -0
  51. package/dist/fortnox/api.d.mts +92 -0
  52. package/dist/fortnox/api.d.mts.map +1 -0
  53. package/dist/fortnox/api.mjs +750 -0
  54. package/dist/fortnox/api.mjs.map +1 -0
  55. package/dist/fortnox/state.d.mts +533 -0
  56. package/dist/fortnox/state.d.mts.map +1 -0
  57. package/dist/fortnox/state.mjs +612 -0
  58. package/dist/fortnox/state.mjs.map +1 -0
  59. package/dist/fortnox.d.mts +128 -0
  60. package/dist/fortnox.d.mts.map +1 -0
  61. package/dist/fortnox.mjs +403 -0
  62. package/dist/fortnox.mjs.map +1 -0
  63. package/dist/gateway-evaluate-recordings.d.mts +12 -0
  64. package/dist/gateway-evaluate-recordings.d.mts.map +1 -0
  65. package/dist/gateway-evaluate-recordings.mjs +128 -0
  66. package/dist/gateway-evaluate-recordings.mjs.map +1 -0
  67. package/dist/gateway.d.mts +272 -0
  68. package/dist/gateway.d.mts.map +1 -0
  69. package/dist/gateway.mjs +400 -0
  70. package/dist/gateway.mjs.map +1 -0
  71. package/dist/github/api.d.mts +63 -0
  72. package/dist/github/api.d.mts.map +1 -0
  73. package/dist/github/api.mjs +527 -0
  74. package/dist/github/api.mjs.map +1 -0
  75. package/dist/github/state.d.mts +272 -0
  76. package/dist/github/state.d.mts.map +1 -0
  77. package/dist/github/state.mjs +303 -0
  78. package/dist/github/state.mjs.map +1 -0
  79. package/dist/github.d.mts +77 -0
  80. package/dist/github.d.mts.map +1 -0
  81. package/dist/github.mjs +180 -0
  82. package/dist/github.mjs.map +1 -0
  83. package/dist/google/calendar.d.mts +10 -0
  84. package/dist/google/calendar.d.mts.map +1 -0
  85. package/dist/google/calendar.mjs +252 -0
  86. package/dist/google/calendar.mjs.map +1 -0
  87. package/dist/google/drive.d.mts +8 -0
  88. package/dist/google/drive.d.mts.map +1 -0
  89. package/dist/google/drive.mjs +252 -0
  90. package/dist/google/drive.mjs.map +1 -0
  91. package/dist/google/gmail.d.mts +10 -0
  92. package/dist/google/gmail.d.mts.map +1 -0
  93. package/dist/google/gmail.mjs +591 -0
  94. package/dist/google/gmail.mjs.map +1 -0
  95. package/dist/google/shared.d.mts +107 -0
  96. package/dist/google/shared.d.mts.map +1 -0
  97. package/dist/google/shared.mjs +146 -0
  98. package/dist/google/shared.mjs.map +1 -0
  99. package/dist/google/state.d.mts +385 -0
  100. package/dist/google/state.d.mts.map +1 -0
  101. package/dist/google/state.mjs +496 -0
  102. package/dist/google/state.mjs.map +1 -0
  103. package/dist/google.d.mts +75 -0
  104. package/dist/google.d.mts.map +1 -0
  105. package/dist/google.mjs +210 -0
  106. package/dist/google.mjs.map +1 -0
  107. package/dist/linkedin-search/api.d.mts +45 -0
  108. package/dist/linkedin-search/api.d.mts.map +1 -0
  109. package/dist/linkedin-search/api.mjs +181 -0
  110. package/dist/linkedin-search/api.mjs.map +1 -0
  111. package/dist/linkedin-search/state.d.mts +123 -0
  112. package/dist/linkedin-search/state.d.mts.map +1 -0
  113. package/dist/linkedin-search/state.mjs +261 -0
  114. package/dist/linkedin-search/state.mjs.map +1 -0
  115. package/dist/linkedin-search.d.mts +69 -0
  116. package/dist/linkedin-search.d.mts.map +1 -0
  117. package/dist/linkedin-search.mjs +158 -0
  118. package/dist/linkedin-search.mjs.map +1 -0
  119. package/dist/mcp/api.d.mts +44 -0
  120. package/dist/mcp/api.d.mts.map +1 -0
  121. package/dist/mcp/api.mjs +557 -0
  122. package/dist/mcp/api.mjs.map +1 -0
  123. package/dist/mcp/recordings.d.mts +40 -0
  124. package/dist/mcp/recordings.d.mts.map +1 -0
  125. package/dist/mcp/recordings.mjs +2390 -0
  126. package/dist/mcp/recordings.mjs.map +1 -0
  127. package/dist/mcp/state.d.mts +71 -0
  128. package/dist/mcp/state.d.mts.map +1 -0
  129. package/dist/mcp/state.mjs +83 -0
  130. package/dist/mcp/state.mjs.map +1 -0
  131. package/dist/mcp.d.mts +84 -0
  132. package/dist/mcp.d.mts.map +1 -0
  133. package/dist/mcp.mjs +241 -0
  134. package/dist/mcp.mjs.map +1 -0
  135. package/dist/messages.d.mts +183 -0
  136. package/dist/messages.d.mts.map +1 -0
  137. package/dist/messages.mjs +532 -0
  138. package/dist/messages.mjs.map +1 -0
  139. package/dist/microsoft/api.d.mts +47 -0
  140. package/dist/microsoft/api.d.mts.map +1 -0
  141. package/dist/microsoft/api.mjs +178 -0
  142. package/dist/microsoft/api.mjs.map +1 -0
  143. package/dist/microsoft/calendar.d.mts +30 -0
  144. package/dist/microsoft/calendar.d.mts.map +1 -0
  145. package/dist/microsoft/calendar.mjs +271 -0
  146. package/dist/microsoft/calendar.mjs.map +1 -0
  147. package/dist/microsoft/drive.d.mts +36 -0
  148. package/dist/microsoft/drive.d.mts.map +1 -0
  149. package/dist/microsoft/drive.mjs +298 -0
  150. package/dist/microsoft/drive.mjs.map +1 -0
  151. package/dist/microsoft/graph.d.mts +198 -0
  152. package/dist/microsoft/graph.d.mts.map +1 -0
  153. package/dist/microsoft/graph.mjs +264 -0
  154. package/dist/microsoft/graph.mjs.map +1 -0
  155. package/dist/microsoft/mail.d.mts +48 -0
  156. package/dist/microsoft/mail.d.mts.map +1 -0
  157. package/dist/microsoft/mail.mjs +488 -0
  158. package/dist/microsoft/mail.mjs.map +1 -0
  159. package/dist/microsoft/state.d.mts +480 -0
  160. package/dist/microsoft/state.d.mts.map +1 -0
  161. package/dist/microsoft/state.mjs +625 -0
  162. package/dist/microsoft/state.mjs.map +1 -0
  163. package/dist/microsoft.d.mts +168 -0
  164. package/dist/microsoft.d.mts.map +1 -0
  165. package/dist/microsoft.mjs +483 -0
  166. package/dist/microsoft.mjs.map +1 -0
  167. package/dist/node.d.mts +47 -0
  168. package/dist/node.d.mts.map +1 -0
  169. package/dist/node.mjs +178 -0
  170. package/dist/node.mjs.map +1 -0
  171. package/dist/notion/api.d.mts +51 -0
  172. package/dist/notion/api.d.mts.map +1 -0
  173. package/dist/notion/api.mjs +507 -0
  174. package/dist/notion/api.mjs.map +1 -0
  175. package/dist/notion/state.d.mts +329 -0
  176. package/dist/notion/state.d.mts.map +1 -0
  177. package/dist/notion/state.mjs +432 -0
  178. package/dist/notion/state.mjs.map +1 -0
  179. package/dist/notion.d.mts +72 -0
  180. package/dist/notion.d.mts.map +1 -0
  181. package/dist/notion.mjs +127 -0
  182. package/dist/notion.mjs.map +1 -0
  183. package/dist/openai.d.mts +165 -0
  184. package/dist/openai.d.mts.map +1 -0
  185. package/dist/openai.mjs +141 -0
  186. package/dist/openai.mjs.map +1 -0
  187. package/dist/opencode-recordings.d.mts +7 -0
  188. package/dist/opencode-recordings.d.mts.map +1 -0
  189. package/dist/opencode-recordings.mjs +222 -0
  190. package/dist/opencode-recordings.mjs.map +1 -0
  191. package/dist/opencode.d.mts +70 -0
  192. package/dist/opencode.d.mts.map +1 -0
  193. package/dist/opencode.mjs +217 -0
  194. package/dist/opencode.mjs.map +1 -0
  195. package/dist/r2-fixtures.d.mts +36 -0
  196. package/dist/r2-fixtures.d.mts.map +1 -0
  197. package/dist/r2-fixtures.mjs +245 -0
  198. package/dist/r2-fixtures.mjs.map +1 -0
  199. package/dist/r2-guard.d.mts +43 -0
  200. package/dist/r2-guard.d.mts.map +1 -0
  201. package/dist/r2-guard.mjs +215 -0
  202. package/dist/r2-guard.mjs.map +1 -0
  203. package/dist/r2.d.mts +166 -0
  204. package/dist/r2.d.mts.map +1 -0
  205. package/dist/r2.mjs +517 -0
  206. package/dist/r2.mjs.map +1 -0
  207. package/dist/responses.d.mts +231 -0
  208. package/dist/responses.d.mts.map +1 -0
  209. package/dist/responses.mjs +556 -0
  210. package/dist/responses.mjs.map +1 -0
  211. package/dist/route-evidence.d.mts +45 -0
  212. package/dist/route-evidence.d.mts.map +1 -0
  213. package/dist/route-evidence.mjs +56 -0
  214. package/dist/route-evidence.mjs.map +1 -0
  215. package/dist/router.d.mts +93 -0
  216. package/dist/router.d.mts.map +1 -0
  217. package/dist/router.mjs +259 -0
  218. package/dist/router.mjs.map +1 -0
  219. package/dist/stateful-core.d.mts +17 -0
  220. package/dist/stateful-core.d.mts.map +1 -0
  221. package/dist/stateful-core.mjs +41 -0
  222. package/dist/stateful-core.mjs.map +1 -0
  223. package/dist/stateful-emulator.d.mts +565 -0
  224. package/dist/stateful-emulator.d.mts.map +1 -0
  225. package/dist/stateful-emulator.mjs +1228 -0
  226. package/dist/stateful-emulator.mjs.map +1 -0
  227. package/dist/stateful-secrets.d.mts +84 -0
  228. package/dist/stateful-secrets.d.mts.map +1 -0
  229. package/dist/stateful-secrets.mjs +216 -0
  230. package/dist/stateful-secrets.mjs.map +1 -0
  231. package/dist/subscription-usage-recordings.d.mts +9 -0
  232. package/dist/subscription-usage-recordings.d.mts.map +1 -0
  233. package/dist/subscription-usage-recordings.mjs +53 -0
  234. package/dist/subscription-usage-recordings.mjs.map +1 -0
  235. package/dist/subscription-usage.d.mts +53 -0
  236. package/dist/subscription-usage.d.mts.map +1 -0
  237. package/dist/subscription-usage.mjs +21 -0
  238. package/dist/subscription-usage.mjs.map +1 -0
  239. package/dist/telegram/api.d.mts +34 -0
  240. package/dist/telegram/api.d.mts.map +1 -0
  241. package/dist/telegram/api.mjs +257 -0
  242. package/dist/telegram/api.mjs.map +1 -0
  243. package/dist/telegram/state.d.mts +128 -0
  244. package/dist/telegram/state.d.mts.map +1 -0
  245. package/dist/telegram/state.mjs +154 -0
  246. package/dist/telegram/state.mjs.map +1 -0
  247. package/dist/telegram.d.mts +62 -0
  248. package/dist/telegram.d.mts.map +1 -0
  249. package/dist/telegram.mjs +127 -0
  250. package/dist/telegram.mjs.map +1 -0
  251. package/dist/todoist/api.d.mts +55 -0
  252. package/dist/todoist/api.d.mts.map +1 -0
  253. package/dist/todoist/api.mjs +415 -0
  254. package/dist/todoist/api.mjs.map +1 -0
  255. package/dist/todoist/state.d.mts +275 -0
  256. package/dist/todoist/state.d.mts.map +1 -0
  257. package/dist/todoist/state.mjs +345 -0
  258. package/dist/todoist/state.mjs.map +1 -0
  259. package/dist/todoist.d.mts +68 -0
  260. package/dist/todoist.d.mts.map +1 -0
  261. package/dist/todoist.mjs +181 -0
  262. package/dist/todoist.mjs.map +1 -0
  263. package/dist/xai.d.mts +267 -0
  264. package/dist/xai.d.mts.map +1 -0
  265. package/dist/xai.mjs +252 -0
  266. package/dist/xai.mjs.map +1 -0
  267. package/package.json +157 -0
  268. package/src/anthropic.ts +289 -0
  269. package/src/chat-completions.ts +924 -0
  270. package/src/codex.ts +296 -0
  271. package/src/dropbox/api.ts +1084 -0
  272. package/src/dropbox/state.ts +364 -0
  273. package/src/dropbox.ts +203 -0
  274. package/src/email-fixtures.ts +1297 -0
  275. package/src/email.ts +1108 -0
  276. package/src/emulator-compose.ts +147 -0
  277. package/src/emulator-http.ts +184 -0
  278. package/src/emulator-kernel.ts +844 -0
  279. package/src/fixture-route.ts +561 -0
  280. package/src/fortnox/api.ts +1352 -0
  281. package/src/fortnox/state.ts +798 -0
  282. package/src/fortnox.ts +801 -0
  283. package/src/gateway-evaluate-recordings.ts +153 -0
  284. package/src/gateway.ts +530 -0
  285. package/src/github/api.ts +986 -0
  286. package/src/github/state.ts +439 -0
  287. package/src/github.ts +271 -0
  288. package/src/google/calendar.ts +486 -0
  289. package/src/google/drive.ts +471 -0
  290. package/src/google/gmail.ts +1011 -0
  291. package/src/google/shared.ts +321 -0
  292. package/src/google/state.ts +686 -0
  293. package/src/google.ts +298 -0
  294. package/src/linkedin-search/api.ts +363 -0
  295. package/src/linkedin-search/state.ts +373 -0
  296. package/src/linkedin-search.ts +241 -0
  297. package/src/mcp/api.ts +995 -0
  298. package/src/mcp/recordings.ts +2665 -0
  299. package/src/mcp/state.ts +125 -0
  300. package/src/mcp.ts +319 -0
  301. package/src/messages.ts +844 -0
  302. package/src/microsoft/api.ts +426 -0
  303. package/src/microsoft/calendar.ts +491 -0
  304. package/src/microsoft/drive.ts +541 -0
  305. package/src/microsoft/graph.ts +550 -0
  306. package/src/microsoft/mail.ts +833 -0
  307. package/src/microsoft/state.ts +822 -0
  308. package/src/microsoft.ts +982 -0
  309. package/src/node.ts +293 -0
  310. package/src/notion/api.ts +976 -0
  311. package/src/notion/state.ts +512 -0
  312. package/src/notion.ts +210 -0
  313. package/src/openai.ts +198 -0
  314. package/src/opencode-recordings.ts +257 -0
  315. package/src/opencode.ts +271 -0
  316. package/src/r2-fixtures.ts +295 -0
  317. package/src/r2-guard.ts +323 -0
  318. package/src/r2.ts +890 -0
  319. package/src/responses.ts +901 -0
  320. package/src/route-evidence.ts +90 -0
  321. package/src/router.ts +490 -0
  322. package/src/stateful-core.ts +70 -0
  323. package/src/stateful-emulator.ts +2571 -0
  324. package/src/stateful-secrets.ts +299 -0
  325. package/src/subscription-usage-recordings.ts +77 -0
  326. package/src/subscription-usage.ts +68 -0
  327. package/src/telegram/api.ts +437 -0
  328. package/src/telegram/state.ts +229 -0
  329. package/src/telegram.ts +227 -0
  330. package/src/todoist/api.ts +736 -0
  331. package/src/todoist/state.ts +456 -0
  332. package/src/todoist.ts +316 -0
  333. package/src/xai.ts +341 -0
@@ -0,0 +1,612 @@
1
+ import { Result, Struct } from "effect";
2
+ import * as Schema from "effect/Schema";
3
+ //#region src/fortnox/state.ts
4
+ /**
5
+ * Fortnox emulator state: the typed entities, the seed input, the default seed, and the
6
+ * account-variance profiles (internal; re-exported by `src/fortnox.ts`).
7
+ *
8
+ * Entity shapes and the default entities follow the synthetic Fortnox conformance fixtures, copied
9
+ * as data (the same customer and document numbers as `fortnoxConformanceFixtureSeeds`), never
10
+ * imported from SDK code. Where no fixture records a value, the default is synthesized and says
11
+ * so below: customer 1002, most invoice rows, and the company information have no fixture.
12
+ *
13
+ * @experimental
14
+ */
15
+ const DiscountType = Schema.Literals(["PERCENT", "AMOUNT"]);
16
+ const rowFields = {
17
+ RowId: Schema.Int,
18
+ AccountNumber: Schema.NullOr(Schema.Int),
19
+ ArticleNumber: Schema.String,
20
+ ContributionPercent: Schema.String,
21
+ ContributionValue: Schema.String,
22
+ CostCenter: Schema.String,
23
+ DeliveredQuantity: Schema.String,
24
+ Description: Schema.String,
25
+ Discount: Schema.Finite,
26
+ DiscountType,
27
+ HouseWork: Schema.Boolean,
28
+ Price: Schema.Finite,
29
+ PriceExcludingVAT: Schema.Finite,
30
+ Project: Schema.String,
31
+ Total: Schema.Finite,
32
+ TotalExcludingVAT: Schema.Finite,
33
+ Unit: Schema.String,
34
+ VAT: Schema.Finite,
35
+ VATCode: Schema.String
36
+ };
37
+ /** A stored invoice row, in the single-invoice wire shape. Totals are derived. */
38
+ const FortnoxEmulatorInvoiceRow = Schema.Struct(rowFields);
39
+ const EmailInformation = Schema.Struct({
40
+ EmailAddressFrom: Schema.String,
41
+ EmailAddressTo: Schema.String,
42
+ EmailAddressCC: Schema.String,
43
+ EmailAddressBCC: Schema.String,
44
+ EmailSubject: Schema.String,
45
+ EmailBody: Schema.String
46
+ });
47
+ const invoiceFields = {
48
+ DocumentNumber: Schema.String,
49
+ CustomerNumber: Schema.String,
50
+ CustomerName: Schema.String,
51
+ Balance: Schema.Finite,
52
+ Booked: Schema.Boolean,
53
+ Cancelled: Schema.Boolean,
54
+ Comments: Schema.String,
55
+ CostCenter: Schema.String,
56
+ Credit: Schema.String,
57
+ Currency: Schema.String,
58
+ CurrencyRate: Schema.Finite,
59
+ CurrencyUnit: Schema.Finite,
60
+ DueDate: Schema.NullOr(Schema.String),
61
+ EmailInformation,
62
+ ExternalInvoiceReference1: Schema.String,
63
+ ExternalInvoiceReference2: Schema.String,
64
+ FinalPayDate: Schema.NullOr(Schema.String),
65
+ Gross: Schema.Finite,
66
+ InvoiceDate: Schema.String,
67
+ InvoiceRows: Schema.Array(FortnoxEmulatorInvoiceRow),
68
+ InvoiceType: Schema.String,
69
+ Net: Schema.Finite,
70
+ NotCompleted: Schema.Boolean,
71
+ NoxFinans: Schema.Boolean,
72
+ OCR: Schema.String,
73
+ OurReference: Schema.String,
74
+ Project: Schema.String,
75
+ Sent: Schema.Boolean,
76
+ TermsOfPayment: Schema.String,
77
+ Total: Schema.Finite,
78
+ TotalToPay: Schema.Finite,
79
+ TotalVAT: Schema.Finite,
80
+ VoucherNumber: Schema.NullOr(Schema.Int),
81
+ VoucherSeries: Schema.NullOr(Schema.String),
82
+ VoucherYear: Schema.NullOr(Schema.Int),
83
+ WayOfDelivery: Schema.String,
84
+ YourReference: Schema.String
85
+ };
86
+ /** A stored customer invoice with its rows. */
87
+ const FortnoxEmulatorInvoice = Schema.Struct(invoiceFields);
88
+ const customerFields = {
89
+ CustomerNumber: Schema.String,
90
+ Name: Schema.String,
91
+ Active: Schema.Boolean,
92
+ Address1: Schema.String,
93
+ Address2: Schema.String,
94
+ City: Schema.String,
95
+ Comments: Schema.String,
96
+ CostCenter: Schema.String,
97
+ Country: Schema.String,
98
+ CountryCode: Schema.String,
99
+ Currency: Schema.String,
100
+ Email: Schema.String,
101
+ EmailInvoice: Schema.String,
102
+ OrganisationNumber: Schema.String,
103
+ OurReference: Schema.String,
104
+ Phone1: Schema.String,
105
+ Phone2: Schema.String,
106
+ TermsOfPayment: Schema.String,
107
+ Type: Schema.String,
108
+ VATNumber: Schema.String,
109
+ VATType: Schema.String,
110
+ YourReference: Schema.String,
111
+ ZipCode: Schema.String
112
+ };
113
+ /** A stored customer. `Country` is read-only (derived from `CountryCode`). */
114
+ const FortnoxEmulatorCustomer = Schema.Struct(customerFields);
115
+ const companyFields = {
116
+ CompanyName: Schema.String,
117
+ OrganizationNumber: Schema.String,
118
+ DatabaseNumber: Schema.Int,
119
+ Address: Schema.String,
120
+ City: Schema.String,
121
+ ZipCode: Schema.String,
122
+ CountryCode: Schema.String,
123
+ VisitAddress: Schema.String,
124
+ VisitCity: Schema.String,
125
+ VisitZipCode: Schema.String,
126
+ VisitCountryCode: Schema.String
127
+ };
128
+ /** The company the credential belongs to (`GET /3/companyinformation`). */
129
+ const FortnoxEmulatorCompany = Schema.Struct(companyFields);
130
+ /** A recorded (never delivered) invoice email. */
131
+ const FortnoxEmulatorOutboxEntry = Schema.Struct({
132
+ DocumentNumber: Schema.String,
133
+ EmailAddressTo: Schema.String,
134
+ EmailAddressCC: Schema.String,
135
+ EmailAddressBCC: Schema.String,
136
+ EmailSubject: Schema.String,
137
+ /** ISO timestamp from the emulator clock. */
138
+ sentAt: Schema.String
139
+ });
140
+ const Counter = Schema.Int.check(Schema.isGreaterThanOrEqualTo(1));
141
+ const Counters = Schema.Struct({
142
+ /** Next RowId handed out; RowIds are regenerated on every row update. */
143
+ nextRowId: Counter,
144
+ /** Next DocumentNumber handed out by `POST /3/invoices`. */
145
+ nextDocumentNumber: Counter
146
+ });
147
+ /** The whole emulator state (JSON-compatible; what `snapshot()` returns). */
148
+ const FortnoxEmulatorStateSchema = Schema.Struct({
149
+ company: FortnoxEmulatorCompany,
150
+ customers: Schema.Array(FortnoxEmulatorCustomer),
151
+ invoices: Schema.Array(FortnoxEmulatorInvoice),
152
+ outbox: Schema.Array(FortnoxEmulatorOutboxEntry),
153
+ counters: Counters
154
+ });
155
+ /** A seeded invoice row: the writable row fields; totals and `VATCode` are derived. */
156
+ const FortnoxEmulatorInvoiceRowSeed = Schema.Struct({
157
+ RowId: Schema.optionalKey(Schema.Int),
158
+ AccountNumber: Schema.optionalKey(Schema.NullOr(Schema.Int)),
159
+ ArticleNumber: Schema.optionalKey(Schema.String),
160
+ CostCenter: Schema.optionalKey(Schema.String),
161
+ DeliveredQuantity: Schema.optionalKey(Schema.String),
162
+ Description: Schema.optionalKey(Schema.String),
163
+ Discount: Schema.optionalKey(Schema.Finite),
164
+ DiscountType: Schema.optionalKey(DiscountType),
165
+ Price: Schema.optionalKey(Schema.Finite),
166
+ Project: Schema.optionalKey(Schema.String),
167
+ Unit: Schema.optionalKey(Schema.String),
168
+ VAT: Schema.optionalKey(Schema.Finite)
169
+ });
170
+ const { InvoiceRows: _invoiceRows, ...invoiceScalarFields } = invoiceFields;
171
+ /**
172
+ * A seeded invoice: `DocumentNumber` and `CustomerNumber` are required; everything else has a
173
+ * synthetic default. Totals (`Net`, `Gross`, `TotalVAT`, `Total`, `TotalToPay`) are always
174
+ * computed from the rows; `Balance` defaults to `Total`.
175
+ */
176
+ const FortnoxEmulatorInvoiceSeed = Schema.Struct({
177
+ ...Struct.mapOmit(invoiceScalarFields, ["DocumentNumber", "CustomerNumber"], Schema.optionalKey),
178
+ InvoiceRows: Schema.optionalKey(Schema.Array(FortnoxEmulatorInvoiceRowSeed))
179
+ });
180
+ /** A seeded customer: `CustomerNumber` and `Name` are required; `Country` follows `CountryCode`. */
181
+ const FortnoxEmulatorCustomerSeed = Schema.Struct(Struct.mapOmit(customerFields, ["CustomerNumber", "Name"], Schema.optionalKey));
182
+ /** Account-variance profiles for the default seed. */
183
+ const FortnoxEmulatorProfile = Schema.Literals([
184
+ "default",
185
+ "empty-company",
186
+ "no-booked-invoices"
187
+ ]);
188
+ /**
189
+ * A typed seed. Start from `profile` (default `'default'`, the fixture entities); `company`,
190
+ * `customers`, and `invoices`, when given, replace that part of the profile.
191
+ */
192
+ const FortnoxEmulatorSeed = Schema.Struct({
193
+ profile: Schema.optionalKey(FortnoxEmulatorProfile),
194
+ company: Schema.optionalKey(FortnoxEmulatorCompany),
195
+ customers: Schema.optionalKey(Schema.Array(FortnoxEmulatorCustomerSeed)),
196
+ invoices: Schema.optionalKey(Schema.Array(FortnoxEmulatorInvoiceSeed))
197
+ });
198
+ const strict = { onExcessProperty: "error" };
199
+ const decodeSeedInput = Schema.decodeUnknownResult(FortnoxEmulatorSeed, strict);
200
+ const decodeStateInput = Schema.decodeUnknownResult(FortnoxEmulatorStateSchema, strict);
201
+ const issueMessage = (issue) => new Schema.SchemaError(issue).message;
202
+ /** `CountryCode` to the Swedish country name Fortnox derives `Country` from (a small table). */
203
+ const fortnoxEmulatorCountries = new Map([
204
+ ["SE", "Sverige"],
205
+ ["NO", "Norge"],
206
+ ["DK", "Danmark"],
207
+ ["FI", "Finland"],
208
+ ["DE", "Tyskland"],
209
+ ["GB", "Storbritannien"],
210
+ ["US", "USA"]
211
+ ]);
212
+ /** VAT percent to Fortnox sales VAT code. */
213
+ const fortnoxEmulatorVatCodes = new Map([
214
+ [25, "MP1"],
215
+ [12, "MP2"],
216
+ [6, "MP3"],
217
+ [0, "MF"]
218
+ ]);
219
+ const round2 = (value) => Math.round(value * 100) / 100;
220
+ /** Row total: `Price × DeliveredQuantity`, less a percent (or amount) discount. */
221
+ const rowTotal = (row) => {
222
+ const gross = row.Price * Number(row.DeliveredQuantity);
223
+ return round2(row.DiscountType === "AMOUNT" ? gross - row.Discount : gross * (100 - row.Discount) / 100);
224
+ };
225
+ /** A full row (fixture key order) with derived totals and VAT code. */
226
+ const buildRow = (input) => {
227
+ const total = rowTotal(input);
228
+ return {
229
+ AccountNumber: input.AccountNumber,
230
+ ArticleNumber: input.ArticleNumber,
231
+ ContributionPercent: "0",
232
+ ContributionValue: "0",
233
+ CostCenter: input.CostCenter,
234
+ DeliveredQuantity: input.DeliveredQuantity,
235
+ Description: input.Description,
236
+ Discount: input.Discount,
237
+ DiscountType: input.DiscountType,
238
+ HouseWork: false,
239
+ Price: input.Price,
240
+ PriceExcludingVAT: input.Price,
241
+ Project: input.Project,
242
+ RowId: input.RowId,
243
+ Total: total,
244
+ TotalExcludingVAT: total,
245
+ Unit: input.Unit,
246
+ VAT: input.VAT,
247
+ VATCode: fortnoxEmulatorVatCodes.get(input.VAT) ?? ""
248
+ };
249
+ };
250
+ /** Defaults for a new row (no positional match). */
251
+ const newRowDefaults = {
252
+ AccountNumber: 3001,
253
+ ArticleNumber: "",
254
+ CostCenter: "",
255
+ DeliveredQuantity: "1.00",
256
+ Description: "",
257
+ Discount: 0,
258
+ DiscountType: "PERCENT",
259
+ Price: 0,
260
+ Project: "",
261
+ Unit: "",
262
+ VAT: 25
263
+ };
264
+ /** Fortnox-style quantity: two decimals (`"2.00"`). */
265
+ const formatQuantity = (value) => value.toFixed(2);
266
+ /**
267
+ * Invoice totals from the rows: `Net = Gross = Σ row totals`, `TotalVAT = Σ row total × VAT%`,
268
+ * and `Total = TotalToPay = Net + TotalVAT` rounded to whole kronor (half up), matching the
269
+ * synthetic row-discount fixture (1150 + 287.5 → 1438).
270
+ */
271
+ const invoiceTotals = (rows) => {
272
+ const net = round2(rows.reduce((sum, row) => sum + row.Total, 0));
273
+ const vat = round2(rows.reduce((sum, row) => sum + row.Total * row.VAT / 100, 0));
274
+ const total = Math.round(net + vat);
275
+ return {
276
+ Net: net,
277
+ Gross: net,
278
+ TotalVAT: vat,
279
+ Total: total,
280
+ TotalToPay: total
281
+ };
282
+ };
283
+ const exampleCustomer = {
284
+ CustomerNumber: "1001",
285
+ Name: "Example Customer AB",
286
+ Active: true,
287
+ Address1: "Exempelgatan 1",
288
+ Address2: "",
289
+ City: "Exempelstad",
290
+ Comments: "Synthetic note: invoice monthly by email.",
291
+ CostCenter: "",
292
+ CountryCode: "SE",
293
+ Currency: "SEK",
294
+ Email: "billing@example.test",
295
+ EmailInvoice: "billing@example.test",
296
+ OrganisationNumber: "000000-0000",
297
+ OurReference: "",
298
+ Phone1: "",
299
+ Phone2: "",
300
+ TermsOfPayment: "30",
301
+ Type: "COMPANY",
302
+ VATNumber: "",
303
+ VATType: "SEVAT",
304
+ YourReference: "",
305
+ ZipCode: "000 00"
306
+ };
307
+ const exampleTrading = {
308
+ CustomerNumber: "1002",
309
+ Name: "Example Trading AB",
310
+ Active: true,
311
+ Address1: "Exempelvägen 2",
312
+ City: "Exempelstad",
313
+ Comments: "",
314
+ CountryCode: "SE",
315
+ Currency: "SEK",
316
+ Email: "accounts@example.test",
317
+ EmailInvoice: "accounts@example.test",
318
+ OrganisationNumber: "000000-0001",
319
+ TermsOfPayment: "30",
320
+ Type: "COMPANY",
321
+ VATType: "SEVAT",
322
+ ZipCode: "000 01"
323
+ };
324
+ const singleRow = (description, price) => ({
325
+ AccountNumber: 3001,
326
+ Description: description,
327
+ DeliveredQuantity: "1.00",
328
+ Price: price,
329
+ VAT: 25,
330
+ Discount: 0,
331
+ DiscountType: "PERCENT"
332
+ });
333
+ const defaultInvoices = [
334
+ {
335
+ DocumentNumber: "101",
336
+ CustomerNumber: "1001",
337
+ Balance: 0,
338
+ Booked: true,
339
+ DueDate: "2026-09-30",
340
+ FinalPayDate: "2026-09-20",
341
+ InvoiceDate: "2026-08-31",
342
+ OCR: "10151",
343
+ Sent: true,
344
+ VoucherNumber: 12,
345
+ VoucherSeries: "B",
346
+ VoucherYear: 3,
347
+ InvoiceRows: [singleRow("Monthly service (synthetic)", 1e3)]
348
+ },
349
+ {
350
+ DocumentNumber: "102",
351
+ CustomerNumber: "1002",
352
+ Balance: 3750,
353
+ Booked: true,
354
+ DueDate: "2026-09-30",
355
+ InvoiceDate: "2026-08-31",
356
+ OCR: "10250",
357
+ Sent: true,
358
+ VoucherNumber: 13,
359
+ VoucherSeries: "B",
360
+ VoucherYear: 3,
361
+ InvoiceRows: [singleRow("Project delivery (synthetic)", 3e3)]
362
+ },
363
+ {
364
+ DocumentNumber: "103",
365
+ CustomerNumber: "1001",
366
+ Booked: false,
367
+ DueDate: "2026-10-31",
368
+ InvoiceDate: "2026-09-30",
369
+ OCR: "10350",
370
+ InvoiceRows: [{
371
+ RowId: 1,
372
+ AccountNumber: 3001,
373
+ Description: "Consulting hours (synthetic)",
374
+ DeliveredQuantity: "2.00",
375
+ Unit: "h",
376
+ Price: 500,
377
+ VAT: 25,
378
+ Discount: 5,
379
+ DiscountType: "PERCENT"
380
+ }, {
381
+ RowId: 2,
382
+ AccountNumber: 3001,
383
+ Description: "Travel (synthetic)",
384
+ DeliveredQuantity: "1.00",
385
+ Price: 250,
386
+ VAT: 25,
387
+ Discount: 0,
388
+ DiscountType: "PERCENT"
389
+ }]
390
+ },
391
+ {
392
+ DocumentNumber: "104",
393
+ CustomerNumber: "1001",
394
+ Balance: 625,
395
+ Booked: true,
396
+ DueDate: "2026-10-31",
397
+ InvoiceDate: "2026-09-30",
398
+ VoucherNumber: 14,
399
+ VoucherSeries: "B",
400
+ VoucherYear: 3,
401
+ EmailInformation: {
402
+ EmailAddressFrom: "invoices@example.test",
403
+ EmailAddressTo: "billing@example.test",
404
+ EmailAddressCC: "",
405
+ EmailAddressBCC: "",
406
+ EmailSubject: "Invoice {no} from Example AB",
407
+ EmailBody: "Synthetic invoice email body."
408
+ },
409
+ InvoiceRows: [singleRow("Support hours (synthetic)", 500)]
410
+ },
411
+ {
412
+ DocumentNumber: "105",
413
+ CustomerNumber: "1001",
414
+ Booked: false,
415
+ DueDate: "2026-09-15",
416
+ InvoiceDate: "2026-08-16",
417
+ InvoiceRows: [singleRow("Workshop (synthetic)", 1e3)]
418
+ }
419
+ ];
420
+ const defaultCompany = {
421
+ CompanyName: "Example AB",
422
+ OrganizationNumber: "000000-0002",
423
+ DatabaseNumber: 100001,
424
+ Address: "Exempelgatan 10",
425
+ City: "Exempelstad",
426
+ ZipCode: "000 02",
427
+ CountryCode: "SE",
428
+ VisitAddress: "Exempelgatan 10",
429
+ VisitCity: "Exempelstad",
430
+ VisitZipCode: "000 02",
431
+ VisitCountryCode: "SE"
432
+ };
433
+ const unbooked = (invoice) => {
434
+ const { Balance: _balance, FinalPayDate: _finalPayDate, ...rest } = invoice;
435
+ return {
436
+ ...rest,
437
+ Booked: false,
438
+ VoucherNumber: null,
439
+ VoucherSeries: null,
440
+ VoucherYear: null
441
+ };
442
+ };
443
+ const profileEntities = (profile) => {
444
+ switch (profile) {
445
+ case "default": return {
446
+ company: defaultCompany,
447
+ customers: [exampleCustomer, exampleTrading],
448
+ invoices: defaultInvoices
449
+ };
450
+ case "empty-company": return {
451
+ company: defaultCompany,
452
+ customers: [],
453
+ invoices: []
454
+ };
455
+ case "no-booked-invoices": return {
456
+ company: defaultCompany,
457
+ customers: [exampleCustomer, exampleTrading],
458
+ invoices: defaultInvoices.map(unbooked)
459
+ };
460
+ }
461
+ };
462
+ /** Numeric-aware order for Fortnox numbers (`"999" < "1001"`). */
463
+ const compareNumbers = (left, right) => left.localeCompare(right, "en", { numeric: true });
464
+ const customerFromSeed = (seed) => {
465
+ const countryCode = seed.CountryCode ?? "SE";
466
+ return {
467
+ CustomerNumber: seed.CustomerNumber,
468
+ Name: seed.Name,
469
+ Active: seed.Active ?? true,
470
+ Address1: seed.Address1 ?? "",
471
+ Address2: seed.Address2 ?? "",
472
+ City: seed.City ?? "",
473
+ Comments: seed.Comments ?? "",
474
+ CostCenter: seed.CostCenter ?? "",
475
+ Country: seed.Country ?? fortnoxEmulatorCountries.get(countryCode) ?? "",
476
+ CountryCode: countryCode,
477
+ Currency: seed.Currency ?? "SEK",
478
+ Email: seed.Email ?? "",
479
+ EmailInvoice: seed.EmailInvoice ?? "",
480
+ OrganisationNumber: seed.OrganisationNumber ?? "",
481
+ OurReference: seed.OurReference ?? "",
482
+ Phone1: seed.Phone1 ?? "",
483
+ Phone2: seed.Phone2 ?? "",
484
+ TermsOfPayment: seed.TermsOfPayment ?? "30",
485
+ Type: seed.Type ?? "COMPANY",
486
+ VATNumber: seed.VATNumber ?? "",
487
+ VATType: seed.VATType ?? "SEVAT",
488
+ YourReference: seed.YourReference ?? "",
489
+ ZipCode: seed.ZipCode ?? ""
490
+ };
491
+ };
492
+ /** Default invoice email for a customer (the email fixture's sender, subject, and body). */
493
+ const defaultEmailInformation = (customer, company) => ({
494
+ EmailAddressFrom: "invoices@example.test",
495
+ EmailAddressTo: customer?.EmailInvoice ?? "",
496
+ EmailAddressCC: "",
497
+ EmailAddressBCC: "",
498
+ EmailSubject: `Invoice {no} from ${company.CompanyName}`,
499
+ EmailBody: "Synthetic invoice email body."
500
+ });
501
+ const rowFromSeed = (seed, ids) => buildRow({
502
+ ...newRowDefaults,
503
+ ...seed,
504
+ DeliveredQuantity: formatQuantity(Number(seed.DeliveredQuantity ?? "1")),
505
+ RowId: seed.RowId ?? ids.next++
506
+ });
507
+ /** Build a stored invoice from a seed; row ids come from `ids` unless the seed names them. */
508
+ const invoiceFromSeed = (seed, customer, company, ids) => {
509
+ const rows = (seed.InvoiceRows ?? []).map((row) => rowFromSeed(row, ids));
510
+ const totals = invoiceTotals(rows);
511
+ return {
512
+ DocumentNumber: seed.DocumentNumber,
513
+ CustomerNumber: seed.CustomerNumber,
514
+ CustomerName: seed.CustomerName ?? customer?.Name ?? "",
515
+ Balance: seed.Balance ?? totals.Total,
516
+ Booked: seed.Booked ?? false,
517
+ Cancelled: seed.Cancelled ?? false,
518
+ Comments: seed.Comments ?? "",
519
+ CostCenter: seed.CostCenter ?? "",
520
+ Credit: seed.Credit ?? "false",
521
+ Currency: seed.Currency ?? customer?.Currency ?? "SEK",
522
+ CurrencyRate: seed.CurrencyRate ?? 1,
523
+ CurrencyUnit: seed.CurrencyUnit ?? 1,
524
+ DueDate: seed.DueDate ?? null,
525
+ EmailInformation: seed.EmailInformation ?? defaultEmailInformation(customer, company),
526
+ ExternalInvoiceReference1: seed.ExternalInvoiceReference1 ?? "",
527
+ ExternalInvoiceReference2: seed.ExternalInvoiceReference2 ?? "",
528
+ FinalPayDate: seed.FinalPayDate ?? null,
529
+ Gross: totals.Gross,
530
+ InvoiceDate: seed.InvoiceDate ?? "2026-09-30",
531
+ InvoiceRows: rows,
532
+ InvoiceType: seed.InvoiceType ?? "INVOICE",
533
+ Net: totals.Net,
534
+ NotCompleted: seed.NotCompleted ?? false,
535
+ NoxFinans: seed.NoxFinans ?? false,
536
+ OCR: seed.OCR ?? "",
537
+ OurReference: seed.OurReference ?? "",
538
+ Project: seed.Project ?? "",
539
+ Sent: seed.Sent ?? false,
540
+ TermsOfPayment: seed.TermsOfPayment ?? customer?.TermsOfPayment ?? "30",
541
+ Total: totals.Total,
542
+ TotalToPay: totals.TotalToPay,
543
+ TotalVAT: totals.TotalVAT,
544
+ VoucherNumber: seed.VoucherNumber ?? null,
545
+ VoucherSeries: seed.VoucherSeries ?? null,
546
+ VoucherYear: seed.VoucherYear ?? null,
547
+ WayOfDelivery: seed.WayOfDelivery ?? "",
548
+ YourReference: seed.YourReference ?? ""
549
+ };
550
+ };
551
+ const duplicate = (values) => values.find((value, index) => values.indexOf(value) !== index);
552
+ const quantityProblem = (rows) => rows.find((row) => row.DeliveredQuantity !== void 0 && !Number.isFinite(Number(row.DeliveredQuantity)));
553
+ /** Integrity problems a decoded seed can still have (duplicates, dangling references). */
554
+ const seedProblem = (entities) => {
555
+ const customerNumbers = entities.customers.map((customer) => customer.CustomerNumber);
556
+ const documentNumbers = entities.invoices.map((invoice) => invoice.DocumentNumber);
557
+ const rowIds = entities.invoices.flatMap((invoice) => (invoice.InvoiceRows ?? []).flatMap((row) => row.RowId === void 0 ? [] : [row.RowId]));
558
+ const duplicateCustomer = duplicate(customerNumbers);
559
+ const duplicateInvoice = duplicate(documentNumbers);
560
+ const duplicateRow = duplicate(rowIds);
561
+ if (duplicateCustomer !== void 0) return `duplicate CustomerNumber ${duplicateCustomer}`;
562
+ if (duplicateInvoice !== void 0) return `duplicate DocumentNumber ${duplicateInvoice}`;
563
+ if (duplicateRow !== void 0) return `duplicate RowId ${duplicateRow}`;
564
+ const dangling = entities.invoices.find((invoice) => !customerNumbers.includes(invoice.CustomerNumber));
565
+ if (dangling !== void 0) return `invoice ${dangling.DocumentNumber} references missing customer ${dangling.CustomerNumber}`;
566
+ const badQuantity = entities.invoices.find((invoice) => quantityProblem(invoice.InvoiceRows ?? []) !== void 0);
567
+ return badQuantity === void 0 ? void 0 : `invoice ${badQuantity.DocumentNumber} has a non-numeric DeliveredQuantity`;
568
+ };
569
+ const nextNumber = (numbers) => numbers.reduce((max, value) => {
570
+ const parsed = Number(value);
571
+ return Number.isSafeInteger(parsed) && parsed >= max ? parsed + 1 : max;
572
+ }, 1);
573
+ /** Build the emulator state for a decoded seed; a string is an integrity problem. */
574
+ const stateFromSeed = (seed) => {
575
+ const profile = profileEntities(seed.profile ?? "default");
576
+ const entities = {
577
+ company: seed.company ?? profile.company,
578
+ customers: seed.customers ?? profile.customers,
579
+ invoices: seed.invoices ?? profile.invoices
580
+ };
581
+ const problem = seedProblem(entities);
582
+ if (problem !== void 0) return problem;
583
+ const customers = entities.customers.map(customerFromSeed).sort((left, right) => compareNumbers(left.CustomerNumber, right.CustomerNumber));
584
+ const explicitRowIds = entities.invoices.flatMap((invoice) => (invoice.InvoiceRows ?? []).flatMap((row) => row.RowId === void 0 ? [] : [row.RowId]));
585
+ const ids = { next: Math.max(0, ...explicitRowIds) + 1 };
586
+ const invoices = entities.invoices.map((invoice) => invoiceFromSeed(invoice, customers.find((customer) => customer.CustomerNumber === invoice.CustomerNumber), entities.company, ids)).sort((left, right) => compareNumbers(left.DocumentNumber, right.DocumentNumber));
587
+ return {
588
+ company: entities.company,
589
+ customers,
590
+ invoices,
591
+ outbox: [],
592
+ counters: {
593
+ nextRowId: ids.next,
594
+ nextDocumentNumber: nextNumber(invoices.map((invoice) => invoice.DocumentNumber))
595
+ }
596
+ };
597
+ };
598
+ /** Decode and build a seed; a string is the reason it is invalid. */
599
+ const buildSeedState = (input) => {
600
+ const decoded = decodeSeedInput(input);
601
+ return Result.isFailure(decoded) ? issueMessage(decoded.failure.issue) : stateFromSeed(decoded.success);
602
+ };
603
+ /** Decode a full state (a restored snapshot); a string is the reason it is invalid. */
604
+ const decodeState = (input) => {
605
+ const decoded = decodeStateInput(input);
606
+ if (Result.isFailure(decoded)) return issueMessage(decoded.failure.issue);
607
+ return { ...decoded.success };
608
+ };
609
+ //#endregion
610
+ export { FortnoxEmulatorCompany, FortnoxEmulatorCustomer, FortnoxEmulatorCustomerSeed, FortnoxEmulatorInvoice, FortnoxEmulatorInvoiceRow, FortnoxEmulatorInvoiceRowSeed, FortnoxEmulatorInvoiceSeed, FortnoxEmulatorOutboxEntry, FortnoxEmulatorProfile, FortnoxEmulatorSeed, FortnoxEmulatorStateSchema, buildRow, buildSeedState, compareNumbers, decodeState, defaultEmailInformation, formatQuantity, fortnoxEmulatorCountries, fortnoxEmulatorVatCodes, invoiceFromSeed, invoiceTotals, newRowDefaults, round2, rowTotal };
611
+
612
+ //# sourceMappingURL=state.mjs.map