@verifyhash/climate-normals 0.1.0 → 0.1.1

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 (4) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +2 -12
  3. package/index.d.ts +166 -0
  4. package/package.json +4 -2
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 <OWNER-NAME PLACEHOLDER>
3
+ Copyright (c) 2026 verifyhash
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -1,12 +1,5 @@
1
1
  # climate-normals
2
2
 
3
- <!-- publish-prep -->
4
- > **TODO (owner): pick the final npm name/scope before publishing.**
5
- > The npm package name is **not** finalized by this project. Convention used here:
6
- > `package.json` keeps the working slug `climate-normals` as a placeholder — replace it
7
- > (and the `npm install` line below) with the real published name/scope before
8
- > running `npm publish`.
9
-
10
3
  A tiny, **zero-dependency** Node library of climate math over **monthly
11
4
  normals** — heating/cooling degree-days, apparent ("feels like") temperature,
12
5
  diurnal range, a continentality index, and a monthly pleasantness score.
@@ -198,15 +191,12 @@ MIT.
198
191
 
199
192
  ## Install
200
193
 
201
- > Placeholder name: the `climate-normals` below is the working slug, not a finalized
202
- > npm name — see the owner TODO near the top of this README.
203
-
204
194
  ```sh
205
- npm install climate-normals
195
+ npm install @verifyhash/climate-normals
206
196
  ```
207
197
 
