@classytic/stage 0.3.0 → 0.4.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 (431) hide show
  1. package/dist/_virtual/_rolldown/runtime.mjs +18 -0
  2. package/dist/atomic/aufbau.d.mts +144 -0
  3. package/dist/atomic/aufbau.mjs +384 -0
  4. package/dist/atomic/elements.d.mts +67 -0
  5. package/dist/atomic/elements.mjs +785 -0
  6. package/dist/atomic/emission.d.mts +112 -0
  7. package/dist/atomic/emission.mjs +179 -0
  8. package/dist/atomic/index.d.mts +8 -0
  9. package/dist/atomic/index.mjs +9 -0
  10. package/dist/atomic/periodic.d.mts +82 -0
  11. package/dist/atomic/periodic.mjs +231 -0
  12. package/dist/atomic/properties.d.mts +100 -0
  13. package/dist/atomic/properties.mjs +574 -0
  14. package/dist/atomic/shells.d.mts +137 -0
  15. package/dist/atomic/shells.mjs +170 -0
  16. package/dist/atomic/trends.d.mts +148 -0
  17. package/dist/atomic/trends.mjs +225 -0
  18. package/dist/chem/chromatography.d.mts +66 -0
  19. package/dist/chem/chromatography.mjs +63 -0
  20. package/dist/chem/complex.d.mts +114 -0
  21. package/dist/chem/complex.mjs +234 -0
  22. package/dist/chem/cycle.d.mts +75 -0
  23. package/dist/chem/cycle.mjs +145 -0
  24. package/dist/chem/equation.d.mts +86 -0
  25. package/dist/chem/equation.mjs +168 -0
  26. package/dist/chem/formula.d.mts +90 -0
  27. package/dist/chem/formula.mjs +201 -0
  28. package/dist/chem/functional-groups.d.mts +31 -0
  29. package/dist/chem/functional-groups.mjs +187 -0
  30. package/dist/chem/hazard.d.mts +94 -0
  31. package/dist/chem/hazard.mjs +329 -0
  32. package/dist/chem/index.d.mts +34 -33
  33. package/dist/chem/index.mjs +34 -28
  34. package/dist/chem/ionic.d.mts +98 -0
  35. package/dist/chem/ionic.mjs +156 -0
  36. package/dist/chem/layout.d.mts +46 -0
  37. package/dist/chem/layout.mjs +342 -0
  38. package/dist/chem/lewis.d.mts +79 -0
  39. package/dist/chem/lewis.mjs +163 -0
  40. package/dist/chem/molecular-orbital.d.mts +114 -0
  41. package/dist/chem/molecular-orbital.mjs +201 -0
  42. package/dist/chem/molecule.d.mts +154 -0
  43. package/dist/chem/molecule.mjs +282 -0
  44. package/dist/chem/nmr.d.mts +153 -0
  45. package/dist/chem/nmr.mjs +165 -0
  46. package/dist/chem/polymer.d.mts +65 -0
  47. package/dist/chem/polymer.mjs +179 -0
  48. package/dist/chem/redox.d.mts +138 -0
  49. package/dist/chem/redox.mjs +328 -0
  50. package/dist/chem/relations.d.mts +183 -0
  51. package/dist/chem/relations.mjs +299 -0
  52. package/dist/chem/skeleton.d.mts +51 -0
  53. package/dist/chem/skeleton.mjs +186 -0
  54. package/dist/chem/solution.d.mts +116 -0
  55. package/dist/chem/solution.mjs +186 -0
  56. package/dist/chem/species.d.mts +47 -0
  57. package/dist/chem/species.mjs +128 -0
  58. package/dist/chem/stereo.d.mts +108 -0
  59. package/dist/chem/stereo.mjs +286 -0
  60. package/dist/chem/stoichiometry.d.mts +95 -0
  61. package/dist/chem/stoichiometry.mjs +145 -0
  62. package/dist/chem/synthesis.d.mts +113 -0
  63. package/dist/chem/synthesis.mjs +281 -0
  64. package/dist/chem/vsepr.d.mts +80 -0
  65. package/dist/chem/vsepr.mjs +247 -0
  66. package/dist/circuit/ac.d.mts +163 -0
  67. package/dist/circuit/ac.mjs +452 -0
  68. package/dist/circuit/dc.d.mts +92 -0
  69. package/dist/circuit/dc.mjs +333 -0
  70. package/dist/circuit/index.d.mts +5 -92
  71. package/dist/circuit/index.mjs +5 -332
  72. package/dist/circuit/network.d.mts +99 -0
  73. package/dist/circuit/network.mjs +440 -0
  74. package/dist/circuit/topology.d.mts +102 -0
  75. package/dist/circuit/topology.mjs +143 -0
  76. package/dist/colour/absorption.d.mts +79 -0
  77. package/dist/colour/absorption.mjs +137 -0
  78. package/dist/colour/index.d.mts +6 -0
  79. package/dist/colour/index.mjs +7 -0
  80. package/dist/colour/name.d.mts +14 -0
  81. package/dist/colour/name.mjs +76 -0
  82. package/dist/colour/observer.d.mts +31 -0
  83. package/dist/colour/observer.mjs +46 -0
  84. package/dist/colour/spectrum.d.mts +61 -0
  85. package/dist/colour/spectrum.mjs +108 -0
  86. package/dist/colour/srgb.d.mts +49 -0
  87. package/dist/colour/srgb.mjs +108 -0
  88. package/dist/core/constants.d.mts +138 -0
  89. package/dist/core/constants.mjs +139 -0
  90. package/dist/core/index.d.mts +3 -1
  91. package/dist/core/index.mjs +3 -1
  92. package/dist/core/vec3.d.mts +94 -0
  93. package/dist/core/vec3.mjs +123 -0
  94. package/dist/core/worked.d.mts +35 -0
  95. package/dist/core/worked.mjs +44 -0
  96. package/dist/electro/cell.d.mts +102 -0
  97. package/dist/electro/cell.mjs +170 -0
  98. package/dist/electro/conductivity.d.mts +157 -0
  99. package/dist/electro/conductivity.mjs +156 -0
  100. package/dist/electro/couples.d.mts +114 -0
  101. package/dist/electro/couples.mjs +334 -0
  102. package/dist/electro/electrolysis.d.mts +96 -0
  103. package/dist/electro/electrolysis.mjs +274 -0
  104. package/dist/electro/faraday.d.mts +150 -0
  105. package/dist/electro/faraday.mjs +118 -0
  106. package/dist/electro/index.d.mts +6 -0
  107. package/dist/electro/index.mjs +7 -0
  108. package/dist/finance/accounting/adjustments.d.mts +17 -0
  109. package/dist/finance/accounting/adjustments.mjs +202 -0
  110. package/dist/finance/accounting/analysis.d.mts +8 -0
  111. package/dist/finance/accounting/analysis.mjs +205 -0
  112. package/dist/finance/accounting/clubs.d.mts +21 -0
  113. package/dist/finance/accounting/clubs.mjs +217 -0
  114. package/dist/finance/accounting/company-statements.d.mts +7 -0
  115. package/dist/finance/accounting/company-statements.mjs +150 -0
  116. package/dist/finance/accounting/harness.d.mts +7 -0
  117. package/dist/finance/accounting/harness.mjs +45 -0
  118. package/dist/finance/accounting/index.d.mts +18 -0
  119. package/dist/finance/accounting/index.mjs +18 -0
  120. package/dist/finance/accounting/journalize.d.mts +16 -0
  121. package/dist/finance/accounting/journalize.mjs +128 -0
  122. package/dist/finance/accounting/manufacturing.d.mts +8 -0
  123. package/dist/finance/accounting/manufacturing.mjs +236 -0
  124. package/dist/finance/accounting/partnership.d.mts +7 -0
  125. package/dist/finance/accounting/partnership.mjs +152 -0
  126. package/dist/finance/accounting/period-case.d.mts +6 -0
  127. package/dist/finance/accounting/period-case.mjs +71 -0
  128. package/dist/finance/accounting/post.d.mts +9 -0
  129. package/dist/finance/accounting/post.mjs +84 -0
  130. package/dist/finance/accounting/precision.d.mts +9 -0
  131. package/dist/finance/accounting/precision.mjs +15 -0
  132. package/dist/finance/accounting/rules.d.mts +21 -0
  133. package/dist/finance/accounting/rules.mjs +37 -0
  134. package/dist/finance/accounting/solve.d.mts +28 -0
  135. package/dist/finance/accounting/solve.mjs +92 -0
  136. package/dist/finance/accounting/statements.d.mts +7 -0
  137. package/dist/finance/accounting/statements.mjs +142 -0
  138. package/dist/finance/accounting/types.d.mts +649 -0
  139. package/dist/finance/accounting/validate.d.mts +7 -0
  140. package/dist/finance/accounting/validate.mjs +67 -0
  141. package/dist/finance/accounting/verification.d.mts +24 -0
  142. package/dist/finance/accounting/verification.mjs +386 -0
  143. package/dist/finance/bizsim.d.mts +21 -39
  144. package/dist/finance/bizsim.mjs +276 -97
  145. package/dist/finance/index.d.mts +20 -43
  146. package/dist/finance/index.mjs +19 -77
  147. package/dist/finance/investment-math.d.mts +7 -0
  148. package/dist/finance/investment-math.mjs +18 -0
  149. package/dist/finance/management-accounting/budgeting.d.mts +7 -0
  150. package/dist/finance/management-accounting/budgeting.mjs +189 -0
  151. package/dist/finance/management-accounting/cash-budget.d.mts +7 -0
  152. package/dist/finance/management-accounting/cash-budget.mjs +154 -0
  153. package/dist/finance/management-accounting/costing.d.mts +8 -0
  154. package/dist/finance/management-accounting/costing.mjs +175 -0
  155. package/dist/finance/management-accounting/decisions.d.mts +8 -0
  156. package/dist/finance/management-accounting/decisions.mjs +164 -0
  157. package/dist/finance/management-accounting/index.d.mts +13 -0
  158. package/dist/finance/management-accounting/index.mjs +13 -0
  159. package/dist/finance/management-accounting/integrated-budget.d.mts +8 -0
  160. package/dist/finance/management-accounting/integrated-budget.mjs +67 -0
  161. package/dist/finance/management-accounting/inventory-costing.d.mts +7 -0
  162. package/dist/finance/management-accounting/inventory-costing.mjs +173 -0
  163. package/dist/finance/management-accounting/investment-appraisal.d.mts +7 -0
  164. package/dist/finance/management-accounting/investment-appraisal.mjs +148 -0
  165. package/dist/finance/management-accounting/management-case.d.mts +8 -0
  166. package/dist/finance/management-accounting/management-case.mjs +91 -0
  167. package/dist/finance/management-accounting/master-budget.d.mts +7 -0
  168. package/dist/finance/management-accounting/master-budget.mjs +137 -0
  169. package/dist/finance/management-accounting/production-costing.d.mts +8 -0
  170. package/dist/finance/management-accounting/production-costing.mjs +214 -0
  171. package/dist/finance/management-accounting/types.d.mts +644 -0
  172. package/dist/finance/management-accounting/variances.d.mts +7 -0
  173. package/dist/finance/management-accounting/variances.mjs +150 -0
  174. package/dist/index.d.mts +6 -6
  175. package/dist/index.mjs +1 -1
  176. package/dist/math/analysis.d.mts +61 -0
  177. package/dist/math/analysis.mjs +187 -0
  178. package/dist/math/answer-check.d.mts +50 -0
  179. package/dist/math/answer-check.mjs +106 -0
  180. package/dist/math/calculus.d.mts +4 -9
  181. package/dist/math/calculus.mjs +216 -7
  182. package/dist/math/complex.d.mts +93 -0
  183. package/dist/math/complex.mjs +239 -0
  184. package/dist/math/expr.d.mts +23 -0
  185. package/dist/math/expr.mjs +36 -0
  186. package/dist/math/index.d.mts +8 -22
  187. package/dist/math/index.mjs +8 -37
  188. package/dist/math/latex.mjs +2 -1
  189. package/dist/math/parse.mjs +1 -1
  190. package/dist/math/poly.d.mts +55 -0
  191. package/dist/math/poly.mjs +273 -0
  192. package/dist/math/rearrange.d.mts +14 -0
  193. package/dist/math/rearrange.mjs +125 -0
  194. package/dist/math/solve.d.mts +21 -0
  195. package/dist/math/solve.mjs +75 -0
  196. package/dist/networking/addressing.d.mts +26 -0
  197. package/dist/networking/addressing.mjs +33 -0
  198. package/dist/networking/cloud/access.d.mts +36 -0
  199. package/dist/networking/cloud/access.mjs +95 -0
  200. package/dist/networking/cloud/containers.d.mts +43 -0
  201. package/dist/networking/cloud/containers.mjs +54 -0
  202. package/dist/networking/cloud/edge.d.mts +17 -0
  203. package/dist/networking/cloud/edge.mjs +31 -0
  204. package/dist/networking/cloud/failure-domains.d.mts +19 -0
  205. package/dist/networking/cloud/failure-domains.mjs +22 -0
  206. package/dist/networking/cloud/geo-routing.d.mts +22 -0
  207. package/dist/networking/cloud/geo-routing.mjs +64 -0
  208. package/dist/networking/cloud/index.d.mts +18 -0
  209. package/dist/networking/cloud/index.mjs +19 -0
  210. package/dist/networking/cloud/inference-reliability.d.mts +30 -0
  211. package/dist/networking/cloud/inference-reliability.mjs +76 -0
  212. package/dist/networking/cloud/inference.d.mts +118 -0
  213. package/dist/networking/cloud/inference.mjs +179 -0
  214. package/dist/networking/cloud/infrastructure.d.mts +45 -0
  215. package/dist/networking/cloud/infrastructure.mjs +96 -0
  216. package/dist/networking/cloud/observability.d.mts +24 -0
  217. package/dist/networking/cloud/observability.mjs +34 -0
  218. package/dist/networking/cloud/orchestration.d.mts +32 -0
  219. package/dist/networking/cloud/orchestration.mjs +38 -0
  220. package/dist/networking/cloud/recovery.d.mts +21 -0
  221. package/dist/networking/cloud/recovery.mjs +27 -0
  222. package/dist/networking/cloud/releases.d.mts +42 -0
  223. package/dist/networking/cloud/releases.mjs +135 -0
  224. package/dist/networking/cloud/scaling.d.mts +25 -0
  225. package/dist/networking/cloud/scaling.mjs +65 -0
  226. package/dist/networking/cloud/secrets.d.mts +39 -0
  227. package/dist/networking/cloud/secrets.mjs +68 -0
  228. package/dist/networking/cloud/server-deployment.d.mts +29 -0
  229. package/dist/networking/cloud/server-deployment.mjs +72 -0
  230. package/dist/networking/cloud/storage.d.mts +16 -0
  231. package/dist/networking/cloud/storage.mjs +58 -0
  232. package/dist/networking/cloud/vpc.d.mts +18 -0
  233. package/dist/networking/cloud/vpc.mjs +100 -0
  234. package/dist/networking/delivery.d.mts +34 -0
  235. package/dist/networking/delivery.mjs +52 -0
  236. package/dist/networking/index.d.mts +47 -0
  237. package/dist/networking/index.mjs +47 -0
  238. package/dist/networking/ipv6.d.mts +28 -0
  239. package/dist/networking/ipv6.mjs +17 -0
  240. package/dist/networking/journeys.d.mts +83 -0
  241. package/dist/networking/journeys.mjs +161 -0
  242. package/dist/networking/models/airtime.d.mts +87 -0
  243. package/dist/networking/models/airtime.mjs +130 -0
  244. package/dist/networking/models/cellular.d.mts +157 -0
  245. package/dist/networking/models/cellular.mjs +252 -0
  246. package/dist/networking/models/encapsulation.d.mts +98 -0
  247. package/dist/networking/models/encapsulation.mjs +132 -0
  248. package/dist/networking/models/handover.d.mts +116 -0
  249. package/dist/networking/models/handover.mjs +209 -0
  250. package/dist/networking/models/handshake.d.mts +90 -0
  251. package/dist/networking/models/handshake.mjs +122 -0
  252. package/dist/networking/models/index.d.mts +14 -0
  253. package/dist/networking/models/index.mjs +15 -0
  254. package/dist/networking/models/media.d.mts +82 -0
  255. package/dist/networking/models/media.mjs +188 -0
  256. package/dist/networking/models/satellite.d.mts +86 -0
  257. package/dist/networking/models/satellite.mjs +121 -0
  258. package/dist/networking/models/spectrum.d.mts +83 -0
  259. package/dist/networking/models/spectrum.mjs +235 -0
  260. package/dist/networking/models/switch.d.mts +80 -0
  261. package/dist/networking/models/switch.mjs +155 -0
  262. package/dist/networking/models/vlan.d.mts +62 -0
  263. package/dist/networking/models/vlan.mjs +100 -0
  264. package/dist/networking/models/vpn.d.mts +66 -0
  265. package/dist/networking/models/vpn.mjs +125 -0
  266. package/dist/networking/models/wifi-privacy.d.mts +82 -0
  267. package/dist/networking/models/wifi-privacy.mjs +130 -0
  268. package/dist/networking/models/wifi.d.mts +240 -0
  269. package/dist/networking/models/wifi.mjs +562 -0
  270. package/dist/networking/nat-traversal.d.mts +24 -0
  271. package/dist/networking/nat-traversal.mjs +38 -0
  272. package/dist/networking/protocols.d.mts +17 -0
  273. package/dist/networking/protocols.mjs +57 -0
  274. package/dist/networking/queue.d.mts +12 -0
  275. package/dist/networking/queue.mjs +18 -0
  276. package/dist/networking/route-learning.d.mts +23 -0
  277. package/dist/networking/route-learning.mjs +43 -0
  278. package/dist/networking/routing.d.mts +11 -0
  279. package/dist/networking/routing.mjs +25 -0
  280. package/dist/networking/signals.d.mts +26 -0
  281. package/dist/networking/signals.mjs +35 -0
  282. package/dist/networking/subnet.d.mts +49 -0
  283. package/dist/networking/subnet.mjs +89 -0
  284. package/dist/networking/tcp-reliability.d.mts +24 -0
  285. package/dist/networking/tcp-reliability.mjs +38 -0
  286. package/dist/networking/topology/contract.d.mts +123 -0
  287. package/dist/networking/topology/index.d.mts +4 -0
  288. package/dist/networking/topology/index.mjs +4 -0
  289. package/dist/networking/topology/presets.d.mts +7 -0
  290. package/dist/networking/topology/presets.mjs +302 -0
  291. package/dist/networking/topology/simulation.d.mts +8 -0
  292. package/dist/networking/topology/simulation.mjs +179 -0
  293. package/dist/networking/wireless.d.mts +11 -0
  294. package/dist/networking/wireless.mjs +17 -0
  295. package/dist/optics/imaging.d.mts +218 -0
  296. package/dist/optics/imaging.mjs +276 -0
  297. package/dist/optics/index.d.mts +7 -0
  298. package/dist/optics/index.mjs +8 -0
  299. package/dist/optics/laws.d.mts +70 -0
  300. package/dist/optics/laws.mjs +195 -0
  301. package/dist/optics/prism.d.mts +148 -0
  302. package/dist/optics/prism.mjs +197 -0
  303. package/dist/optics/refraction.d.mts +201 -0
  304. package/dist/optics/refraction.mjs +270 -0
  305. package/dist/optics/wave-optics.d.mts +171 -0
  306. package/dist/optics/wave-optics.mjs +259 -0
  307. package/dist/physics/ac/index.d.mts +183 -0
  308. package/dist/physics/ac/index.mjs +203 -0
  309. package/dist/physics/dynamics/forces.d.mts +98 -0
  310. package/dist/physics/dynamics/forces.mjs +153 -0
  311. package/dist/physics/dynamics/friction.d.mts +76 -0
  312. package/dist/physics/dynamics/friction.mjs +119 -0
  313. package/dist/physics/dynamics/system.d.mts +68 -0
  314. package/dist/physics/dynamics/system.mjs +125 -0
  315. package/dist/physics/electrostatics/index.d.mts +169 -0
  316. package/dist/physics/electrostatics/index.mjs +249 -0
  317. package/dist/physics/energy/centre-of-mass.d.mts +115 -0
  318. package/dist/physics/energy/centre-of-mass.mjs +180 -0
  319. package/dist/physics/energy/conservation.d.mts +81 -0
  320. package/dist/physics/energy/conservation.mjs +129 -0
  321. package/dist/physics/energy/power.d.mts +90 -0
  322. package/dist/physics/energy/power.mjs +167 -0
  323. package/dist/physics/energy/spring.d.mts +73 -0
  324. package/dist/physics/energy/spring.mjs +129 -0
  325. package/dist/physics/energy/store.d.mts +63 -0
  326. package/dist/physics/energy/store.mjs +108 -0
  327. package/dist/physics/energy/theorem.d.mts +65 -0
  328. package/dist/physics/energy/theorem.mjs +113 -0
  329. package/dist/physics/energy/work.d.mts +114 -0
  330. package/dist/physics/energy/work.mjs +219 -0
  331. package/dist/physics/gravitation/body.d.mts +85 -0
  332. package/dist/physics/gravitation/body.mjs +168 -0
  333. package/dist/physics/gravitation/kepler.d.mts +127 -0
  334. package/dist/physics/gravitation/kepler.mjs +216 -0
  335. package/dist/physics/gravitation/law.d.mts +117 -0
  336. package/dist/physics/gravitation/law.mjs +175 -0
  337. package/dist/physics/gravitation/orbit.d.mts +119 -0
  338. package/dist/physics/gravitation/orbit.mjs +202 -0
  339. package/dist/physics/gravitation/potential.d.mts +114 -0
  340. package/dist/physics/gravitation/potential.mjs +202 -0
  341. package/dist/physics/gravitation/variation.d.mts +97 -0
  342. package/dist/physics/gravitation/variation.mjs +175 -0
  343. package/dist/physics/index.d.mts +35 -0
  344. package/dist/physics/index.mjs +36 -0
  345. package/dist/physics/integral-sweep.d.mts +63 -0
  346. package/dist/physics/integral-sweep.mjs +126 -0
  347. package/dist/physics/kinematics/equations.d.mts +47 -0
  348. package/dist/physics/kinematics/equations.mjs +126 -0
  349. package/dist/physics/kinematics/free-fall.d.mts +53 -0
  350. package/dist/physics/kinematics/free-fall.mjs +71 -0
  351. package/dist/physics/kinematics/given.d.mts +16 -0
  352. package/dist/physics/kinematics/given.mjs +55 -0
  353. package/dist/physics/kinematics/roots.d.mts +41 -0
  354. package/dist/physics/kinematics/roots.mjs +72 -0
  355. package/dist/physics/kinematics/solve.d.mts +52 -0
  356. package/dist/physics/kinematics/solve.mjs +172 -0
  357. package/dist/physics/magnetism/biot-savart.d.mts +161 -0
  358. package/dist/physics/magnetism/biot-savart.mjs +353 -0
  359. package/dist/physics/magnetism/flux.d.mts +94 -0
  360. package/dist/physics/magnetism/flux.mjs +313 -0
  361. package/dist/physics/magnetism/geomagnetism.d.mts +151 -0
  362. package/dist/physics/magnetism/geomagnetism.mjs +184 -0
  363. package/dist/physics/magnetism/index.d.mts +12 -0
  364. package/dist/physics/magnetism/index.mjs +74 -0
  365. package/dist/physics/magnetism/lorentz.d.mts +28 -0
  366. package/dist/physics/magnetism/lorentz.mjs +88 -0
  367. package/dist/physics/magnetism/magnetic-force.d.mts +102 -0
  368. package/dist/physics/magnetism/magnetic-force.mjs +169 -0
  369. package/dist/physics/momentum/collide.d.mts +77 -0
  370. package/dist/physics/momentum/collide.mjs +115 -0
  371. package/dist/physics/momentum/impulse.d.mts +89 -0
  372. package/dist/physics/momentum/impulse.mjs +159 -0
  373. package/dist/physics/momentum/planar.d.mts +60 -0
  374. package/dist/physics/momentum/planar.mjs +110 -0
  375. package/dist/physics/projectile.d.mts +107 -0
  376. package/dist/physics/projectile.mjs +185 -0
  377. package/dist/physics/rotation/angular.d.mts +85 -0
  378. package/dist/physics/rotation/angular.mjs +130 -0
  379. package/dist/physics/rotation/circular.d.mts +79 -0
  380. package/dist/physics/rotation/circular.mjs +131 -0
  381. package/dist/physics/rotation/inertia.d.mts +164 -0
  382. package/dist/physics/rotation/inertia.mjs +332 -0
  383. package/dist/physics/rotation/torque.d.mts +65 -0
  384. package/dist/physics/rotation/torque.mjs +134 -0
  385. package/dist/physics/vectors.d.mts +64 -0
  386. package/dist/physics/vectors.mjs +114 -0
  387. package/dist/quantity/index.d.mts +119 -0
  388. package/dist/quantity/index.mjs +417 -0
  389. package/dist/relation/derive.d.mts +74 -0
  390. package/dist/relation/derive.mjs +73 -0
  391. package/dist/relation/index.d.mts +56 -0
  392. package/dist/relation/index.mjs +234 -0
  393. package/dist/scene/evaluators.mjs +1 -1
  394. package/dist/sim/thermal.mjs +45 -20
  395. package/dist/thermo/calorimetry.d.mts +207 -0
  396. package/dist/thermo/calorimetry.mjs +345 -0
  397. package/dist/thermo/cycles.d.mts +142 -0
  398. package/dist/thermo/cycles.mjs +256 -0
  399. package/dist/thermo/entropy.d.mts +87 -0
  400. package/dist/thermo/entropy.mjs +140 -0
  401. package/dist/thermo/expansion.d.mts +130 -0
  402. package/dist/thermo/expansion.mjs +178 -0
  403. package/dist/thermo/gas.d.mts +197 -0
  404. package/dist/thermo/gas.mjs +279 -0
  405. package/dist/thermo/heat-transfer.d.mts +164 -0
  406. package/dist/thermo/heat-transfer.mjs +217 -0
  407. package/dist/thermo/index.d.mts +9 -82
  408. package/dist/thermo/index.mjs +9 -132
  409. package/dist/thermo/processes.d.mts +95 -0
  410. package/dist/thermo/processes.mjs +154 -0
  411. package/dist/thermo/temperature.d.mts +174 -0
  412. package/dist/thermo/temperature.mjs +236 -0
  413. package/dist/waves/damping.d.mts +224 -0
  414. package/dist/waves/damping.mjs +317 -0
  415. package/dist/waves/doppler.d.mts +72 -0
  416. package/dist/waves/doppler.mjs +125 -0
  417. package/dist/waves/index.d.mts +10 -0
  418. package/dist/waves/index.mjs +10 -0
  419. package/dist/waves/pendulum.d.mts +130 -0
  420. package/dist/waves/pendulum.mjs +211 -0
  421. package/dist/waves/pitch.d.mts +125 -0
  422. package/dist/waves/pitch.mjs +158 -0
  423. package/dist/waves/shm.d.mts +170 -0
  424. package/dist/waves/shm.mjs +279 -0
  425. package/dist/waves/springs.d.mts +103 -0
  426. package/dist/waves/springs.mjs +176 -0
  427. package/dist/waves/superposition.d.mts +124 -0
  428. package/dist/waves/superposition.mjs +196 -0
  429. package/dist/waves/wave.d.mts +154 -0
  430. package/dist/waves/wave.mjs +178 -0
  431. package/package.json +74 -2
