solve-engine 2.25.0 → 2.27.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 (240) hide show
  1. package/dist/CalendarBackend-MdS3Bb4P.d.cts +181 -0
  2. package/dist/CalendarBackend-MdS3Bb4P.d.ts +181 -0
  3. package/dist/{Configuration-DnzYPmoK.d.cts → Configuration-BxriK9Kw.d.cts} +63 -4
  4. package/dist/{Configuration-DnzYPmoK.d.ts → Configuration-BxriK9Kw.d.ts} +63 -4
  5. package/dist/DateCalendar-B85t6Vk6.d.ts +90 -0
  6. package/dist/DateCalendar-CUGI1fT4.d.cts +90 -0
  7. package/dist/{EngineError-fR1K1rvx.d.cts → EngineError-C-kBwYlN.d.cts} +31 -4
  8. package/dist/{EngineError-fR1K1rvx.d.ts → EngineError-C-kBwYlN.d.ts} +31 -4
  9. package/dist/{FormattingSettings-bRKjU7wI.d.ts → FormattingSettings-ByO-4wiM.d.cts} +14 -0
  10. package/dist/{FormattingSettings-bRKjU7wI.d.cts → FormattingSettings-CvCzAfsz.d.ts} +14 -0
  11. package/dist/{Lexer-aB95pjoX.d.cts → Lexer-DhGhoAa2.d.cts} +13 -3
  12. package/dist/{Lexer-Bmctxl0n.d.ts → Lexer-DqtnZMC5.d.ts} +13 -3
  13. package/dist/{PackageCompatibility-CUVg8tmt.d.cts → PackageCompatibility-CNiTtC6S.d.cts} +1 -1
  14. package/dist/{PackageCompatibility-BludTs7v.d.ts → PackageCompatibility-fj_f7uqC.d.ts} +1 -1
  15. package/dist/{PackageRegistry-Dvn4i2QK.d.cts → PackageRegistry-BHBCFswo.d.cts} +328 -14
  16. package/dist/{PackageRegistry-DT-x32OM.d.ts → PackageRegistry-CNZUwWHJ.d.ts} +328 -14
  17. package/dist/{Parselet-BawfGuTF.d.cts → Parselet-DF3864la.d.cts} +19 -3
  18. package/dist/{Parselet-DqTbbtWA.d.ts → Parselet-Dgymjxzd.d.ts} +19 -3
  19. package/dist/{Token-CbP_OutD.d.cts → Token-D8f7yaz1.d.cts} +17 -0
  20. package/dist/{Token-CbP_OutD.d.ts → Token-D8f7yaz1.d.ts} +17 -0
  21. package/dist/{TokenNormalizer-CLBtiE8M.d.ts → TokenNormalizer-IF7nPRMp.d.ts} +1 -1
  22. package/dist/{TokenNormalizer-CjTDmHgB.d.cts → TokenNormalizer-Pe3_390t.d.cts} +1 -1
  23. package/dist/{ScopeManager-B636am7Y.d.ts → VMBuiltins-CZiZRKn-.d.ts} +91 -9
  24. package/dist/{ScopeManager-CdwX0VTw.d.cts → VMBuiltins-kv4rr0y5.d.cts} +91 -9
  25. package/dist/{VMCheckpoints-DDlxNssY.d.ts → VMCheckpoints-DXze6ypg.d.ts} +2 -2
  26. package/dist/{VMCheckpoints-CYqeq8IV.d.cts → VMCheckpoints-yun4ocSv.d.cts} +2 -2
  27. package/dist/{Value-Ds3Gy07C.d.cts → Value-BYHw-x7q.d.cts} +57 -1
  28. package/dist/{Value-Ds3Gy07C.d.ts → Value-BYHw-x7q.d.ts} +57 -1
  29. package/dist/{WorkerError-B1dF3VYT.d.cts → WorkerError-BLZyNq6M.d.cts} +1 -1
  30. package/dist/{WorkerError-dneODN-u.d.ts → WorkerError-CfBJYueR.d.ts} +1 -1
  31. package/dist/chunk-2SYYKQ4Q.cjs +2 -0
  32. package/dist/chunk-2SYYKQ4Q.cjs.map +1 -0
  33. package/dist/chunk-6EYKVQT3.cjs +2 -0
  34. package/dist/chunk-6EYKVQT3.cjs.map +1 -0
  35. package/dist/chunk-7RC6RBS6.cjs +2 -0
  36. package/dist/chunk-7RC6RBS6.cjs.map +1 -0
  37. package/dist/chunk-AZX4NTYN.cjs +3 -0
  38. package/dist/chunk-AZX4NTYN.cjs.map +1 -0
  39. package/dist/{chunk-JFZ5SLF7.js → chunk-BCR53EIL.js} +2 -2
  40. package/dist/{chunk-JFZ5SLF7.js.map → chunk-BCR53EIL.js.map} +1 -1
  41. package/dist/chunk-BCY2WY5P.js +5 -0
  42. package/dist/chunk-BCY2WY5P.js.map +1 -0
  43. package/dist/chunk-BLJ6E577.js +2 -0
  44. package/dist/chunk-BLJ6E577.js.map +1 -0
  45. package/dist/chunk-CL7DM2FX.js +2 -0
  46. package/dist/chunk-CL7DM2FX.js.map +1 -0
  47. package/dist/{chunk-BMXYR5LI.cjs → chunk-CQLCTKMX.cjs} +2 -2
  48. package/dist/{chunk-BMXYR5LI.cjs.map → chunk-CQLCTKMX.cjs.map} +1 -1
  49. package/dist/chunk-D4VBWPWN.js +2 -0
  50. package/dist/chunk-D4VBWPWN.js.map +1 -0
  51. package/dist/chunk-DFMAZ6XM.cjs +3 -0
  52. package/dist/chunk-DFMAZ6XM.cjs.map +1 -0
  53. package/dist/chunk-E4HAKNBQ.cjs +2 -0
  54. package/dist/chunk-E4HAKNBQ.cjs.map +1 -0
  55. package/dist/{chunk-XHQYHXRE.js → chunk-ESZNJQ2C.js} +3 -3
  56. package/dist/{chunk-XHQYHXRE.js.map → chunk-ESZNJQ2C.js.map} +1 -1
  57. package/dist/{chunk-IJMNVBIS.js → chunk-FAO6DQ74.js} +2 -2
  58. package/dist/chunk-FAO6DQ74.js.map +1 -0
  59. package/dist/{chunk-WGP4UUO5.cjs → chunk-FDKTESBC.cjs} +2 -2
  60. package/dist/{chunk-WGP4UUO5.cjs.map → chunk-FDKTESBC.cjs.map} +1 -1
  61. package/dist/{chunk-NEGZZB7F.cjs → chunk-G2V33LFM.cjs} +2 -2
  62. package/dist/{chunk-NEGZZB7F.cjs.map → chunk-G2V33LFM.cjs.map} +1 -1
  63. package/dist/chunk-GJZIJK2Q.cjs +2 -0
  64. package/dist/chunk-GJZIJK2Q.cjs.map +1 -0
  65. package/dist/chunk-GVL3ZMS7.cjs +2 -0
  66. package/dist/chunk-GVL3ZMS7.cjs.map +1 -0
  67. package/dist/{chunk-YBQPEWT7.cjs → chunk-GXO7TSXQ.cjs} +3 -3
  68. package/dist/chunk-GXO7TSXQ.cjs.map +1 -0
  69. package/dist/{chunk-OONQ3V3I.js → chunk-HANGBVEE.js} +2 -2
  70. package/dist/{chunk-OONQ3V3I.js.map → chunk-HANGBVEE.js.map} +1 -1
  71. package/dist/chunk-J4K72CQN.js +2 -0
  72. package/dist/chunk-J4K72CQN.js.map +1 -0
  73. package/dist/{chunk-72PYPENZ.js → chunk-LE6WZLJ4.js} +2 -2
  74. package/dist/{chunk-72PYPENZ.js.map → chunk-LE6WZLJ4.js.map} +1 -1
  75. package/dist/chunk-LQIRBP4Q.js +2 -0
  76. package/dist/chunk-LQIRBP4Q.js.map +1 -0
  77. package/dist/{chunk-RDYXH7ML.js → chunk-LTUYWJGO.js} +2 -2
  78. package/dist/{chunk-RDYXH7ML.js.map → chunk-LTUYWJGO.js.map} +1 -1
  79. package/dist/chunk-O5PO4D2A.cjs +2 -0
  80. package/dist/chunk-O5PO4D2A.cjs.map +1 -0
  81. package/dist/chunk-PQFI55AC.js +3 -0
  82. package/dist/chunk-PQFI55AC.js.map +1 -0
  83. package/dist/chunk-QQHHZPEW.cjs +2 -0
  84. package/dist/chunk-QQHHZPEW.cjs.map +1 -0
  85. package/dist/chunk-REZQFPVX.js +2 -0
  86. package/dist/chunk-REZQFPVX.js.map +1 -0
  87. package/dist/chunk-RRUGQ6DM.js +2 -0
  88. package/dist/chunk-RRUGQ6DM.js.map +1 -0
  89. package/dist/chunk-S3ODNMJS.js +2 -0
  90. package/dist/chunk-S3ODNMJS.js.map +1 -0
  91. package/dist/{chunk-SAF3B3AX.cjs → chunk-SE6ZCGZ5.cjs} +2 -2
  92. package/dist/{chunk-SAF3B3AX.cjs.map → chunk-SE6ZCGZ5.cjs.map} +1 -1
  93. package/dist/chunk-TC23XEAV.js +2 -0
  94. package/dist/chunk-TC23XEAV.js.map +1 -0
  95. package/dist/{chunk-FYAMQFZZ.cjs → chunk-TMQ37JQY.cjs} +3 -3
  96. package/dist/{chunk-FYAMQFZZ.cjs.map → chunk-TMQ37JQY.cjs.map} +1 -1
  97. package/dist/chunk-TPPM4QSS.cjs +2 -0
  98. package/dist/chunk-TPPM4QSS.cjs.map +1 -0
  99. package/dist/chunk-UVHD7BBC.js +3 -0
  100. package/dist/{chunk-ZDCZ5IDD.js.map → chunk-UVHD7BBC.js.map} +1 -1
  101. package/dist/{chunk-57PSJQQW.js → chunk-VB6QMU2W.js} +3 -3
  102. package/dist/chunk-VB6QMU2W.js.map +1 -0
  103. package/dist/chunk-VQO54ZMA.js +2 -0
  104. package/dist/chunk-VQO54ZMA.js.map +1 -0
  105. package/dist/{chunk-7DP57BA7.js → chunk-Y7XRA2EV.js} +2 -2
  106. package/dist/{chunk-7DP57BA7.js.map → chunk-Y7XRA2EV.js.map} +1 -1
  107. package/dist/{chunk-5IJD5L3O.cjs → chunk-YBQOQTVL.cjs} +2 -2
  108. package/dist/chunk-YBQOQTVL.cjs.map +1 -0
  109. package/dist/{chunk-EL2XUOWX.js → chunk-YG7UWQFV.js} +2 -2
  110. package/dist/{chunk-EL2XUOWX.js.map → chunk-YG7UWQFV.js.map} +1 -1
  111. package/dist/chunk-YSHWNCDH.cjs +5 -0
  112. package/dist/chunk-YSHWNCDH.cjs.map +1 -0
  113. package/dist/chunk-ZC2NPRLO.js +3 -0
  114. package/dist/chunk-ZC2NPRLO.js.map +1 -0
  115. package/dist/{chunk-FYTB7SDP.cjs → chunk-ZDJTDFTR.cjs} +2 -2
  116. package/dist/{chunk-FYTB7SDP.cjs.map → chunk-ZDJTDFTR.cjs.map} +1 -1
  117. package/dist/chunk-ZE5KKMBV.cjs +2 -0
  118. package/dist/chunk-ZE5KKMBV.cjs.map +1 -0
  119. package/dist/{chunk-4BAUQE6A.cjs → chunk-ZPHUTCJ5.cjs} +3 -3
  120. package/dist/{chunk-4BAUQE6A.cjs.map → chunk-ZPHUTCJ5.cjs.map} +1 -1
  121. package/dist/{chunk-GBCN7FNV.cjs → chunk-ZSLVLMO5.cjs} +2 -2
  122. package/dist/{chunk-GBCN7FNV.cjs.map → chunk-ZSLVLMO5.cjs.map} +1 -1
  123. package/dist/constants.cjs +1 -1
  124. package/dist/constants.d.cts +1 -1
  125. package/dist/constants.d.ts +1 -1
  126. package/dist/constants.js +1 -1
  127. package/dist/engine.cjs +1 -1
  128. package/dist/engine.d.cts +14 -12
  129. package/dist/engine.d.ts +14 -12
  130. package/dist/engine.js +1 -1
  131. package/dist/errors.cjs +1 -1
  132. package/dist/errors.d.cts +3 -3
  133. package/dist/errors.d.ts +3 -3
  134. package/dist/errors.js +1 -1
  135. package/dist/format.cjs +1 -1
  136. package/dist/format.d.cts +4 -3
  137. package/dist/format.d.ts +4 -3
  138. package/dist/format.js +1 -1
  139. package/dist/index.cjs +1 -1
  140. package/dist/index.cjs.map +1 -1
  141. package/dist/index.d.cts +15 -13
  142. package/dist/index.d.ts +15 -13
  143. package/dist/index.js +1 -1
  144. package/dist/index.js.map +1 -1
  145. package/dist/language.d.cts +12 -11
  146. package/dist/language.d.ts +12 -11
  147. package/dist/lexer.cjs +1 -1
  148. package/dist/lexer.d.cts +4 -4
  149. package/dist/lexer.d.ts +4 -4
  150. package/dist/lexer.js +1 -1
  151. package/dist/normalizer.cjs +1 -1
  152. package/dist/normalizer.d.cts +3 -3
  153. package/dist/normalizer.d.ts +3 -3
  154. package/dist/normalizer.js +1 -1
  155. package/dist/packages.cjs +1 -1
  156. package/dist/packages.d.cts +11 -10
  157. package/dist/packages.d.ts +11 -10
  158. package/dist/packages.js +1 -1
  159. package/dist/parser.cjs +1 -1
  160. package/dist/parser.d.cts +5 -4
  161. package/dist/parser.d.ts +5 -4
  162. package/dist/parser.js +1 -1
  163. package/dist/{pipeline-69q2tsLE.d.cts → pipeline-BYkKNpql.d.cts} +1 -1
  164. package/dist/{pipeline-DTqGLPsV.d.ts → pipeline-Cl7KW8CB.d.ts} +1 -1
  165. package/dist/resolvers.d.cts +2 -2
  166. package/dist/resolvers.d.ts +2 -2
  167. package/dist/temporal.cjs +2 -0
  168. package/dist/temporal.cjs.map +1 -0
  169. package/dist/temporal.d.cts +201 -0
  170. package/dist/temporal.d.ts +201 -0
  171. package/dist/temporal.js +2 -0
  172. package/dist/temporal.js.map +1 -0
  173. package/dist/testing.cjs +2 -2
  174. package/dist/testing.cjs.map +1 -1
  175. package/dist/testing.d.cts +12 -11
  176. package/dist/testing.d.ts +12 -11
  177. package/dist/testing.js +1 -1
  178. package/dist/testing.js.map +1 -1
  179. package/dist/uom.cjs +1 -1
  180. package/dist/uom.d.cts +2 -2
  181. package/dist/uom.d.ts +2 -2
  182. package/dist/uom.js +1 -1
  183. package/dist/vm.cjs +1 -1
  184. package/dist/vm.cjs.map +1 -1
  185. package/dist/vm.d.cts +8 -56
  186. package/dist/vm.d.ts +8 -56
  187. package/dist/vm.js +1 -1
  188. package/dist/vm.js.map +1 -1
  189. package/dist/worker.cjs +2 -2
  190. package/dist/worker.cjs.map +1 -1
  191. package/dist/worker.d.cts +35 -13
  192. package/dist/worker.d.ts +35 -13
  193. package/dist/worker.js +2 -2
  194. package/dist/worker.js.map +1 -1
  195. package/package.json +12 -1
  196. package/dist/chunk-4BRTUFTH.js +0 -2
  197. package/dist/chunk-4BRTUFTH.js.map +0 -1
  198. package/dist/chunk-4NZXCHQL.cjs +0 -2
  199. package/dist/chunk-4NZXCHQL.cjs.map +0 -1
  200. package/dist/chunk-57PSJQQW.js.map +0 -1
  201. package/dist/chunk-5IJD5L3O.cjs.map +0 -1
  202. package/dist/chunk-634ILVMP.cjs +0 -2
  203. package/dist/chunk-634ILVMP.cjs.map +0 -1
  204. package/dist/chunk-63ZOOUOL.js +0 -2
  205. package/dist/chunk-63ZOOUOL.js.map +0 -1
  206. package/dist/chunk-77KI7AKJ.cjs +0 -2
  207. package/dist/chunk-77KI7AKJ.cjs.map +0 -1
  208. package/dist/chunk-7N3IJSWF.js +0 -5
  209. package/dist/chunk-7N3IJSWF.js.map +0 -1
  210. package/dist/chunk-DUYTXLO2.js +0 -2
  211. package/dist/chunk-DUYTXLO2.js.map +0 -1
  212. package/dist/chunk-IJMNVBIS.js.map +0 -1
  213. package/dist/chunk-JSM3O7EM.cjs +0 -2
  214. package/dist/chunk-JSM3O7EM.cjs.map +0 -1
  215. package/dist/chunk-MZMA32NE.js +0 -3
  216. package/dist/chunk-MZMA32NE.js.map +0 -1
  217. package/dist/chunk-N4SSR7Q6.js +0 -2
  218. package/dist/chunk-N4SSR7Q6.js.map +0 -1
  219. package/dist/chunk-NMU5E7W7.js +0 -2
  220. package/dist/chunk-NMU5E7W7.js.map +0 -1
  221. package/dist/chunk-OB2VX4IL.js +0 -2
  222. package/dist/chunk-OB2VX4IL.js.map +0 -1
  223. package/dist/chunk-RAPEZR5L.cjs +0 -2
  224. package/dist/chunk-RAPEZR5L.cjs.map +0 -1
  225. package/dist/chunk-SPOVFRZO.cjs +0 -5
  226. package/dist/chunk-SPOVFRZO.cjs.map +0 -1
  227. package/dist/chunk-SQHBOWES.cjs +0 -2
  228. package/dist/chunk-SQHBOWES.cjs.map +0 -1
  229. package/dist/chunk-UF5XMZTT.js +0 -2
  230. package/dist/chunk-UF5XMZTT.js.map +0 -1
  231. package/dist/chunk-UV3EUIBT.cjs +0 -3
  232. package/dist/chunk-UV3EUIBT.cjs.map +0 -1
  233. package/dist/chunk-VMSCRVNX.cjs +0 -2
  234. package/dist/chunk-VMSCRVNX.cjs.map +0 -1
  235. package/dist/chunk-XBGK3TTU.cjs +0 -3
  236. package/dist/chunk-XBGK3TTU.cjs.map +0 -1
  237. package/dist/chunk-XX55RR4Q.js +0 -3
  238. package/dist/chunk-XX55RR4Q.js.map +0 -1
  239. package/dist/chunk-YBQPEWT7.cjs.map +0 -1
  240. package/dist/chunk-ZDCZ5IDD.js +0 -3
