@aryacode/dsh-aryacode-polish 0.3.5 → 0.3.7

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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,36 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.3.7] - 2026-10-27
4
+
5
+ ### Fixed
6
+
7
+ - **A weekday holiday was priced at peak.** DeepSeek's rule is "Beijing time,
8
+ Monday to Friday **excluding Chinese statutory public holidays**, 09:00–12:00
9
+ and 14:00–18:00", and the fold only knew about weekdays: every weekday inside
10
+ those windows was billed at 2×, so a public holiday overstated the estimate by
11
+ double. `entries/usage.js` now carries the 2026 holiday dates as dated data,
12
+ sourced from the State Council notice (Guo Ban Fa Ming Dian [2025] No. 7), and
13
+ `test/cost.spec.mjs` proves a holiday Thursday is off-peak while an ordinary one
14
+ is not.
15
+
16
+ ### Changed
17
+
18
+ - **The rate table is verified against both price pages and pinned by a test.**
19
+ Re-checked 2026-10-27 against the English and Chinese pricing pages: all twelve
20
+ off-peak numbers match (Flash `0.003/0.15/0.6` USD and `0.02/1/4` CNY, Pro
21
+ `0.022/0.66/1.98` USD and `0.15/4.5/13.5` CNY), and the legacy Flash model names
22
+ still bill at the Flash price. A new spec fails if any of those numbers drift.
23
+
24
+ ## [0.3.6] - 2026-10-27
25
+
26
+ ### Fixed
27
+
28
+ - **The README's status line no longer carries a version.** The packaged README is
29
+ the card's page body, so any version written into its prose is stale as soon as
30
+ the next release ships — 0.3.5 was published with a page still describing
31
+ "0.3.4". The status now says what shipped; the version comes from the manifest
32
+ and the page header. `test/docs.spec.mjs` fails if a version returns.
33
+
3
34
  ## [0.3.5] - 2026-10-27
4
35
 
5
36
  ### Fixed
package/README.md CHANGED
@@ -7,8 +7,8 @@ installed into and patches nothing. It is one package, one Plugins row, and one
7
7
  switch per feature, so a refinement that turns out to be wrong for a machine can
8
8
  be turned off without uninstalling anything.
9
9
 
10
- Status: **0.3.4.** Two features shipped and released: the estimated session cost
11
- pill and the account balance line.
10
+ Status: **two features shipped.** The version is the package's, and the card
11
+ header already shows it.
12
12
 
13
13
  ## What it is
14
14
 
@@ -39,7 +39,9 @@ The numbers come from the Host, never from the browser:
39
39
 
40
40
  - `entries/usage.js` folds model-attributed provider usage out of the durable
41
41
  session log, one row per provider, model, and hour, and tags each band as peak
42
- or off-peak (Beijing weekdays 09–12 and 14–18 are billed at 2×).
42
+ or off-peak. Peak is Beijing weekdays 09:00–12:00 and 14:00–18:00, billed at 2×,
43
+ and Chinese statutory public holidays are off-peak all day — the 2026 list is
44
+ dated data in that file, sourced from the State Council notice.
43
45
  - `entries/cost.js` registers the `polishCost` projection and prices that fold:
44
46
  cache reads at the cache rate, uncached input and cache writes at the miss
45
47
  rate, output at the output rate. The wire view is already money, so no rate
@@ -47,8 +49,10 @@ The numbers come from the Host, never from the browser:
47
49
  - An unknown provider, model, or rate period keeps its tokens and marks the
48
50
  estimate **incomplete** — the pill says so rather than reporting a number it
49
51
  cannot stand behind.
50
- - The rate table is dated and lives in one place. When DeepSeek changes prices,
51
- append a period; do not edit history.
52
+ - The rate table is dated and lives in one place, and
53
+ `test/cost.spec.mjs` pins all twelve published numbers together with the two
54
+ price pages they came from. When DeepSeek changes prices, append a period; do
55
+ not edit history.
52
56
 
53
57
  ## Declaring a feature
54
58
 
package/entries/cost.js CHANGED
@@ -12,7 +12,11 @@ import { applyModelUsage, initialModelUsage } from './usage.js'
12
12
  /**
13
13
  * Off-peak price per million tokens. Peak is twice this. `usd` is the English
14
14
  * price page and `cny` the Chinese one; cache writes are billed as misses.
15
- * Verified 2026-09-27 against https://api-docs.deepseek.com/quick_start/pricing/
15
+ *
16
+ * Verified 2026-10-27 against both pages:
17
+ * https://api-docs.deepseek.com/quick_start/pricing/
18
+ * https://api-docs.deepseek.com/zh-cn/quick_start/pricing
19
+ * `test/cost.spec.mjs` pins all twelve numbers so an edit cannot drift silently.
16
20
  */
