@onlyworlds/sdk 4.42.0 → 4.42.2

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
@@ -5,6 +5,22 @@ earlier history lives in git log only.
5
5
 
6
6
  ## [Unreleased]
7
7
 
8
+ ## [4.42.2] - 2026-10-20
9
+
10
+ Two calendar reading fixes, found writing the `atlas_calendar` profile's conformance fixture (OW Council h58 #8943, #8946).
11
+
12
+ ### Fixed
13
+ - **A down era has no year zero, even when its pivot falls mid-year.** Its year is now counted from the year holding the step just before the pivot, which reads `year_base` (1 by default). With the pivot mid-year, the earlier steps of the pivot's own year read year 0 ("0 BG") and every year before it one lower; with the pivot on a year's first step, nothing changes. The mirror of an up era, whose first partial year is year 1.
14
+ - **Equal-start eras resolve by a stated rule:** an up era over a down one, then the later era in the list. The comparator returned `-1` for any pair led by an up era, so two eras of one direction came out in the sort's order rather than the list's.
15
+
16
+ ## [4.42.1] - 2026-10-20
17
+
18
+ The calendar reader refuses what the `atlas_calendar` profile refuses (schema-dist `profiles/calendar.md`; Quillon's Unity read, OW Council h58 #8917).
19
+
20
+ ### Fixed
21
+ - **`readCalendarValue` / `readCalendarConfig` no longer throw on a falsy `eras` or `intercalary`** (`false`, `0`, `""`): it threw a `TypeError` where the profile says a reader refuses and shows bare numbers. It now returns `null`.
22
+ - **A step is an integer, so the reader now refuses** an era whose `start` or `end` is not a whole number, a `year_base` other than `0` or `1` (a string `"1"` printed as `"01"` before), and month or weekday names that are not strings. Atlas writes none of these; the Unity SDK refuses them the same way.
23
+
8
24
  ## [4.42.0] - 2026-10-20
9
25
 
10
26
  Schema 00.32.02 (Skeld, OW Council h58 #8811): repinned to schema-dist v0.32.2-dist.29.
package/dist/index.d.ts CHANGED
@@ -3999,7 +3999,12 @@ interface EraDomain {
3999
3999
  hi: number;
4000
4000
  }
4001
4001
  declare function resolveEraDomains(eras: CalendarEra[]): EraDomain[];
4002
- /** The era owning a step: domain containment; wild overlaps resolve to latest start (up wins ties). */
4002
+ /**
4003
+ * The era owning a step: domain containment; overlaps resolve to the latest start, then an
4004
+ * up era over a down one, then the later era in the list (the profile, calendar.md). The
4005
+ * comparator was `up ? -1 : 1` before 4.42.2: inconsistent for two eras of one direction,
4006
+ * so their order was the sort's, not the list's.
4007
+ */
4003
4008
  declare function eraForStep(cfg: CalendarConfig, step: number): CalendarEra | null;
4004
4009
  /** The display year for a step under an era (or the absolute year without one). */
4005
4010
  declare function displayYear(cfg: CalendarConfig, step: number, era: CalendarEra | null): number;
package/dist/index.js CHANGED
@@ -3001,18 +3001,21 @@ function readCalendarConfig(value) {
3001
3001
  const cfg = value;
3002
3002
  if (cfg.version !== 1 || typeof cfg.grain !== "string") return null;
3003
3003
  const months = cfg.bundles?.months;
3004
- if (months && (!Array.isArray(months.names) || !Array.isArray(months.lengths) || months.names.length !== months.lengths.length || months.names.length === 0)) return null;
3005
- if (cfg.eras && !Array.isArray(cfg.eras)) return null;
3006
- if (cfg.eras?.some((e) => typeof e?.name !== "string" || !Number.isFinite(e?.start))) return null;
3007
- if (cfg.intercalary && (!Array.isArray(cfg.intercalary) || cfg.intercalary.some((i) => typeof i?.name !== "string" || !Number.isInteger(i?.after_month)))) return null;
3004
+ if (months && (!Array.isArray(months.names) || !Array.isArray(months.lengths) || months.names.length !== months.lengths.length || months.names.length === 0 || !months.names.every(isString))) return null;
3005
+ if (cfg.eras != null && !Array.isArray(cfg.eras)) return null;
3006
+ if (cfg.eras?.some((e) => typeof e?.name !== "string" || !Number.isSafeInteger(e?.start) || e.end != null && !Number.isSafeInteger(e.end) || e.year_base != null && e.year_base !== 0 && e.year_base !== 1)) return null;
3007
+ if (cfg.intercalary != null && (!Array.isArray(cfg.intercalary) || cfg.intercalary.some((i) => typeof i?.name !== "string" || !Number.isInteger(i?.after_month)))) return null;
3008
3008
  if (months && !months.lengths.every(isPositiveInt)) return null;
3009
3009
  const year = cfg.bundles?.year;
3010
3010
  if (year != null && !isPositiveInt(year.steps)) return null;
3011
3011
  const week = cfg.bundles?.week;
3012
- if (week != null && (!isPositiveInt(week.length) || !Array.isArray(week.names))) return null;
3012
+ if (week != null && (!isPositiveInt(week.length) || !Array.isArray(week.names) || !week.names.every(isString))) return null;
3013
3013
  if (cfg.intercalary?.some((i) => i.every_years != null && !isPositiveInt(i.every_years))) return null;
3014
3014
  return cfg;
3015
3015
  }
3016
+ function isString(s) {
3017
+ return typeof s === "string";
3018
+ }
3016
3019
  function isPositiveInt(n) {
3017
3020
  return Number.isSafeInteger(n) && n >= 1;
3018
3021
  }
@@ -3075,7 +3078,9 @@ function eraForStep(cfg, step) {
3075
3078
  if (eras.length === 0) return null;
3076
3079
  const holding = resolveEraDomains(eras).filter((d) => step >= d.lo && step < d.hi);
3077
3080
  if (holding.length === 0) return null;
3078
- holding.sort((a, b) => b.era.start - a.era.start || ((a.era.direction ?? "up") === "up" ? -1 : 1));
3081
+ const place = new Map(eras.map((e, i) => [e, i]));
3082
+ const down = (e) => (e.direction ?? "up") === "down" ? 1 : 0;
3083
+ holding.sort((a, b) => b.era.start - a.era.start || down(a.era) - down(b.era) || (place.get(b.era) ?? 0) - (place.get(a.era) ?? 0));
3079
3084
  return holding[0].era;
3080
3085
  }
3081
3086
  function displayYear(cfg, step, era) {
@@ -3083,7 +3088,7 @@ function displayYear(cfg, step, era) {
3083
3088
  if (!era || era.restart === false) return abs;
3084
3089
  const base = era.year_base ?? 1;
3085
3090
  if ((era.direction ?? "up") === "down") {
3086
- return absoluteYear(cfg, era.start) - abs + base - 1;
3091
+ return absoluteYear(cfg, era.start - 1) - abs + base;
3087
3092
  }
3088
3093
  return abs - absoluteYear(cfg, era.start) + base;
3089
3094
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@onlyworlds/sdk",
3
- "version": "4.42.0",
3
+ "version": "4.42.2",
4
4
  "description": "TypeScript SDK for the OnlyWorlds API - build world-building applications with type safety",
5
5
  "type": "module",
6
6
  "exports": {