@nextera.one/tps-standard 0.5.34 → 0.7.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 (60) hide show
  1. package/CHANGELOG.md +88 -0
  2. package/README.md +133 -56
  3. package/dist/driver-manager.d.ts +34 -0
  4. package/dist/driver-manager.js +53 -0
  5. package/dist/driver-manager.js.map +1 -0
  6. package/dist/drivers/chinese.d.ts +25 -0
  7. package/dist/drivers/chinese.js +485 -0
  8. package/dist/drivers/chinese.js.map +1 -0
  9. package/dist/esm/date.js +170 -0
  10. package/dist/esm/date.js.map +1 -0
  11. package/dist/esm/driver-manager.js +49 -0
  12. package/dist/esm/driver-manager.js.map +1 -0
  13. package/dist/esm/drivers/chinese.js +481 -0
  14. package/dist/esm/drivers/chinese.js.map +1 -0
  15. package/dist/esm/drivers/gregorian.js +160 -0
  16. package/dist/esm/drivers/gregorian.js.map +1 -0
  17. package/dist/esm/drivers/hijri.js +184 -0
  18. package/dist/esm/drivers/hijri.js.map +1 -0
  19. package/dist/esm/drivers/holocene.js +115 -0
  20. package/dist/esm/drivers/holocene.js.map +1 -0
  21. package/dist/esm/drivers/julian.js +161 -0
  22. package/dist/esm/drivers/julian.js.map +1 -0
  23. package/dist/esm/drivers/persian.js +190 -0
  24. package/dist/esm/drivers/persian.js.map +1 -0
  25. package/dist/esm/drivers/tps.js +181 -0
  26. package/dist/esm/drivers/tps.js.map +1 -0
  27. package/dist/esm/drivers/unix.js +50 -0
  28. package/dist/esm/drivers/unix.js.map +1 -0
  29. package/dist/esm/index.js +873 -0
  30. package/dist/esm/index.js.map +1 -0
  31. package/dist/esm/types.js +28 -0
  32. package/dist/esm/types.js.map +1 -0
  33. package/dist/esm/uid.js +221 -0
  34. package/dist/esm/uid.js.map +1 -0
  35. package/dist/esm/utils/calendar.js +126 -0
  36. package/dist/esm/utils/calendar.js.map +1 -0
  37. package/dist/esm/utils/env.js +76 -0
  38. package/dist/esm/utils/env.js.map +1 -0
  39. package/dist/esm/utils/timezone.js +168 -0
  40. package/dist/esm/utils/timezone.js.map +1 -0
  41. package/dist/esm/utils/tps-string.js +160 -0
  42. package/dist/esm/utils/tps-string.js.map +1 -0
  43. package/dist/index.d.ts +91 -2
  44. package/dist/index.js +412 -132
  45. package/dist/index.js.map +1 -1
  46. package/dist/types.d.ts +19 -1
  47. package/dist/types.js +1 -0
  48. package/dist/types.js.map +1 -1
  49. package/dist/uid.js +1 -1
  50. package/dist/uid.js.map +1 -1
  51. package/dist/utils/timezone.d.ts +32 -0
  52. package/dist/utils/timezone.js +173 -0
  53. package/dist/utils/timezone.js.map +1 -0
  54. package/package.json +20 -5
  55. package/src/driver-manager.ts +54 -0
  56. package/src/drivers/chinese.ts +542 -0
  57. package/src/index.ts +379 -123
  58. package/src/types.ts +26 -2
  59. package/src/uid.ts +2 -2
  60. package/src/utils/timezone.ts +182 -0
package/src/types.ts CHANGED
@@ -15,6 +15,7 @@ export const DefaultCalendars = {
15
15
  JUL: "jul",
16
16
  HOLO: "holo",
17
17
  UNIX: "unix",
18
+ CHIN: "chin",
18
19
  } as const;
19
20
 
20
21
  /**
@@ -53,13 +54,32 @@ export interface TPSComponents {
53
54
  plusCode?: string;
54
55
  what3words?: string;
55
56
 
57
+ // --- SPATIAL: Place layer (P:cc=JO,ci=AMM,...) ---
58
+ /** ISO 3166-1 alpha-2 country code, e.g. "JO" → P:cc=JO */
59
+ placeCountryCode?: string;
60
+ /** Full country name, e.g. "Jordan" → P:cn=Jordan */
61
+ placeCountryName?: string;
62
+ /** City IATA/ISO code, e.g. "AMM" → P:ci=AMM */
63
+ placeCityCode?: string;
64
+ /** Full city name, e.g. "Amman" → P:ct=Amman */
65
+ placeCityName?: string;
66
+
67
+ // --- SPATIAL: Network / Digital Location ---
68
+ /** IPv4 address (net:ip4:x or NIP4:x) */
69
+ ipv4?: string;
70
+ /** IPv6 address (net:ip6:x or NIP6:x) */
71
+ ipv6?: string;
72
+ /** Logical node / host name (node:api-1 or NODE:api-1) */
73
+ nodeName?: string;
74
+
56
75
  // --- SPATIAL: Structural Anchors ---