17
21
  const OFF_PEAK = {
18
22
  flash: {
package/entries/usage.js CHANGED
@@ -15,18 +15,64 @@ function zero() {
15
15
  }
16
16
 
17
17
  /**
18
- * Beijing peak is weekdays 09:00-12:00 and 14:00-18:00; weekends are off-peak
19
- * all day. DeepSeek bills peak hours at twice the off-peak rate.
18
+ * Chinese statutory public holidays, as Beijing calendar dates.
19
+ *
20
+ * DeepSeek bills peak hours at twice the off-peak rate, and its rule is "Beijing
21
+ * time, Monday to Friday (excluding Chinese statutory public holidays) 09:00-12:00
22
+ * and 14:00-18:00"; weekends and holidays are off-peak all day. A weekday holiday
23
+ * that is not listed here would be priced at peak and overstate the estimate, so
24
+ * this list is dated data like the rate table: append the next year's notice, do
25
+ * not edit history.
26
+ *
27
+ * 2026: General Office of the State Council, Guo Ban Fa Ming Dian [2025] No. 7
28
+ * (2025-11-04),
29
+ * https://www.gov.cn/zhengce/zhengceku/202511/content_7047091.htm
30
+ *
31
+ * Designated make-up working days stay off-peak: the published rule names
32
+ * Monday through Friday, so a working Saturday is still a Saturday.
33
+ */
34
+ const CHINA_HOLIDAYS = new Set([
35
+ // New Year 2026: Jan 1 (Thu) - Jan 3 (Sat)
36
+ '2026-01-01', '2026-01-02', '2026-01-03',
37
+ // Spring Festival: Feb 15 (Sun) - Feb 23 (Mon)
38
+ '2026-02-15', '2026-02-16', '2026-02-17', '2026-02-18', '2026-02-19',
39
+ '2026-02-20', '2026-02-21', '2026-02-22', '2026-02-23',
40
+ // Qingming: Apr 4 (Sat) - Apr 6 (Mon)
41
+ '2026-04-04', '2026-04-05', '2026-04-06',
42
+ // Labour Day: May 1 (Fri) - May 5 (Tue)
43
+ '2026-05-01', '2026-05-02', '2026-05-03', '2026-05-04', '2026-05-05',
44
+ // Dragon Boat: Jun 19 (Fri) - Jun 21 (Sun)
45
+ '2026-06-19', '2026-06-20', '2026-06-21',
46
+ // Mid-Autumn: Sep 25 (Fri) - Sep 27 (Sun)
47
+ '2026-09-25', '2026-09-26', '2026-09-27',
48
+ // National Day: Oct 1 (Thu) - Oct 7 (Wed)
49
+ '2026-10-01', '2026-10-02', '2026-10-03', '2026-10-04',
50
+ '2026-10-05', '2026-10-06', '2026-10-07',
51
+ ])
52
+
53
+ /**
54
+ * Beijing peak is weekdays 09:00-12:00 and 14:00-18:00, minus Chinese statutory
55
+ * public holidays; weekends are off-peak all day. DeepSeek bills peak hours at
56
+ * twice the off-peak rate.
20
57
  * @param {number} time - event time in milliseconds.
21
58
  * @returns {boolean} whether that instant is a billed peak instant.
22
59
  */
23
60
  export function isBeijingPeak(time) {
24
61
  const parts = new Intl.DateTimeFormat('en-US', {
25
- timeZone: 'Asia/Shanghai', weekday: 'short', hour: 'numeric', hourCycle: 'h23',
62
+ timeZone: 'Asia/Shanghai',
63
+ weekday: 'short',
64
+ year: 'numeric',
65
+ month: '2-digit',
66
+ day: '2-digit',
67
+ hour: 'numeric',
68
+ hourCycle: 'h23',
26
69
  }).formatToParts(new Date(time))
27
- const weekday = parts.find(part => part.type === 'weekday')?.value
28
- const hour = Number(parts.find(part => part.type === 'hour')?.value)
70
+ const part = type => parts.find(entry => entry.type === type)?.value
71
+ const weekday = part('weekday')
72
+ const hour = Number(part('hour'))
29
73
  if (weekday === 'Sat' || weekday === 'Sun' || !Number.isInteger(hour)) return false
74
+ const date = `${part('year')}-${part('month')}-${part('day')}`
75
+ if (CHINA_HOLIDAYS.has(date)) return false
30
76
  return (hour >= 9 && hour < 12) || (hour >= 14 && hour < 18)
31
77
  }
32
78
 
package/lib/client.js CHANGED
@@ -23,7 +23,7 @@ window.__ModuleLoader__.load({
23
23
  ]
24
24
  const ROW_ID = "polish"
25
25
  const ROW_KEY = "@aryacode/dsh-aryacode-polish" + '#' + ROW_ID
26
- const CLIENT_VERSION = "0.3.5"
26
+ const CLIENT_VERSION = "0.3.7"
27
27
 
28
28
  /**
29
29
  * The two pure decisions behind the balance line: which wallet to show, and how
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aryacode/dsh-aryacode-polish",
3
- "version": "0.3.5",
3
+ "version": "0.3.7",
4
4
  "description": "AryaCode Polish: one install for the small things that make AryaCode feel finished. One Plugins row, one switch per quality-of-life feature.",
5
5
  "keywords": [
6
6
  "dsh",