208
198
  ```js
209
- const climate = require('climate-normals');
199
+ const climate = require('@verifyhash/climate-normals');
210
200
 
211
201
  const july = { hi: 23.5, lo: 14.0, pr: 45, rh: 65, ws: 3.2 };
212
202
  climate.meanTemp(july); // 18.75 (°C, midpoint of hi/lo)
package/index.d.ts ADDED
@@ -0,0 +1,166 @@
1
+ /**
2
+ * Type declarations for @verifyhash/climate-normals — zero-dependency climate
3
+ * math over monthly normals.
4
+ *
5
+ * The canonical month object is { hi, lo, pr?, rh?, ws? }: average daily high
6
+ * / low temperature (°C), monthly precipitation (mm, pleasantness only),
7
+ * relative humidity (%, apparent-temp only), wind speed (m/s, apparent-temp
8
+ * only). Functions only read the fields they document. "months" arrays are in
9
+ * calendar order (index 0 = January); year-summarising functions require
10
+ * exactly 12 entries.
11
+ */
12
+
13
+ /** One month of normals. Only hi/lo are always required. */
14
+ export interface MonthNormal {
15
+ /** Average daily HIGH temperature, °C. */
16
+ hi: number;
17
+ /** Average daily LOW temperature, °C. */
18
+ lo: number;
19
+ /** Average monthly PRECIPITATION, mm (pleasantness only). */
20
+ pr?: number;
21
+ /** Average RELATIVE HUMIDITY, % (apparent-temp only). */
22
+ rh?: number;
23
+ /** Average WIND SPEED, m/s (apparent-temp only). */
24
+ ws?: number;
25
+ }
26
+
27
+ /** Non-leap days per month (Feb = 28). */
28
+ export const DAYS_IN_MONTH: number[];
29
+ /** Default degree-day base temperature, °C (18). */
30
+ export const HDD_BASE: number;
31
+ /** Comfort band lower bound, °C mean daily temperature (18). */
32
+ export const COMFORT_LO: number;
33
+ /** Comfort band upper bound, °C mean daily temperature (24). */
34
+ export const COMFORT_HI: number;
35
+ /** Rain penalty per mm for the pleasantness heuristic (0.03). */
36
+ export const RAIN_PENALTY_PER_MM: number;
37
+ /** Avg high (°C) at/above which the heat index applies (27). */
38
+ export const FEELS_WARM_HI: number;
39
+ /** Avg low (°C) at/below which wind chill applies (10). */
40
+ export const FEELS_COLD_LO: number;
41
+
42
+ /** Mean daily temperature of a month = (hi + lo) / 2, in °C. */
43
+ export function meanTemp(month: { hi: number; lo: number }): number;
44
+
45
+ /** Result of degreeDays(). */
46
+ export interface DegreeDaysResult {
47
+ /** Per-month raw (unrounded) degree-days. */
48
+ rows: Array<{ i: number; mean: number; hdd: number; cdd: number }>;
49
+ /** Rounded annual heating degree-day total. */
50
+ hdd: number;
51
+ /** Rounded annual cooling degree-day total. */
52
+ cdd: number;
53
+ /** Whichever total is larger (ties count as heating). */
54
+ dominated: 'heating' | 'cooling';
55
+ }
56
+
57
+ /**
58
+ * Heating & cooling degree-days for a year of monthly normals (exactly 12
59
+ * months, Jan..Dec). Base defaults to 18 °C.
60
+ */
61
+ export function degreeDays(
62
+ months: Array<{ hi: number; lo: number }>,
63
+ base?: number
64
+ ): DegreeDaysResult;
65
+
66
+ /**
67
+ * NWS Heat Index (Rothfusz regression): apparent temperature in °C for air
68
+ * temperature tC (°C) and relative humidity rh (%).
69
+ */
70
+ export function heatIndex(tC: number, rh: number): number;
71
+
72
+ /**
73
+ * NWS wind chill (2001 revision): apparent temperature in °C for air
74
+ * temperature tC (°C) and wind speed ws (m/s). Below ~4.8 km/h wind the air
75
+ * temperature is returned unchanged; never warmer than tC.
76
+ */
77
+ export function windChill(tC: number, ws: number): number;
78
+
79
+ /** Options for apparentTemperature(). */
80
+ export interface ApparentTemperatureOptions {
81
+ /** Avg high (°C) at/above which the heat index applies (default 27). */
82
+ warmThreshold?: number;
83
+ /** Avg low (°C) at/below which wind chill applies (default 10). */
84
+ coldThreshold?: number;
85
+ }
86
+
87
+ /** Result of apparentTemperature(). */
88
+ export interface ApparentTemperatureResult {
89
+ feelsHi: number;
90
+ feelsLo: number;
91
+ hiMode: 'actual' | 'heat';
92
+ loMode: 'actual' | 'wind';
93
+ /** feelsHi - hi (≥ 0): how much hotter humidity makes the day. */
94
+ dHot: number;
95
+ /** lo - feelsLo (≥ 0): how much colder wind makes the night. */
96
+ dCold: number;
97
+ }
98
+
99
+ /**
100
+ * Apparent ("feels like") daily high and low for one month of normals,
101
+ * folding in humidity (heat index) and/or wind (wind chill) when the
102
+ * thresholds are met.
103
+ */
104
+ export function apparentTemperature(
105
+ month: { hi: number; lo: number; rh?: number; ws?: number },
106
+ opts?: ApparentTemperatureOptions
107
+ ): ApparentTemperatureResult;
108
+
109
+ /**
110
+ * Day-to-night temperature swing across a year (exactly 12 months). `annual`
111
+ * is the mean of the 12 swings; `big`/`small` are the month indices of the
112
+ * largest and smallest swings (first month wins ties).
113
+ */
114
+ export function diurnalRange(months: Array<{ hi: number; lo: number }>): {
115
+ swings: number[];
116
+ annual: number;
117
+ big: number;
118
+ small: number;
119
+ };
120
+
121
+ /**
122
+ * Annual mean-temperature range and its continentality classification
123
+ * (exactly 12 months). `warm`/`cold` are month indices; `range` is rounded to
124
+ * one decimal °C; `klass` is 'maritime / oceanic',
125
+ * 'transitional / moderately continental', or 'continental'.
126
+ */
127
+ export function continentality(months: Array<{ hi: number; lo: number }>): {
128
+ warm: number;
129
+ cold: number;
130
+ warmMean: number;
131
+ coldMean: number;
132
+ range: number;
133
+ klass: string;
134
+ };
135
+
136
+ /**
137
+ * Pleasantness (comfort) score for a single month — LOWER is more
138
+ * comfortable; a month inside the 18–24 °C band with no rain scores 0.
139
+ */
140
+ export function pleasantnessScore(month: {
141
+ hi: number;
142
+ lo: number;
143
+ pr?: number;
144
+ }): {
145
+ mean: number;
146
+ tempPenalty: number;
147
+ rainPenalty: number;
148
+ score: number;
149
+ };
150
+
151
+ /**
152
+ * Rank a year of months (exactly 12) from most to least pleasant. `ranked`
153
+ * holds month indices best-first; ties keep calendar order.
154
+ */
155
+ export function rankMonths(
156
+ months: Array<{ hi: number; lo: number; pr?: number }>
157
+ ): {
158
+ scored: Array<{
159
+ i: number;
160
+ mean: number;
161
+ tempPenalty: number;
162
+ rainPenalty: number;
163
+ score: number;
164
+ }>;
165
+ ranked: number[];
166
+ };
package/package.json CHANGED
@@ -1,8 +1,9 @@
1
1
  {
2
2
  "name": "@verifyhash/climate-normals",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Zero-dependency climate math over monthly normals: heating/cooling degree-days, apparent (\"feels like\") temperature, diurnal range, a continentality index, and a monthly pleasantness score.",
5
5
  "main": "index.js",
6
+ "types": "index.d.ts",
6
7
  "type": "commonjs",
7
8
  "scripts": {
8
9
  "test": "node test/index.test.js"
@@ -23,7 +24,8 @@
23
24
  "license": "MIT",
24
25
  "files": [
25
26
  "index.js",
26
- "README.md"
27
+ "README.md",
28
+ "index.d.ts"
27
29
  ],
28
30
  "publishConfig": {
29
31
  "access": "public"