57
76
  building?: string;
58
77
  floor?: string;
59
78
  room?: string;
79
+ door?: string;
60
80
  zone?: string;
61
81
 
62
- /** Raw pre-@ space anchor */
82
+ /** Raw pre-@ space anchor (generic/legacy/planet/adm) */
63
83
  spaceAnchor?: string;
64
84
 
65
85
  // --- SPATIAL: Privacy Markers ---
@@ -71,9 +91,13 @@ export interface TPSComponents {
71
91
  actor?: string;
72
92
  signature?: string;
73
93
 
74
- // --- CONTEXT ---
94
+ // --- EXTENSIONS (;KEY:val or ;key=val after T: tokens, before #) ---
75
95
  extensions?: Record<string, string>;
76
96
 
97
+ // --- CONTEXT (#C:key=val;key=val in fragment) ---
98
+ /** Structured context key-value pairs from the #C: fragment block */
99
+ context?: Record<string, string>;
100
+
77
101
  order?: TimeOrder;
78
102
  }
79
103
 
package/src/uid.ts CHANGED
@@ -2,9 +2,9 @@
2
2
  * TPS-UID v1 — Temporal Positioning System Identifier (Binary Reversible)
3
3
  */
4
4
 
5
- import { TPSComponents, DefaultCalendars, TimeOrder } from "./types";
6
- import { Env } from "./utils/env";
7
5
  import { TPS } from "./index";
6
+ import { DefaultCalendars, TimeOrder } from "./types";
7
+ import { Env } from "./utils/env";
8
8
 