@@ -0,0 +1,181 @@
1
+ /**
2
+ * The calendar the engine computes dates with, behind one interface.
3
+ *
4
+ * Every date the engine holds is an instant: epoch milliseconds in a
5
+ * `Datetime` value, with no zone attached. Every date *question* the engine
6
+ * answers is a calendar question about that instant: which day it falls on,
7
+ * what the same wall-clock time a month later is, whether it is a Saturday,
8
+ * how it is written out. Answering those needs a time zone and a set of
9
+ * calendar rules, and until this interface existed the answer was always the
10
+ * JavaScript `Date` object read in the host process's own zone, scattered
11
+ * across some twenty files.
12
+ *
13
+ * A backend gathers those questions into one place so that a different
14
+ * implementation can answer them. Two ship with the engine. {@link DateCalendar}
15
+ * is the same `Date` code moved behind these methods and is the default, so
16
+ * nothing observable changes for a host that configures nothing. The
17
+ * `Temporal` backend (`solve-engine/temporal`) answers the same questions
18
+ * through a `Temporal` implementation the host hands it, native or polyfilled,
19
+ * and carries a time zone of its own rather than the process's; the engine
20
+ * never imports a polyfill.
21
+ *
22
+ * The contract is deliberately narrow. Methods take and return plain numbers
23
+ * and strings, never a `Date` or a `Temporal` object, so a `Datetime` value's
24
+ * payload stays a number and no worker message, snapshot or arena entry
25
+ * changes shape. Arithmetic whose answer does not depend on a zone (a day
26
+ * number, the days in a month, the ISO week) lives beside the backend in
27
+ * `calendar/Gregorian.ts` rather than behind it, because sharing one
28
+ * implementation is what keeps two backends from disagreeing on it.
29
+ *
30
+ * The shape is public and settled by the two backends that implement it. A
31
+ * host may implement the interface directly; a change to it follows the
32
+ * package's semantic versioning, so a new required method is a major.
33
+ *
34
+ * @module CalendarBackend
35
+ */
36
+ /**
37
+ * The calendar fields of one instant, read in the backend's zone.
38
+ *
39
+ * `month0` counts from zero (January is 0) and `weekday` from Sunday (0) to
40
+ * Saturday (6), matching `Date` at every internal boundary so a backend cannot
41
+ * be off by one against the code that reads it. Every field is `NaN` for an
42
+ * instant the backend cannot represent.
43
+ */
44
+ interface CalendarFields {
45
+ readonly year: number;
46
+ /** Zero-based month: 0 is January, 11 is December. */
47
+ readonly month0: number;
48
+ /** Day of the month, from 1. */
49
+ readonly day: number;
50
+ /** Day of the week: 0 is Sunday, 6 is Saturday. */
51
+ readonly weekday: number;
52
+ readonly hour: number;
53
+ readonly minute: number;
54
+ readonly second: number;
55
+ readonly millisecond: number;
56
+ }
57
+ /**
58
+ * The calendar fields a named time zone shows for an instant: the date and
59
+ * the wall-clock time, with the same zero-based month as {@link CalendarFields}.
60
+ * Sub-second precision is never needed for a zone conversion, so there is no
61
+ * millisecond field.
62
+ */
63
+ interface ZonedFields {
64
+ readonly year: number;
65
+ /** Zero-based month: 0 is January, 11 is December. */
66
+ readonly month0: number;
67
+ /** Day of the month, from 1. */
68
+ readonly day: number;
69
+ readonly hour: number;
70
+ readonly minute: number;
71
+ readonly second: number;
72
+ }
73
+ /**
74
+ * The calendar computations the engine performs, as one replaceable unit.
75
+ *
76
+ * "Local" throughout means the backend's own zone: the host process's zone for
77
+ * the `Date` backend, the configured zone for the `Temporal` one. A local
78
+ * operation that cannot be represented (an instant past the range the backend
79
+ * supports, a field that is not finite) answers `NaN`, never throws; the
80
+ * caller decides what an unrepresentable date means for its form.
81
+ *
82
+ * The four named-zone methods are the exception, and the contract is stated on
83
+ * each: a zone name the runtime does not know throws its `RangeError`, as
84
+ * `Intl` and `Temporal` both do, because a zone reaches the backend only from
85
+ * the engine's own zone registry and an unknown one is a data fault the caller
86
+ * should see rather than a `NaN` to display. Callers hand those methods a
87
+ * finite instant (`now()`, or a literal already checked).
88
+ */
89
+ interface CalendarBackend {
90
+ /** The current instant, in epoch milliseconds. Read at evaluation time, never baked into bytecode. */
91
+ now(): number;
92
+ /** The local calendar fields of an instant, `weekday` included. See {@link CalendarFields}. */
93
+ fields(epochMs: number): CalendarFields;
94
+ /**
95
+ * Local midnight on a calendar date, in epoch milliseconds.
96
+ *
97
+ * Fields overflow the way `Date`'s do (month 12 is January of the next
98
+ * year, day 0 the last day of the month before), which is what a caller
99
+ * checking for a rolled-over literal relies on: build the date, read its
100
+ * fields back, and a 30 February shows up as 1 or 2 March.
101
+ */
102
+ localMidnight(year: number, month0: number, day: number): number;
103
+ /**
104
+ * A wall-clock time on a calendar date, given as minutes past local
105
+ * midnight, in epoch milliseconds.
106
+ *
107
+ * The minutes name a clock reading, not an elapsed span: 540 minutes is
108
+ * 09:00 on that date even on a day with a daylight-saving transition,
109
+ * where 540 minutes of elapsed time from midnight would land at 10:00 or
110
+ * 08:00.
111
+ */
112
+ localWallClock(year: number, month0: number, day: number, minutesPastMidnight: number): number;
113
+ /**
114
+ * Move an instant by whole calendar days, holding the local wall-clock
115
+ * time. A day that contains a daylight-saving transition is 23 or 25
116
+ * hours long, so this is a field step, not an addition of milliseconds.
117
+ */
118
+ addDays(epochMs: number, days: number): number;
119
+ /**
120
+ * Move an instant by whole calendar months, holding the local wall-clock
121
+ * time and clamping the day to the length of the month landed in: 31
122
+ * January plus a month is 28 February, or 29 in a leap year, never 3 March.
123
+ */
124
+ addMonths(epochMs: number, months: number): number;
125
+ /** The local zone's offset from UTC at an instant, in minutes, positive when ahead of UTC. */
126
+ utcOffsetMinutes(epochMs: number): number;
127
+ /**
128
+ * Parse an ISO 8601 date or date-time string to epoch milliseconds, or
129
+ * `NaN` when it names no instant.
130
+ *
131
+ * A date-only string (`2019-04-01`) is UTC midnight; a date-time with no
132
+ * offset and no `Z` is local time. Both readings are the ECMAScript ones,
133
+ * and every backend reproduces them so the two spellings of a literal keep
134
+ * meaning the same instant whichever backend is in use.
135
+ */
136
+ parseIso8601(text: string): number;
137
+ /** The spelled-out local date in a locale, `Tuesday, March 10, 2026` in `en`. */
138
+ formatLongDate(epochMs: number, locale: string): string;
139
+ /** The local time of day in a locale, `9:30:00 AM` in `en`. */
140
+ formatTimeOfDay(epochMs: number, locale: string): string;
141
+ /**
142
+ * A named IANA zone's offset from UTC at an instant, in minutes, positive
143
+ * when ahead of UTC. Throws the runtime's `RangeError` for a zone it does
144
+ * not know or an instant it cannot represent.
145
+ */
146
+ zoneOffsetMinutes(zone: string, epochMs: number): number;
147
+ /**
148
+ * The calendar date and wall-clock time a named IANA zone shows for an
149
+ * instant. Throws the runtime's `RangeError` for a zone it does not know or
150
+ * an instant it cannot represent.
151
+ */
152
+ fieldsInZone(zone: string, epochMs: number): ZonedFields;
153
+ /**
154
+ * The wall-clock time in a named IANA zone, `1:00 AM`, in the `en-US` style
155
+ * the timezone forms answer in. Throws the runtime's `RangeError` for a
156
+ * zone it does not know or an instant it cannot represent.
157
+ */
158
+ formatTimeInZone(zone: string, epochMs: number): string;
159
+ /**
160
+ * The calendar date in a named IANA zone, `July 31, 2026`, in the `en-US`
161
+ * style the timezone forms answer in. Throws the runtime's `RangeError` for
162
+ * a zone it does not know or an instant it cannot represent.
163
+ */
164
+ formatDateInZone(zone: string, epochMs: number): string;
165
+ /**
166
+ * The zone this backend's "local" means, when it can name one.
167
+ *
168
+ * Optional, and deliberately so: the interface's own contract says a new
169
+ * REQUIRED method is a major, and every backend written against the shipped
170
+ * shape has to keep compiling. A backend that reads the host process's zone
171
+ * (the default {@link DateCalendar}) leaves it undefined rather than
172
+ * reporting a zone it does not itself compute in; one built for a named zone
173
+ * (`dateCalendarInZone`, the `Temporal` backend) returns that IANA name.
174
+ *
175
+ * A caller that needs "which zone is local here" and gets `undefined` should
176
+ * fall back to whatever it meant by local before, never guess a name.
177
+ */
178
+ zone?(): string;
179
+ }
180
+
181
+ export type { CalendarBackend as C, ZonedFields as Z, CalendarFields as a };
@@ -0,0 +1,181 @@
1
+ /**
2
+ * The calendar the engine computes dates with, behind one interface.
3
+ *
4
+ * Every date the engine holds is an instant: epoch milliseconds in a
5
+ * `Datetime` value, with no zone attached. Every date *question* the engine
6
+ * answers is a calendar question about that instant: which day it falls on,
7
+ * what the same wall-clock time a month later is, whether it is a Saturday,
8
+ * how it is written out. Answering those needs a time zone and a set of
9
+ * calendar rules, and until this interface existed the answer was always the
10
+ * JavaScript `Date` object read in the host process's own zone, scattered
11
+ * across some twenty files.
12
+ *
13
+ * A backend gathers those questions into one place so that a different
14
+ * implementation can answer them. Two ship with the engine. {@link DateCalendar}
15
+ * is the same `Date` code moved behind these methods and is the default, so
16
+ * nothing observable changes for a host that configures nothing. The
17
+ * `Temporal` backend (`solve-engine/temporal`) answers the same questions
18
+ * through a `Temporal` implementation the host hands it, native or polyfilled,
19
+ * and carries a time zone of its own rather than the process's; the engine
20
+ * never imports a polyfill.
21
+ *
22
+ * The contract is deliberately narrow. Methods take and return plain numbers
23
+ * and strings, never a `Date` or a `Temporal` object, so a `Datetime` value's
24
+ * payload stays a number and no worker message, snapshot or arena entry
25
+ * changes shape. Arithmetic whose answer does not depend on a zone (a day
26
+ * number, the days in a month, the ISO week) lives beside the backend in
27
+ * `calendar/Gregorian.ts` rather than behind it, because sharing one
28
+ * implementation is what keeps two backends from disagreeing on it.
29
+ *
30
+ * The shape is public and settled by the two backends that implement it. A
31
+ * host may implement the interface directly; a change to it follows the
32
+ * package's semantic versioning, so a new required method is a major.
33
+ *
34
+ * @module CalendarBackend
35
+ */
36
+ /**
37
+ * The calendar fields of one instant, read in the backend's zone.
38
+ *
39
+ * `month0` counts from zero (January is 0) and `weekday` from Sunday (0) to
40
+ * Saturday (6), matching `Date` at every internal boundary so a backend cannot
41
+ * be off by one against the code that reads it. Every field is `NaN` for an
42
+ * instant the backend cannot represent.
43
+ */
44
+ interface CalendarFields {
45
+ readonly year: number;
46
+ /** Zero-based month: 0 is January, 11 is December. */
47
+ readonly month0: number;
48
+ /** Day of the month, from 1. */
49
+ readonly day: number;
50
+ /** Day of the week: 0 is Sunday, 6 is Saturday. */
51
+ readonly weekday: number;
52
+ readonly hour: number;
53
+ readonly minute: number;
54
+ readonly second: number;
55
+ readonly millisecond: number;
56
+ }
57
+ /**
58
+ * The calendar fields a named time zone shows for an instant: the date and
59
+ * the wall-clock time, with the same zero-based month as {@link CalendarFields}.
60
+ * Sub-second precision is never needed for a zone conversion, so there is no
61
+ * millisecond field.
62
+ */
63
+ interface ZonedFields {
64
+ readonly year: number;
65
+ /** Zero-based month: 0 is January, 11 is December. */
66
+ readonly month0: number;
67
+ /** Day of the month, from 1. */
68
+ readonly day: number;
69
+ readonly hour: number;
70
+ readonly minute: number;
71
+ readonly second: number;
72
+ }
73
+ /**
74
+ * The calendar computations the engine performs, as one replaceable unit.
75
+ *
76
+ * "Local" throughout means the backend's own zone: the host process's zone for
77
+ * the `Date` backend, the configured zone for the `Temporal` one. A local
78
+ * operation that cannot be represented (an instant past the range the backend
79
+ * supports, a field that is not finite) answers `NaN`, never throws; the
80
+ * caller decides what an unrepresentable date means for its form.
81
+ *
82
+ * The four named-zone methods are the exception, and the contract is stated on
83
+ * each: a zone name the runtime does not know throws its `RangeError`, as
84
+ * `Intl` and `Temporal` both do, because a zone reaches the backend only from
85
+ * the engine's own zone registry and an unknown one is a data fault the caller
86
+ * should see rather than a `NaN` to display. Callers hand those methods a
87
+ * finite instant (`now()`, or a literal already checked).
88
+ */
89
+ interface CalendarBackend {
90
+ /** The current instant, in epoch milliseconds. Read at evaluation time, never baked into bytecode. */
91
+ now(): number;
92
+ /** The local calendar fields of an instant, `weekday` included. See {@link CalendarFields}. */
93
+ fields(epochMs: number): CalendarFields;
94
+ /**
95
+ * Local midnight on a calendar date, in epoch milliseconds.
96
+ *
97
+ * Fields overflow the way `Date`'s do (month 12 is January of the next
98
+ * year, day 0 the last day of the month before), which is what a caller
99
+ * checking for a rolled-over literal relies on: build the date, read its
100
+ * fields back, and a 30 February shows up as 1 or 2 March.
101
+ */
102
+ localMidnight(year: number, month0: number, day: number): number;
103
+ /**
104
+ * A wall-clock time on a calendar date, given as minutes past local
105
+ * midnight, in epoch milliseconds.
106
+ *
107
+ * The minutes name a clock reading, not an elapsed span: 540 minutes is
108
+ * 09:00 on that date even on a day with a daylight-saving transition,
109
+ * where 540 minutes of elapsed time from midnight would land at 10:00 or
110
+ * 08:00.
111
+ */
112
+ localWallClock(year: number, month0: number, day: number, minutesPastMidnight: number): number;
113
+ /**
114
+ * Move an instant by whole calendar days, holding the local wall-clock
115
+ * time. A day that contains a daylight-saving transition is 23 or 25
116
+ * hours long, so this is a field step, not an addition of milliseconds.
117
+ */
118
+ addDays(epochMs: number, days: number): number;
119
+ /**
120
+ * Move an instant by whole calendar months, holding the local wall-clock
121
+ * time and clamping the day to the length of the month landed in: 31
122
+ * January plus a month is 28 February, or 29 in a leap year, never 3 March.
123
+ */
124
+ addMonths(epochMs: number, months: number): number;
125
+ /** The local zone's offset from UTC at an instant, in minutes, positive when ahead of UTC. */
126
+ utcOffsetMinutes(epochMs: number): number;
127
+ /**
128
+ * Parse an ISO 8601 date or date-time string to epoch milliseconds, or
129
+ * `NaN` when it names no instant.
130
+ *
131
+ * A date-only string (`2019-04-01`) is UTC midnight; a date-time with no
132
+ * offset and no `Z` is local time. Both readings are the ECMAScript ones,
133
+ * and every backend reproduces them so the two spellings of a literal keep
134
+ * meaning the same instant whichever backend is in use.
135
+ */
136
+ parseIso8601(text: string): number;
137
+ /** The spelled-out local date in a locale, `Tuesday, March 10, 2026` in `en`. */
138
+ formatLongDate(epochMs: number, locale: string): string;
139
+ /** The local time of day in a locale, `9:30:00 AM` in `en`. */
140
+ formatTimeOfDay(epochMs: number, locale: string): string;
141
+ /**
142
+ * A named IANA zone's offset from UTC at an instant, in minutes, positive
143
+ * when ahead of UTC. Throws the runtime's `RangeError` for a zone it does
144
+ * not know or an instant it cannot represent.
145
+ */
146
+ zoneOffsetMinutes(zone: string, epochMs: number): number;
147
+ /**
148
+ * The calendar date and wall-clock time a named IANA zone shows for an
149
+ * instant. Throws the runtime's `RangeError` for a zone it does not know or
150
+ * an instant it cannot represent.
151
+ */
152
+ fieldsInZone(zone: string, epochMs: number): ZonedFields;
153
+ /**
154
+ * The wall-clock time in a named IANA zone, `1:00 AM`, in the `en-US` style
155
+ * the timezone forms answer in. Throws the runtime's `RangeError` for a
156
+ * zone it does not know or an instant it cannot represent.
157
+ */
158
+ formatTimeInZone(zone: string, epochMs: number): string;
159
+ /**
160
+ * The calendar date in a named IANA zone, `July 31, 2026`, in the `en-US`
161
+ * style the timezone forms answer in. Throws the runtime's `RangeError` for
162
+ * a zone it does not know or an instant it cannot represent.
163
+ */
164
+ formatDateInZone(zone: string, epochMs: number): string;
165
+ /**
166
+ * The zone this backend's "local" means, when it can name one.
167
+ *
168
+ * Optional, and deliberately so: the interface's own contract says a new
169
+ * REQUIRED method is a major, and every backend written against the shipped
170
+ * shape has to keep compiling. A backend that reads the host process's zone
171
+ * (the default {@link DateCalendar}) leaves it undefined rather than
172
+ * reporting a zone it does not itself compute in; one built for a named zone
173
+ * (`dateCalendarInZone`, the `Temporal` backend) returns that IANA name.
174
+ *
175
+ * A caller that needs "which zone is local here" and gets `undefined` should
176
+ * fall back to whatever it meant by local before, never guess a name.
177
+ */
178
+ zone?(): string;
179
+ }
180
+
181
+ export type { CalendarBackend as C, ZonedFields as Z, CalendarFields as a };
@@ -58,11 +58,25 @@ type HolidayCalendar = HolidayPredicate | Iterable<string | number | Date>;
58
58
  * a host can match its readers' locale. `'MDY'` is what lets a US reader's