@@ -0,0 +1,562 @@
1
+ //#region src/networking/models/wifi.ts
2
+ const BANDS = {
3
+ "2.4": {
4
+ id: "2.4",
5
+ label: "2.4 GHz",
6
+ megahertz: 2437,
7
+ channels: 3,
8
+ peakMbps: 150,
9
+ note: "Travels further and through more walls. Only three non-overlapping channels, shared with every neighbour, every microwave oven and every Bluetooth device."
10
+ },
11
+ "5": {
12
+ id: "5",
13
+ label: "5 GHz",
14
+ megahertz: 5180,
15
+ channels: 24,
16
+ peakMbps: 650,
17
+ note: "Far more room and far more speed, and it pays for that with range. A shorter wave is absorbed harder by everything it passes through."
18
+ }
19
+ };
20
+ /**
21
+ * Loss per wall, in dB. These are the numbers a site survey actually uses, rounded to whole
22
+ * decibels because the spread between real buildings is wider than the rounding.
23
+ *
24
+ * The column to read across is the band. Concrete costs 12 dB at 2.4 GHz and 20 dB at 5 GHz: the
25
+ * SAME wall takes eight extra decibels out of the faster band, which is a further sixfold drop in
26
+ * power. One interior wall is survivable on either band. Two concrete walls is where 5 GHz stops
27
+ * being a choice.
28
+ */
29
+ const MATERIALS = {
30
+ drywall: {
31
+ id: "drywall",
32
+ label: "Plasterboard partition",
33
+ loss: {
34
+ "2.4": 3,
35
+ "5": 4
36
+ },
37
+ note: "A hollow partition between two rooms. Nearly free to pass through, which is why open-plan flats cover easily."
38
+ },
39
+ wood: {
40
+ id: "wood",
41
+ label: "Wooden door",
42
+ loss: {
43
+ "2.4": 3,
44
+ "5": 5
45
+ },
46
+ note: "Closing an internal door costs real signal. Students rarely believe this until they watch the number move."
47
+ },
48
+ glass: {
49
+ id: "glass",
50
+ label: "Glass",
51
+ loss: {
52
+ "2.4": 3,
53
+ "5": 6
54
+ },
55
+ note: "Plain glass is mild. Coated energy-saving glass behaves closer to brick, which is why signal often dies at a balcony."
56
+ },
57
+ brick: {
58
+ id: "brick",
59
+ label: "Brick wall",
60
+ loss: {
61
+ "2.4": 6,
62
+ "5": 10
63
+ },
64
+ note: "The standard load-bearing wall in most homes here. Two of them between router and phone is the usual cause of a dead bedroom."
65
+ },
66
+ concrete: {
67
+ id: "concrete",
68
+ label: "Reinforced concrete",
69
+ loss: {
70
+ "2.4": 12,
71
+ "5": 20
72
+ },
73
+ note: "Slab, column or shear wall. The steel inside matters as much as the concrete: a conductive mesh reflects what it does not absorb."
74
+ },
75
+ metal: {
76
+ id: "metal",
77
+ label: "Metal / lift shaft",
78
+ loss: {
79
+ "2.4": 30,
80
+ "5": 35
81
+ },
82
+ note: "Effectively a wall a radio cannot cross. Signal reaches the far side by going around it, never through."
83
+ }
84
+ };
85
+ /**
86
+ * Transmit power of a domestic access point, in dBm. 20 dBm is 100 mW, the legal ceiling in most
87
+ * places and what essentially every home router emits, which is worth knowing because it means
88
+ * "buy a more powerful router" is not available as an answer. The only levers are position,
89
+ * frequency, and a second access point.
90
+ */
91
+ const TX_POWER_DBM = 20;
92
+ /**
93
+ * How fast power falls with distance indoors.
94
+ *
95
+ * In free space the exponent is 2: pure spreading over a sphere. Indoors, 3.0 is the standard
96
+ * figure for a home or small office, because furniture, floors and people absorb as well as the
97
+ * geometry spreading. The walls are counted separately and explicitly, so this number represents
98
+ * everything that is NOT a wall the learner placed.
99
+ */
100
+ const PATH_LOSS_EXPONENT = 3;
101
+ /**
102
+ * The floor below which a number stops meaning anything, in dBm.
103
+ *
104
+ * Thermal noise in a 20 MHz channel sits near -101 dBm, so a receiver cannot distinguish a signal
105
+ * from the noise it arrives in much below this. An uncapped model happily reports -114 dBm, which
106
+ * looks precise and is fiction: the honest statement is "below the noise floor", and the lab should
107
+ * say that rather than print a number a real radio could never measure.
108
+ */
109
+ const NOISE_FLOOR_DBM = -100;
110
+ /**
111
+ * Loss over the first metre, in dB. This is where frequency enters before any wall is involved:
112
+ * about 40 dB at 2.4 GHz and 46 dB at 5 GHz. The faster band starts six decibels behind at the
113
+ * very first metre, having passed through nothing at all.
114
+ */
115
+ function referenceLossDb(band) {
116
+ return 20 * Math.log10(BANDS[band].megahertz) + 20 * Math.log10(.001) + 32.44;
117
+ }
118
+ /** Do two segments cross? Used to find which walls sit between the router and a point. */
119
+ function segmentsCross(a1, a2, b1, b2) {
120
+ const side = (p, q, r) => (q.x - p.x) * (r.y - p.y) - (q.y - p.y) * (r.x - p.x);
121
+ const d1 = side(b1, b2, a1);
122
+ const d2 = side(b1, b2, a2);
123
+ const d3 = side(a1, a2, b1);
124
+ const d4 = side(a1, a2, b2);
125
+ return (d1 > 0 !== d2 > 0 || d1 === 0 || d2 === 0) && (d3 > 0 !== d4 > 0 || d3 === 0 || d4 === 0) && d1 !== 0 && d2 !== 0 && d3 !== 0 && d4 !== 0;
126
+ }
127
+ /** The walls a straight line from the router to a point passes through. */
128
+ function wallsBetween(plan, from, to) {
129
+ return plan.walls.filter((wall) => segmentsCross(from, to, {
130
+ x: wall.x1,
131
+ y: wall.y1
132
+ }, {
133
+ x: wall.x2,
134
+ y: wall.y2
135
+ }));
136
+ }
137
+ /**
138
+ * Received signal strength at a point, by the log-distance model with explicit wall terms.
139
+ *
140
+ * This treats the signal as travelling in a straight line and ignores reflection, which in a real
141
+ * flat delivers some signal around a corner that this model calls dead. That simplification is
142
+ * deliberate and is the right one for teaching: it keeps the cause of every number visible, and a
143
+ * model that says "a wall costs you this much" is exactly the intuition a learner should leave with.
144
+ */
145
+ function signalAt(plan, router, point, band) {
146
+ const dx = point.x - router.x;
147
+ const dy = point.y - router.y;
148
+ const distanceM = Math.max(1, Math.hypot(dx, dy));
149
+ const obstacles = wallsBetween(plan, router, point);
150
+ const wallLossDb = obstacles.reduce((sum, wall) => sum + MATERIALS[wall.material].loss[band], 0);
151
+ const spreading = 10 * 3 * Math.log10(distanceM);
152
+ const rssi = 20 - referenceLossDb(band) - spreading - wallLossDb;
153
+ return {
154
+ rssi: Math.max(NOISE_FLOOR_DBM, rssi),
155
+ distanceM,
156
+ obstacles,
157
+ wallLossDb
158
+ };
159
+ }
160
+ /**
161
+ * The grade ladder, in dBm.
162
+ *
163
+ * These are the thresholds a real site survey designs against rather than round numbers chosen to
164
+ * look tidy: -67 dBm is the industry target for voice and video, and -70 is where ordinary data
165
+ * starts to struggle. Naming what a learner could DO at each level, rather than calling it "3 bars",
166
+ * is the point. Bars are a made-up scale that differs between handsets; dBm is a measurement.
167
+ */
168
+ const GRADES = [
169
+ {
170
+ id: "excellent",
171
+ label: "Excellent",
172
+ floor: -50,
173
+ can: "Anything at full speed, right beside the router."
174
+ },
175
+ {
176
+ id: "good",
177
+ label: "Good",
178
+ floor: -60,
179
+ can: "HD video calls and large downloads, no trouble."
180
+ },
181
+ {
182
+ id: "usable",
183
+ label: "Usable",
184
+ floor: -67,
185
+ can: "Video works. This is the level a network is designed to reach everywhere it matters."
186
+ },
187
+ {
188
+ id: "weak",
189
+ label: "Weak",
190
+ floor: -80,
191
+ can: "Messaging and browsing. Calls break up and video stops to buffer."
192
+ },
193
+ {
194
+ id: "dead",
195
+ label: "No usable signal",
196
+ floor: -Infinity,
197
+ can: "The phone may still show a bar and nothing will load."
198
+ }
199
+ ];
200
+ function grade(rssi) {
201
+ return GRADES.find((step) => rssi >= step.floor) ?? GRADES[GRADES.length - 1];
202
+ }
203
+ /**
204
+ * A rough throughput for a reading, in Mbps.
205
+ *
206
+ * Real rate selection is a ladder of modulation schemes, and the shape that matters to a learner is
207
+ * that throughput does not fade gently with distance: it holds up, then falls off a cliff as each
208
+ * rung becomes unreadable. Interpolating between the grade thresholds reproduces that staircase
209
+ * feel without pretending to model MCS tables.
210
+ */
211
+ function throughputMbps(rssi, band) {
212
+ const peak = BANDS[band].peakMbps;
213
+ if (rssi >= -50) return peak;
214
+ if (rssi >= -60) return Math.round(peak * .7);
215
+ if (rssi >= -67) return Math.round(peak * .4);
216
+ if (rssi >= -73) return Math.round(peak * .15);
217
+ if (rssi >= -80) return Math.round(peak * .05);
218
+ return 0;
219
+ }
220
+ /** Sample points inside a room. A 3x3 grid inset from the walls, so a corner is not judged from its centre. */
221
+ function samplePoints(room) {
222
+ const points = [];
223
+ for (let ix = 1; ix <= 3; ix++) for (let iy = 1; iy <= 3; iy++) points.push({
224
+ x: room.x + room.w * ix / 4,
225
+ y: room.y + room.h * iy / 4
226
+ });
227
+ return points;
228
+ }
229
+ /**
230
+ * Grade every room from its WORST corner rather than its centre.
231
+ *
232
+ * Judging a room by its middle is how a coverage plan passes on paper and fails in the building:
233
+ * the desk is against the far wall, not in the centre of the floor. Reporting the worst sample also
234
+ * makes the lab honest when a learner parks the router in the hallway and every room reads "usable"
235
+ * from its midpoint while the bed and the desk do not.
236
+ */
237
+ function roomVerdicts(plan, router, band) {
238
+ return plan.rooms.map((room) => {
239
+ let worst = null;
240
+ for (const point of samplePoints(room)) {
241
+ const reading = signalAt(plan, router, point, band);
242
+ if (!worst || reading.rssi < worst.rssi) worst = reading;
243
+ }
244
+ const reading = worst;
245
+ const blamed = [...new Set(reading.obstacles.map((wall) => wall.material))].sort((a, b) => MATERIALS[b].loss[band] - MATERIALS[a].loss[band]);
246
+ return {
247
+ room,
248
+ rssi: reading.rssi,
249
+ grade: grade(reading.rssi),
250
+ mbps: throughputMbps(reading.rssi, band),
251
+ blamed
252
+ };
253
+ });
254
+ }
255
+ /**
256
+ * RSSI on a regular grid over the whole plan, for the heat map.
257
+ *
258
+ * Returned row-major as `[row][col]` with row 0 at the top, matching how the SVG draws it, so the
259
+ * scene never has to flip an index and quietly mirror the picture.
260
+ */
261
+ function coverageGrid(plan, router, band, cols, rows) {
262
+ const grid = [];
263
+ for (let row = 0; row < rows; row++) {
264
+ const line = [];
265
+ const y = plan.heightM * (row + .5) / rows;
266
+ for (let col = 0; col < cols; col++) {
267
+ const x = plan.widthM * (col + .5) / cols;
268
+ line.push(signalAt(plan, router, {
269
+ x,
270
+ y
271
+ }, band).rssi);
272
+ }
273
+ grid.push(line);
274
+ }
275
+ return grid;
276
+ }
277
+ /** Share of the rooms that reach at least `usable`, which is the number a learner is trying to raise. */
278
+ function coverageScore(plan, router, band) {
279
+ const verdicts = roomVerdicts(plan, router, band);
280
+ if (!verdicts.length) return 0;
281
+ return verdicts.filter((verdict) => verdict.rssi >= -67).length / verdicts.length;
282
+ }
283
+ /** A run of wall with doorway gaps left open, so a learner can see signal pour through a door. */
284
+ function wallRun(axis, at, spans, material) {
285
+ return spans.map(([from, to]) => axis === "h" ? {
286
+ x1: from,
287
+ y1: at,
288
+ x2: to,
289
+ y2: at,
290
+ material
291
+ } : {
292
+ x1: at,
293
+ y1: from,
294
+ x2: at,
295
+ y2: to,
296
+ material
297
+ });
298
+ }
299
+ /**
300
+ * Floor plans a learner recognises, which is most of the work.
301
+ *
302
+ * A generic rectangle labelled "room A / room B" teaches the model and none of the intuition. The
303
+ * three-bedroom flat below is the ordinary shape of an apartment in Dhaka or Chattogram: brick
304
+ * partitions, a concrete wet wall around the bathroom, and the router wherever the broadband cable
305
+ * happened to enter, which is almost never where it should be. A learner who fixes THIS plan can
306
+ * walk home and fix theirs, and that transfer is the whole reason to draw a room instead of a graph.
307
+ */
308
+ const FLOOR_PLANS = [
309
+ {
310
+ id: "flat",
311
+ name: "Three-bedroom flat",
312
+ widthM: 12,
313
+ heightM: 9,
314
+ note: "The cable enters at the drawing room corner, so that is where the router sits. Two brick walls and a concrete wet wall stand between it and the far bedroom.",
315
+ rooms: [
316
+ {
317
+ id: "living",
318
+ name: "Drawing room",
319
+ x: 0,
320
+ y: 0,
321
+ w: 6,
322
+ h: 5
323
+ },
324
+ {
325
+ id: "kitchen",
326
+ name: "Kitchen",
327
+ x: 6,
328
+ y: 0,
329
+ w: 3,
330
+ h: 5
331
+ },
332
+ {
333
+ id: "bath",
334
+ name: "Bathroom",
335
+ x: 9,
336
+ y: 0,
337
+ w: 3,
338
+ h: 5
339
+ },
340
+ {
341
+ id: "bed1",
342
+ name: "Bedroom 1",
343
+ x: 0,
344
+ y: 5,
345
+ w: 4,
346
+ h: 4
347
+ },
348
+ {
349
+ id: "bed2",
350
+ name: "Bedroom 2",
351
+ x: 4,
352
+ y: 5,
353
+ w: 4,
354
+ h: 4
355
+ },
356
+ {
357
+ id: "bed3",
358
+ name: "Bedroom 3",
359
+ x: 8,
360
+ y: 5,
361
+ w: 4,
362
+ h: 4
363
+ }
364
+ ],
365
+ spots: [
366
+ {
367
+ id: "corner",
368
+ name: "Drawing room corner, where the cable enters",
369
+ x: 1,
370
+ y: 1
371
+ },
372
+ {
373
+ id: "middle",
374
+ name: "Middle of the drawing room",
375
+ x: 4.6,
376
+ y: 2.4
377
+ },
378
+ {
379
+ id: "kitchen",
380
+ name: "On the kitchen worktop",
381
+ x: 7.5,
382
+ y: 4.3
383
+ },
384
+ {
385
+ id: "hall",
386
+ name: "Bedroom 2 wall, beside the door",
387
+ x: 7.6,
388
+ y: 5.4
389
+ },
390
+ {
391
+ id: "bed1",
392
+ name: "Bedroom 1, next to the bed",
393
+ x: 2,
394
+ y: 7
395
+ }
396
+ ],
397
+ walls: [
398
+ ...wallRun("h", 5, [
399
+ [0, 3],
400
+ [3.9, 7],
401
+ [7.9, 12]
402
+ ], "brick"),
403
+ ...wallRun("v", 6, [[0, 3.2], [4.1, 5]], "brick"),
404
+ ...wallRun("v", 9, [[0, 5]], "concrete"),
405
+ ...wallRun("v", 4, [[5, 8.1]], "brick"),
406
+ ...wallRun("v", 8, [[5, 8.1]], "brick")
407
+ ]
408
+ },
409
+ {
410
+ id: "open",
411
+ name: "Open-plan studio",
412
+ widthM: 10,
413
+ heightM: 7,
414
+ note: "Almost nothing in the way. Included so a learner can see what distance alone does, with absorption taken out of the picture.",
415
+ rooms: [
416
+ {
417
+ id: "main",
418
+ name: "Living and sleeping",
419
+ x: 0,
420
+ y: 0,
421
+ w: 7,
422
+ h: 7
423
+ },
424
+ {
425
+ id: "wash",
426
+ name: "Washroom",
427
+ x: 7,
428
+ y: 0,
429
+ w: 3,
430
+ h: 3
431
+ },
432
+ {
433
+ id: "balcony",
434
+ name: "Balcony",
435
+ x: 7,
436
+ y: 3,
437
+ w: 3,
438
+ h: 4
439
+ }
440
+ ],
441
+ spots: [
442
+ {
443
+ id: "corner",
444
+ name: "Corner by the door",
445
+ x: 1,
446
+ y: 1
447
+ },
448
+ {
449
+ id: "middle",
450
+ name: "Middle of the room",
451
+ x: 3.5,
452
+ y: 3.5
453
+ },
454
+ {
455
+ id: "balcony",
456
+ name: "Out on the balcony",
457
+ x: 8.5,
458
+ y: 5
459
+ }
460
+ ],
461
+ walls: [
462
+ ...wallRun("v", 7, [[0, 2.2]], "brick"),
463
+ ...wallRun("h", 3, [[7, 10]], "drywall"),
464
+ ...wallRun("v", 7, [[3.4, 7]], "glass")
465
+ ]
466
+ },
467
+ {
468
+ id: "office",
469
+ name: "Small office floor",
470
+ widthM: 16,
471
+ heightM: 10,
472
+ note: "A concrete core and a lift shaft. One access point cannot do this, and discovering that is the point of the plan.",
473
+ rooms: [
474
+ {
475
+ id: "open-desks",
476
+ name: "Open desks",
477
+ x: 0,
478
+ y: 0,
479
+ w: 9,
480
+ h: 10
481
+ },
482
+ {
483
+ id: "meeting",
484
+ name: "Meeting room",
485
+ x: 9,
486
+ y: 0,
487
+ w: 4,
488
+ h: 5
489
+ },
490
+ {
491
+ id: "server",
492
+ name: "Server room",
493
+ x: 9,
494
+ y: 5,
495
+ w: 4,
496
+ h: 5
497
+ },
498
+ {
499
+ id: "lobby",
500
+ name: "Lift lobby",
501
+ x: 13,
502
+ y: 0,
503
+ w: 3,
504
+ h: 10
505
+ }
506
+ ],
507
+ spots: [
508
+ {
509
+ id: "desks",
510
+ name: "Above the open desks",
511
+ x: 4.5,
512
+ y: 5
513
+ },
514
+ {
515
+ id: "core",
516
+ name: "Against the concrete core",
517
+ x: 8.2,
518
+ y: 4.5
519
+ },
520
+ {
521
+ id: "meeting",
522
+ name: "Inside the meeting room",
523
+ x: 11,
524
+ y: 2.5
525
+ }
526
+ ],
527
+ walls: [
528
+ ...wallRun("v", 9, [[0, 4.1], [5, 10]], "concrete"),
529
+ ...wallRun("h", 5, [[9, 13]], "concrete"),
530
+ ...wallRun("v", 13, [[0, 4], [5.1, 10]], "metal")
531
+ ]
532
+ }
533
+ ];
534
+ /**
535
+ * The best spot on the plan, found by trying a coarse grid of positions.
536
+ *
537
+ * Present this only AFTER a learner has committed to a position of their own. Shown first it is an
538
+ * answer key and they will drag toward it without forming a reason; shown second it is feedback on
539
+ * a guess they already had to justify, and the gap between the two is the lesson.
540
+ */
541
+ function bestPlacement(plan, band, step = 1) {
542
+ let best = {
543
+ x: plan.widthM / 2,
544
+ y: plan.heightM / 2
545
+ };
546
+ let bestScore = -Infinity;
547
+ for (let x = step; x < plan.widthM; x += step) for (let y = step; y < plan.heightM; y += step) {
548
+ const candidate = {
549
+ x,
550
+ y
551
+ };
552
+ const worst = Math.min(...roomVerdicts(plan, candidate, band).map((verdict) => verdict.rssi));
553
+ if (worst > bestScore) {
554
+ bestScore = worst;
555
+ best = candidate;
556
+ }
557
+ }
558
+ return best;
559
+ }
560
+
561
+ //#endregion
562
+ export { BANDS, FLOOR_PLANS, GRADES, MATERIALS, NOISE_FLOOR_DBM, PATH_LOSS_EXPONENT, TX_POWER_DBM, bestPlacement, coverageGrid, coverageScore, grade, referenceLossDb, roomVerdicts, signalAt, throughputMbps, wallsBetween };
@@ -0,0 +1,24 @@
1
+ //#region src/networking/nat-traversal.d.ts
2
+ type NatBehavior = "endpoint-independent" | "address-dependent" | "symmetric";
3
+ type TraversalStrategy = "host-only" | "stun" | "ice";
4
+ interface NatTraversalOptions {
5
+ leftNat: NatBehavior;
6
+ rightNat: NatBehavior;
7
+ strategy: TraversalStrategy;
8
+ turnAvailable?: boolean;
9
+ }
10
+ interface NatTraversalResult {
11
+ candidates: readonly ("host" | "server-reflexive" | "relay")[];
12
+ selectedPath: "direct" | "mapped-direct" | "relay" | "blocked";
13
+ relayRequired: boolean;
14
+ relativeLatency: 1 | 2;
15
+ explanation: string;
16
+ }
17
+ declare function simulateNatTraversal({
18
+ leftNat,
19
+ rightNat,
20
+ strategy,
21
+ turnAvailable
22
+ }: NatTraversalOptions): NatTraversalResult;
23
+ //#endregion
24
+ export { NatBehavior, NatTraversalOptions, NatTraversalResult, TraversalStrategy, simulateNatTraversal };
@@ -0,0 +1,38 @@
1
+ //#region src/networking/nat-traversal.ts
2
+ function simulateNatTraversal({ leftNat, rightNat, strategy, turnAvailable = true }) {
3
+ if (strategy === "host-only") return {
4
+ candidates: ["host"],
5
+ selectedPath: "blocked",
6
+ relayRequired: false,
7
+ relativeLatency: 1,
8
+ explanation: "Private host addresses are not reachable across the public Internet."
9
+ };
10
+ if (!(leftNat === "symmetric" || rightNat === "symmetric")) return {
11
+ candidates: ["host", "server-reflexive"],
12
+ selectedPath: "mapped-direct",
13
+ relayRequired: false,
14
+ relativeLatency: 1,
15
+ explanation: "STUN reveals usable public mappings, so the peers can check a direct path."
16
+ };
17
+ if (strategy === "ice" && turnAvailable) return {
18
+ candidates: [
19
+ "host",
20
+ "server-reflexive",
21
+ "relay"
22
+ ],
23
+ selectedPath: "relay",
24
+ relayRequired: true,
25
+ relativeLatency: 2,
26
+ explanation: "Direct checks fail, so ICE selects the TURN relay candidate."
27
+ };
28
+ return {
29
+ candidates: ["host", "server-reflexive"],
30
+ selectedPath: "blocked",
31
+ relayRequired: true,
32
+ relativeLatency: 1,
33
+ explanation: "The changing mapping defeats the direct candidate and no relay is available."
34
+ };
35
+ }
36
+
37
+ //#endregion
38
+ export { simulateNatTraversal };
@@ -0,0 +1,17 @@
1
+ //#region src/networking/protocols.d.ts
2
+ type DnsCache = "cold" | "warm";
3
+ interface DnsHop {
4
+ readonly id: string;
5
+ readonly label: string;
6
+ readonly answer: string;
7
+ }
8
+ declare function dnsHops(hostname?: string, address?: string): readonly DnsHop[];
9
+ declare const DNS_HOPS: readonly DnsHop[];
10
+ declare function dnsPath(cache: DnsCache, hostname?: string, address?: string): readonly DnsHop[];
11
+ declare function dnsLookupMs(cache: DnsCache, hopMs: number): number;
12
+ type CertificateKind = "trusted" | "wrong-name" | "untrusted";
13
+ declare const TLS_STEPS: readonly ["ClientHello", "ServerHello", "Certificate", "Finished", "Application data"];
14
+ declare function certificateAccepted(kind: CertificateKind): boolean;
15
+ declare function visibleOnWire(step: number, accepted: boolean): string;
16
+ //#endregion
17
+ export { CertificateKind, DNS_HOPS, DnsCache, DnsHop, TLS_STEPS, certificateAccepted, dnsHops, dnsLookupMs, dnsPath, visibleOnWire };
@@ -0,0 +1,57 @@
1
+ //#region src/networking/protocols.ts
2
+ function dnsHops(hostname = "chat.example", address = "203.0.113.42") {
3
+ const suffix = hostname.includes(".") ? `.${hostname.split(".").at(-1)}` : hostname;
4
+ return [
5
+ {
6
+ id: "device",
7
+ label: "Your device",
8
+ answer: "Ask the recursive resolver"
9
+ },
10
+ {
11
+ id: "resolver",
12
+ label: "Recursive resolver",
13
+ answer: "Check cache, then do the lookup"
14
+ },
15
+ {
16
+ id: "root",
17
+ label: "Root",
18
+ answer: `Ask the ${suffix} servers`
19
+ },
20
+ {
21
+ id: "tld",
22
+ label: suffix,
23
+ answer: `Ask ${hostname}’s authority`
24
+ },
25
+ {
26
+ id: "authority",
27
+ label: "Authoritative server",
28
+ answer: address
29
+ }
30
+ ];
31
+ }
32
+ const DNS_HOPS = dnsHops();
33
+ function dnsPath(cache, hostname, address) {
34
+ const hops = dnsHops(hostname, address);
35
+ return cache === "warm" ? hops.slice(0, 2) : hops;
36
+ }
37
+ function dnsLookupMs(cache, hopMs) {
38
+ return cache === "warm" ? Math.max(1, hopMs) : Math.max(1, hopMs) * 4;
39
+ }
40
+ const TLS_STEPS = [
41
+ "ClientHello",
42
+ "ServerHello",
43
+ "Certificate",
44
+ "Finished",
45
+ "Application data"
46
+ ];
47
+ function certificateAccepted(kind) {
48
+ return kind === "trusted";
49
+ }
50
+ function visibleOnWire(step, accepted) {
51
+ if (step < 2) return "ClientHello and ServerHello";
52
+ if (!accepted) return "handshake stopped";
53
+ return step < 4 ? "encrypted handshake bytes" : "encrypted application bytes";
54
+ }
55
+
56
+ //#endregion
57
+ export { DNS_HOPS, TLS_STEPS, certificateAccepted, dnsHops, dnsLookupMs, dnsPath, visibleOnWire };
@@ -0,0 +1,12 @@
1
+ //#region src/networking/queue.d.ts
2
+ /** Pure finite-buffer queue mechanics. Rates are packets per second. */
3
+ interface QueueResult {
4
+ readonly queued: number;
5
+ readonly dropped: number;
6
+ readonly delayMs: number;
7
+ readonly state: "clear" | "building" | "dropping";
8
+ }
9
+ declare function queueAtTime(arrivalPps: number, servicePps: number, bufferPackets: number, elapsedSeconds: number): QueueResult;
10
+ declare function bottleneckQueue(arrivalPps: number, servicePps: number, bufferPackets: number): QueueResult;
11
+ //#endregion
12
+ export { QueueResult, bottleneckQueue, queueAtTime };