9
9
  /**
10
10
  * Decoded result from TPSUID7RB binary format.
@@ -0,0 +1,182 @@
1
+ /**
2
+ * Timezone Utilities
3
+ *
4
+ * Provides lightweight, zero-dependency helpers for converting between
5
+ * UTC timestamps and local timestamps in a given IANA timezone or
6
+ * fixed UTC offset.
7
+ *
8
+ * Used by `TPS.toDate()` when the parsed extensions include a `tz` key.
9
+ *
10
+ * Examples:
11
+ * tz=Asia/Tehran → IANA timezone name
12
+ * tz=+03:30 → fixed UTC offset
13
+ * tz=IRST → abbreviated names (best-effort, common ones mapped)
14
+ */
15
+
16
+ /** Map of common abbreviated timezone names to IANA names. */
17
+ const TZ_ABBR: Record<string, string> = {
18
+ // Middle East
19
+ IRST: "Asia/Tehran",
20
+ IRDT: "Asia/Tehran",
21
+ AST: "Asia/Riyadh",
22
+ AST3: "Asia/Riyadh",
23
+ // Europe
24
+ CET: "Europe/Paris",
25
+ CEST: "Europe/Paris",
26
+ EET: "Europe/Athens",
27
+ EEST: "Europe/Athens",
28
+ WET: "Europe/Lisbon",
29
+ WEST: "Europe/Lisbon",
30
+ // Americas
31
+ EST: "America/New_York",
32
+ EDT: "America/New_York",
33
+ CST: "America/Chicago",
34
+ CDT: "America/Chicago",
35
+ MST: "America/Denver",
36
+ MDT: "America/Denver",
37
+ PST: "America/Los_Angeles",
38
+ PDT: "America/Los_Angeles",
39
+ // Asia Pacific
40
+ JST: "Asia/Tokyo",
41
+ KST: "Asia/Seoul",
42
+ IST: "Asia/Kolkata",
43
+ CST8: "Asia/Shanghai",
44
+ AEST: "Australia/Sydney",
45
+ AEDT: "Australia/Sydney",
46
+ // UTC variants
47
+ UTC: "UTC",
48
+ GMT: "UTC",
49
+ Z: "UTC",
50
+ };
51
+
52
+ /**
53
+ * Parse a `tz` string into an IANA timezone name, or return null if unrecognized.
54
+ */
55
+ function resolveIANA(tz: string): string | null {
56
+ if (!tz) return null;
57
+
58
+ // Direct IANA name (e.g. "Asia/Tehran")
59
+ if (tz.includes("/")) return tz;
60
+
61
+ // Common abbreviation lookup
62
+ const abbr = TZ_ABBR[tz.toUpperCase()];
63
+ if (abbr) return abbr;
64
+
65
+ return null;
66
+ }
67
+
68
+ /**
69
+ * Parses a fixed offset string like "+03:30", "-05:00", "+0530" into ms.
70
+ * Returns NaN if the string is not a valid offset.
71
+ */
72
+ function parseFixedOffset(tz: string): number {
73
+ const m = tz.match(/^([+-])(\d{1,2}):?(\d{2})$/);
74
+ if (!m) return NaN;
75
+ const sign = m[1] === "+" ? 1 : -1;
76
+ const h = parseInt(m[2], 10);
77
+ const min = parseInt(m[3], 10);
78
+ return sign * (h * 60 + min) * 60_000;
79
+ }
80
+
81
+ /**
82
+ * Returns the UTC offset in milliseconds for a given IANA timezone at a
83
+ * specific UTC moment. Uses `Intl.DateTimeFormat` for correctness.
84
+ *
85
+ * Returns 0 (UTC) if the timezone is unrecognised by the runtime.
86
+ */
87
+ function getIANAOffsetMs(ianaName: string, atUtcMs: number): number {
88
+ try {
89
+ // Build a formatter that reports both UTC and local time parts
90
+ const fmt = new Intl.DateTimeFormat("en-US", {
91
+ timeZone: ianaName,
92
+ year: "numeric",
93
+ month: "2-digit",
94
+ day: "2-digit",
95
+ hour: "2-digit",
96
+ minute: "2-digit",
97
+ second: "2-digit",
98
+ hour12: false,
99
+ });
100
+ const parts = Object.fromEntries(
101
+ fmt.formatToParts(new Date(atUtcMs)).map((p) => [p.type, p.value]),
102
+ );
103
+
104
+ // Reconstruct the local time as UTC
105
+ const localMs = Date.UTC(
106
+ parseInt(parts.year),
107
+ parseInt(parts.month) - 1,
108
+ parseInt(parts.day),
109
+ parseInt(parts.hour === "24" ? "0" : parts.hour),
110
+ parseInt(parts.minute),
111
+ parseInt(parts.second),
112
+ );
113
+ return localMs - atUtcMs;
114
+ } catch {
115
+ return 0;
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Given a UTC timestamp (ms), returns the equivalent *local* millisecond
121
+ * value for the given `tz` string.
122
+ *
123
+ * This is useful for display: `utcMs + offsetMs` gives local wall-clock time.
124
+ */
125
+ export function utcToLocal(utcMs: number, tz: string): number {
126
+ // Try fixed offset first (e.g. "+03:30")
127
+ const fixed = parseFixedOffset(tz);
128
+ if (!isNaN(fixed)) return utcMs + fixed;
129
+
130
+ const iana = resolveIANA(tz);
131
+ if (!iana) return utcMs; // Unknown tz — return UTC unchanged
132
+
133
+ return utcMs + getIANAOffsetMs(iana, utcMs);
134
+ }
135
+
136
+ /**
137
+ * Given a *local* timestamp (ms) in `tz`, returns the equivalent UTC ms.
138
+ *
139
+ * Used when converting a calendar date expressed in local time back to UTC.
140
+ */
141
+ export function localToUtc(localMs: number, tz: string): number {
142
+ // Try fixed offset first
143
+ const fixed = parseFixedOffset(tz);
144
+ if (!isNaN(fixed)) return localMs - fixed;
145
+
146
+ const iana = resolveIANA(tz);
147
+ if (!iana) return localMs;
148
+
149
+ // Approximation: compute the offset at the approximate UTC moment
150
+ // (offset iteration is overkill for a scheduling library)
151
+ const approxUtcMs = localMs - getIANAOffsetMs(iana, localMs);
152
+ // One correction pass for DST edge-cases
153
+ const correctedOffset = getIANAOffsetMs(iana, approxUtcMs);
154
+ return localMs - correctedOffset;
155
+ }
156
+
157
+ /**
158
+ * Returns the UTC offset string (e.g. "+03:30") for a given IANA timezone
159
+ * at the current moment. Useful for formatting and display.
160
+ */
161
+ export function getOffsetString(tz: string, atUtcMs = Date.now()): string {
162
+ // Fast-path for UTC/GMT/Z
163
+ const upper = tz.toUpperCase();
164
+ if (upper === "UTC" || upper === "GMT" || upper === "Z") return "+00:00";
165
+
166
+ const fixed = parseFixedOffset(tz);
167
+ if (!isNaN(fixed)) return tz;
168
+
169
+ const iana = resolveIANA(tz);
170
+ if (!iana) return "+00:00";
171
+
172
+ const offsetMs = getIANAOffsetMs(iana, atUtcMs);
173
+ const sign = offsetMs >= 0 ? "+" : "-";
174
+ const abs = Math.abs(offsetMs);
175
+ const h = Math.floor(abs / 3_600_000)
176
+ .toString()
177
+ .padStart(2, "0");
178
+ const m = Math.floor((abs % 3_600_000) / 60_000)
179
+ .toString()
180
+ .padStart(2, "0");
181
+ return `${sign}${h}:${m}`;
182
+ }