59
59
  * `12/25/2023` parse, which `'auto'` refuses because the slash defaults to
60
60
  * day-first.
61
+ * - `'locale'`: the order the reader's own machine writes dates in, asked of
62
+ * `Intl` once per engine (see `calendar/HostLocale.ts`). Where that cannot
63
+ * be answered, the engine reads dates exactly as `'auto'` does and reports
64
+ * the fact through `ExpressionEngine.getDateReading()`, rather than guessing.
65
+ * A host that is not the reader (a server rendering someone else's document)
66
+ * names the reader instead, through {@link DateConfig.inputLocale}.
61
67
  *
62
- * Only the all-numeric literals are affected. A spelled-out month (`March 9,
63
- * 2024`) is never ambiguous, and an ISO timestamp is always read as ISO.
68
+ * Only ambiguous literals are affected. A spelled-out month (`March 9, 2024`)
69
+ * is never ambiguous; nor is a hyphen literal with a four-digit leading group
70
+ * (`2024-03-09`), which has no reading but year-month-day and is read as ISO
71
+ * under every order, timestamp or not.
64
72
  */
65
- type DateInputOrder = 'auto' | 'DMY' | 'MDY' | 'YMD';
73
+ type DateInputOrder = 'auto' | 'locale' | 'DMY' | 'MDY' | 'YMD';
74
+ /**
75
+ * What a date-shaped numeric run the configured order cannot read does: report
76
+ * the problem, or fall through to the arithmetic it is spelled like. See
77
+ * {@link DateConfig.onAmbiguous}.
78
+ */
79
+ type DateAmbiguity = 'refuse' | 'arithmetic';
66
80
  /** Date-related engine configuration: offset limits, input order, holidays. */
67
81
  interface DateConfig {
68
82
  /**
@@ -70,6 +84,51 @@ interface DateConfig {
70
84
  * `'auto'` (by separator, the historic behaviour). See {@link DateInputOrder}.
71
85
  */
72
86
  readonly inputOrder: DateInputOrder;
87
+ /**
88
+ * The BCP-47 tag `'locale'` reads the order from, `"en-US"` or `"de-DE"`.
89
+ * Unset, the host machine is asked.
90
+ *
91
+ * Read ONLY when {@link inputOrder} is `'locale'`. Setting it beside any
92
+ * other order changes no result: a field that quietly switched inference on
93
+ * would make the predictable mistake a wrong reading rather than no change.
94
+ * Its shape is checked wherever it is set, though, and a tag `Intl` refuses
95
+ * (`"en_US"`, with an underscore) raises `DATE_INPUT_LOCALE_INVALID` at
96
+ * construction, because a locale silently ignored is a date order silently
97
+ * wrong.
98
+ *
99
+ * Deliberately separate from the engine's `locale` option, which is a
100
+ * language (`'en' | 'de' | 'fr'`) and carries no region. Day/month order is a
101
+ * region question: a bare `en` probes as month-first while a UK machine
102
+ * resolves to `en-GB` and probes as day-first, so wiring the two together
103
+ * would flip every existing British engine to month-first.
104
+ */
105
+ readonly inputLocale?: string;
106
+ /**
107
+ * What a date-shaped numeric run the resolved order cannot read does.
108
+ * Defaults to `'refuse'`.
109
+ *
110
+ * - `'refuse'`: the line reports a structured Error value naming the
111
+ * problem, DATE_ORDER_MISMATCH when another order would have read it and
112
+ * DATE_NOT_A_CALENDAR_DAY when no order names a real day. `12/25/2026` on
113
+ * a day-first engine says there is no month 25, rather than answering
114
+ * 0.00.
115
+ * - `'arithmetic'`: the run falls through to the division or subtraction it
116
+ * is spelled like, which is what every version before this one did.
117
+ * `12/25/2026` is 0.00 again, and `2026-02-29` is 1,995.
118
+ *
119
+ * The refusal is scoped to runs nobody writes as arithmetic: a two-step
120
+ * chain ending in a four-digit denominator (`03/04/2026` as division is
121
+ * 0.0004), and an ISO-shaped hyphen run. A four-digit LEADING group is
122
+ * ordinary arithmetic (`1000/10/5` is 20, `1024/8/2` is 64) and is never
123
+ * refused, and neither is a run whose groups are all one or two digits
124
+ * (`12/13/14` stays 0.07), because a two-digit year is too weak a signal to
125
+ * hang a refusal on.
126
+ *
127
+ * The one refusal this setting does not restore is the dot form
128
+ * (`25.12.2026` under a month-first order): its only other outcome is a
129
+ * parse error, and an error is not an answer.
130
+ */
131
+ readonly onAmbiguous: DateAmbiguity;
73
132
  /**
74
133
  * How far forward a date offset whose COST grows with the offset may reach,
75
134
  * in years. Enforced by `vm/VM.ts`'s `addBusinessDays()`.
@@ -439,4 +498,4 @@ interface ValidationResult {
439
498
  warnings?: string[];
440
499
  }
441
500
 
442
- export { ConfigManager as C, DEFAULT_CONFIG as D, type EngineConfigOverride as E, type HolidayCalendar as H, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type EngineConfig as a, type DateConfig as b, type DiagnosticConfig as c, type HolidayPredicate as d, type ValidationConfig as e, type ValidationResult as f };
501
+ export { ConfigManager as C, type DateAmbiguity as D, type EngineConfigOverride as E, type HolidayCalendar as H, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type EngineConfig as a, DEFAULT_CONFIG as b, type DateConfig as c, type DiagnosticConfig as d, type HolidayPredicate as e, type ValidationConfig as f, type ValidationResult as g };
@@ -58,11 +58,25 @@ type HolidayCalendar = HolidayPredicate | Iterable<string | number | Date>;
58
58
  * a host can match its readers' locale. `'MDY'` is what lets a US reader's
59
59
  * `12/25/2023` parse, which `'auto'` refuses because the slash defaults to
60
60
  * day-first.
61
+ * - `'locale'`: the order the reader's own machine writes dates in, asked of
62
+ * `Intl` once per engine (see `calendar/HostLocale.ts`). Where that cannot
63
+ * be answered, the engine reads dates exactly as `'auto'` does and reports
64
+ * the fact through `ExpressionEngine.getDateReading()`, rather than guessing.
65
+ * A host that is not the reader (a server rendering someone else's document)
66
+ * names the reader instead, through {@link DateConfig.inputLocale}.
61
67
  *
62
- * Only the all-numeric literals are affected. A spelled-out month (`March 9,
63
- * 2024`) is never ambiguous, and an ISO timestamp is always read as ISO.
68
+ * Only ambiguous literals are affected. A spelled-out month (`March 9, 2024`)
69
+ * is never ambiguous; nor is a hyphen literal with a four-digit leading group
70
+ * (`2024-03-09`), which has no reading but year-month-day and is read as ISO
71
+ * under every order, timestamp or not.
64
72
  */
65
- type DateInputOrder = 'auto' | 'DMY' | 'MDY' | 'YMD';
73
+ type DateInputOrder = 'auto' | 'locale' | 'DMY' | 'MDY' | 'YMD';
74
+ /**
75
+ * What a date-shaped numeric run the configured order cannot read does: report
76
+ * the problem, or fall through to the arithmetic it is spelled like. See
77
+ * {@link DateConfig.onAmbiguous}.
78
+ */
79
+ type DateAmbiguity = 'refuse' | 'arithmetic';
66
80
  /** Date-related engine configuration: offset limits, input order, holidays. */
67
81
  interface DateConfig {
68
82
  /**
@@ -70,6 +84,51 @@ interface DateConfig {
70
84
  * `'auto'` (by separator, the historic behaviour). See {@link DateInputOrder}.
71
85
  */
72
86
  readonly inputOrder: DateInputOrder;
87
+ /**
88
+ * The BCP-47 tag `'locale'` reads the order from, `"en-US"` or `"de-DE"`.
89
+ * Unset, the host machine is asked.
90
+ *
91
+ * Read ONLY when {@link inputOrder} is `'locale'`. Setting it beside any
92
+ * other order changes no result: a field that quietly switched inference on
93
+ * would make the predictable mistake a wrong reading rather than no change.
94
+ * Its shape is checked wherever it is set, though, and a tag `Intl` refuses
95
+ * (`"en_US"`, with an underscore) raises `DATE_INPUT_LOCALE_INVALID` at
96
+ * construction, because a locale silently ignored is a date order silently
97
+ * wrong.
98
+ *
99
+ * Deliberately separate from the engine's `locale` option, which is a
100
+ * language (`'en' | 'de' | 'fr'`) and carries no region. Day/month order is a
101
+ * region question: a bare `en` probes as month-first while a UK machine
102
+ * resolves to `en-GB` and probes as day-first, so wiring the two together
103
+ * would flip every existing British engine to month-first.
104
+ */
105
+ readonly inputLocale?: string;
106
+ /**
107
+ * What a date-shaped numeric run the resolved order cannot read does.
108
+ * Defaults to `'refuse'`.
109
+ *
110
+ * - `'refuse'`: the line reports a structured Error value naming the
111
+ * problem, DATE_ORDER_MISMATCH when another order would have read it and
112
+ * DATE_NOT_A_CALENDAR_DAY when no order names a real day. `12/25/2026` on
113
+ * a day-first engine says there is no month 25, rather than answering
114
+ * 0.00.
115
+ * - `'arithmetic'`: the run falls through to the division or subtraction it
116
+ * is spelled like, which is what every version before this one did.
117
+ * `12/25/2026` is 0.00 again, and `2026-02-29` is 1,995.
118
+ *
119
+ * The refusal is scoped to runs nobody writes as arithmetic: a two-step
120
+ * chain ending in a four-digit denominator (`03/04/2026` as division is
121
+ * 0.0004), and an ISO-shaped hyphen run. A four-digit LEADING group is
122
+ * ordinary arithmetic (`1000/10/5` is 20, `1024/8/2` is 64) and is never
123
+ * refused, and neither is a run whose groups are all one or two digits
124
+ * (`12/13/14` stays 0.07), because a two-digit year is too weak a signal to
125
+ * hang a refusal on.
126
+ *
127
+ * The one refusal this setting does not restore is the dot form
128
+ * (`25.12.2026` under a month-first order): its only other outcome is a
129
+ * parse error, and an error is not an answer.
130
+ */
131
+ readonly onAmbiguous: DateAmbiguity;
73
132
  /**
74
133
  * How far forward a date offset whose COST grows with the offset may reach,
75
134
  * in years. Enforced by `vm/VM.ts`'s `addBusinessDays()`.
@@ -439,4 +498,4 @@ interface ValidationResult {
439
498
  warnings?: string[];
440
499
  }
441
500
 
442
- export { ConfigManager as C, DEFAULT_CONFIG as D, type EngineConfigOverride as E, type HolidayCalendar as H, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type EngineConfig as a, type DateConfig as b, type DiagnosticConfig as c, type HolidayPredicate as d, type ValidationConfig as e, type ValidationResult as f };
501
+ export { ConfigManager as C, type DateAmbiguity as D, type EngineConfigOverride as E, type HolidayCalendar as H, type PerformanceConfig as P, type VMConfig as V, type WorkerConfig as W, type EngineConfig as a, DEFAULT_CONFIG as b, type DateConfig as c, type DiagnosticConfig as d, type HolidayPredicate as e, type ValidationConfig as f, type ValidationResult as g };
@@ -0,0 +1,90 @@
1
+ import { C as CalendarBackend, a as CalendarFields, Z as ZonedFields } from './CalendarBackend-MdS3Bb4P.js';
2
+
3
+ /**
4
+ * The default {@link CalendarBackend}: the JavaScript `Date` object, read in
5
+ * the host process's time zone, with `Intl.DateTimeFormat` for named zones.
6
+ *
7
+ * This is the calendar code the engine has always run, moved behind the
8
+ * interface method by method rather than rewritten, so a host that configures
9
+ * nothing sees the same instants and the same strings it did before the
10
+ * backend existed. Where `Date` has a quirk (a two-digit year in a
11
+ * constructor maps to the 1900s, an out-of-range instant answers `NaN`), the
12
+ * quirk is kept here deliberately: the point of this backend is to be the
13
+ * behaviour the `Temporal` backend is measured against, not to improve on it.
14
+ *
15
+ * It stays the default because it is the one calendar every supported runtime
16
+ * has. `Temporal` ships unflagged in Node 26 and in current Chrome, Firefox
17
+ * and Deno, but not in Safari or in the Node 22 and 24 the engine supports,
18
+ * and the smallest polyfill adds about twenty kilobytes gzipped to a bundle
19
+ * that a host doing plain arithmetic never needs. A host that wants
20
+ * `Temporal` opts in through the engine's `calendar` option with the backend
21
+ * from `solve-engine/temporal`, and pays for it only then.
22
+ */
23
+ declare class DateCalendar implements CalendarBackend {
24
+ now(): number;
25
+ fields(epochMs: number): CalendarFields;
26
+ localMidnight(year: number, month0: number, day: number): number;
27
+ localWallClock(year: number, month0: number, day: number, minutesPastMidnight: number): number;
28
+ addDays(epochMs: number, days: number): number;
29
+ addMonths(epochMs: number, months: number): number;
30
+ utcOffsetMinutes(epochMs: number): number;
31
+ parseIso8601(text: string): number;
32
+ formatLongDate(epochMs: number, locale: string): string;
33
+ formatTimeOfDay(epochMs: number, locale: string): string;
34
+ zoneOffsetMinutes(zone: string, epochMs: number): number;
35
+ fieldsInZone(zone: string, epochMs: number): ZonedFields;
36
+ formatTimeInZone(zone: string, epochMs: number): string;
37
+ formatDateInZone(zone: string, epochMs: number): string;
38
+ }
39
+ /**
40
+ * The one `Date` backend, shared by every engine that configures no other.
41
+ *
42
+ * Stateless, so sharing is safe: it holds no zone of its own and reads the
43
+ * process's. It is also what the sites with no engine in hand use (the
44
+ * normaliser rules that fuse a literal, `days in <period>`, the stocks and
45
+ * historical-currency date phrases, and `formatValue`), which is why an
46
+ * engine's own backend is the default here rather than a second copy.
47
+ */
48
+ declare const DATE_CALENDAR: CalendarBackend;
49
+ /**
50
+ * The backend a plugin function or converter should compute with: the one
51
+ * on its execution context, or the `Date` backend when the handler was
52
+ * called with no context (a direct call from a test, or an `as` converter
53
+ * invoked outside the VM).
54
+ *
55
+ * @param context - The execution context the handler received, if any.
56
+ * @returns The engine's backend when the context carries one, else {@link DATE_CALENDAR}.
57
+ */
58
+ declare function calendarOf(context?: {
59
+ readonly calendar?: CalendarBackend;
60
+ }): CalendarBackend;
61
+ /**
62
+ * A `Date` backend that computes in a named time zone rather than the host
63
+ * process's.
64
+ *
65
+ * This is how a host pins the zone the engine reads dates in, and it is the
66
+ * only knob for it: the zone belongs to the calendar backend, which already
67
+ * owns what "local" means, so there is deliberately no `date.zone` config
68
+ * field to drift against it.
69
+ *
70
+ * ```ts
71
+ * import { createEngine, dateCalendarInZone } from "solve-engine";
72
+ * const engine = createEngine({ calendar: dateCalendarInZone("Asia/Tokyo") });
73
+ * ```
74
+ *
75
+ * It ships on the `Date` backend on purpose. `Temporal` is undefined on Node
76
+ * 24 and in Safari, so "pass a `Temporal` backend" would put the zone out of
77
+ * reach for most hosts today; `Temporal` stays an accuracy upgrade for the
78
+ * ambiguous wall clocks around a daylight-saving transition, never a
79
+ * prerequisite for naming a zone at all.
80
+ *
81
+ * @param zone - An IANA zone name, e.g. `"Asia/Tokyo"`.
82
+ * @returns A backend whose local zone is that one.
83
+ * @throws A `DATE_ZONE_UNKNOWN` config error when this runtime's `Intl` does
84
+ * not know the zone. Refused here rather than per line, because a backend
85
+ * that cannot compute in the zone it was asked for must not quietly answer
86
+ * in another one.
87
+ */
88
+ declare function dateCalendarInZone(zone: string): CalendarBackend;
89
+
90
+ export { DATE_CALENDAR as D, DateCalendar as a, calendarOf as c, dateCalendarInZone as d };