@classytic/primitives 0.19.0 → 0.20.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.
- package/CHANGELOG.md +906 -751
- package/README.md +160 -159
- package/dist/approval.d.mts +49 -10
- package/dist/approval.mjs +44 -10
- package/dist/bank-transaction.d.mts +1 -1
- package/dist/cadence-BFQVC1Qp.d.mts +107 -0
- package/dist/cadence.d.mts +1 -92
- package/dist/cadence.mjs +133 -4
- package/dist/calendar-B6fm-FbR.d.mts +46 -0
- package/dist/calendar.d.mts +1 -45
- package/dist/canonical.mjs +17 -0
- package/dist/context.d.mts +28 -1
- package/dist/currency.d.mts +2 -2
- package/dist/currency.mjs +134 -19
- package/dist/event-infra.d.mts +1 -34
- package/dist/event-infra.mjs +16 -46
- package/dist/idempotency.d.mts +253 -0
- package/dist/idempotency.mjs +226 -0
- package/dist/memory-outbox.d.mts +64 -0
- package/dist/memory-outbox.mjs +172 -0
- package/dist/monetization.d.mts +1 -1
- package/dist/money-DPo9fLBi.d.mts +347 -0
- package/dist/money.d.mts +1 -140
- package/dist/money.mjs +6 -15
- package/dist/outbox.d.mts +49 -1
- package/dist/outbox.mjs +64 -1
- package/dist/payment-events.d.mts +132 -4
- package/dist/payment-events.mjs +22 -2
- package/dist/payment-gateway.d.mts +210 -7
- package/dist/payment-gateway.mjs +18 -1
- package/dist/period.d.mts +138 -7
- package/dist/period.mjs +316 -5
- package/dist/person-parse.d.mts +82 -0
- package/dist/person-parse.mjs +109 -0
- package/dist/proration.d.mts +2 -2
- package/dist/proration.mjs +18 -6
- package/dist/sla-policy.d.mts +1 -1
- package/dist/state-machine.mjs +13 -0
- package/dist/suspension.d.mts +1 -1
- package/dist/timezone-tlG7ygwx.d.mts +114 -0
- package/dist/timezone.d.mts +2 -100
- package/dist/timezone.mjs +38 -3
- package/dist/unit-cost-rate.d.mts +1 -2
- package/package.json +244 -232
- package/dist/currency-BCJnJBlb.d.mts +0 -119
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import { t as Brand } from "./brand-LLXqoh5J.mjs";
|
|
2
|
+
import { s as IsoWeekday } from "./cadence-BFQVC1Qp.mjs";
|
|
3
|
+
import { t as UtcOffsetMinutes } from "./calendar-B6fm-FbR.mjs";
|
|
4
|
+
|
|
5
|
+
//#region src/scheduling/timezone.d.ts
|
|
6
|
+
declare class TimeZoneError extends Error {
|
|
7
|
+
constructor(message: string);
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Is `zone` a valid IANA timezone name on this runtime's ICU data?
|
|
11
|
+
* Use at BOOT to validate host config (an offer's `timezone`, an org
|
|
12
|
+
* setting) — fail loud at wiring time, not on the first localized read.
|
|
13
|
+
*/
|
|
14
|
+
declare function isValidTimeZone(zone: string): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Every IANA timezone name this runtime supports — the data source for a
|
|
17
|
+
* Google-Calendar-style zone picker. Straight from ICU via
|
|
18
|
+
* `Intl.supportedValuesOf` (Node >= 18); no bundled tz list to go stale.
|
|
19
|
+
*
|
|
20
|
+
* UIs typically label each entry with its current offset:
|
|
21
|
+
* `listTimeZones().map((z) => ({ zone: z, label: zoneOffsetLabel(now, z) }))`.
|
|
22
|
+
*/
|
|
23
|
+
declare function listTimeZones(): readonly string[];
|
|
24
|
+
/**
|
|
25
|
+
* The zone's UTC offset AT `instant`, in minutes east of UTC — DST-exact.
|
|
26
|
+
* `zoneOffsetMinutes(july, 'Europe/London')` → 60; `(january, …)` → 0;
|
|
27
|
+
* `(any, 'Asia/Dhaka')` → 360.
|
|
28
|
+
*
|
|
29
|
+
* This is the value `/calendar`'s docstring tells hosts to "resolve and pass
|
|
30
|
+
* in": `startOfMonth(instant, zoneOffsetMinutes(instant, zone))`.
|
|
31
|
+
*/
|
|
32
|
+
declare function zoneOffsetMinutes(instant: Date, zone: string): UtcOffsetMinutes;
|
|
33
|
+
/**
|
|
34
|
+
* The zone's offset label AT `instant` — `'GMT+06:00'` / `'GMT-05:30'` /
|
|
35
|
+
* `'GMT'`. Ready-made display text for zone pickers.
|
|
36
|
+
*/
|
|
37
|
+
declare function zoneOffsetLabel(instant: Date, zone: string): string;
|
|
38
|
+
interface LocalTimeParts {
|
|
39
|
+
/** ISO weekday in the zone — 1=Mon … 7=Sun (matches `/cadence`). */
|
|
40
|
+
isoWeekday: IsoWeekday;
|
|
41
|
+
/** Hour of day in the zone, 0–23. */
|
|
42
|
+
hour: number;
|
|
43
|
+
/** Minute of hour, 0–59. */
|
|
44
|
+
minute: number;
|
|
45
|
+
/** `hour * 60 + minute` — the shape "HH:MM window" checks want. */
|
|
46
|
+
minutesOfDay: number;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* The wall-clock weekday + time of `instant` in `zone` — what pricing
|
|
50
|
+
* schedules ("peak Fri 17:00–22:00"), slot grids, and working-hours checks
|
|
51
|
+
* evaluate against. DST-exact per instant.
|
|
52
|
+
*/
|
|
53
|
+
declare function localTimeParts(instant: Date, zone: string): LocalTimeParts;
|
|
54
|
+
/**
|
|
55
|
+
* A calendar day — `'YYYY-MM-DD'` — with NO time and NO zone until one is
|
|
56
|
+
* bound. The type for hotel nights, POS business dates, statement periods,
|
|
57
|
+
* VAT filing years. Lexicographic order == chronological order, so it's
|
|
58
|
+
* index- and range-query-friendly as a Mongo string key.
|
|
59
|
+
*/
|
|
60
|
+
type CivilDate = Brand<string, 'CivilDate'>;
|
|
61
|
+
/** Runtime guard for external input. */
|
|
62
|
+
declare function isCivilDate(value: unknown): value is CivilDate;
|
|
63
|
+
/** Validate + brand a `'YYYY-MM-DD'` string. Throws on malformed input. */
|
|
64
|
+
declare function civilDate(value: string): CivilDate;
|
|
65
|
+
/**
|
|
66
|
+
* The calendar day `instant` falls on IN `zone` — e.g. the POS business
|
|
67
|
+
* date: `civilDateOf(new Date(), 'Asia/Dhaka')`. Never depends on the
|
|
68
|
+
* server's TZ env.
|
|
69
|
+
*/
|
|
70
|
+
declare function civilDateOf(instant: Date, zone: string): CivilDate;
|
|
71
|
+
/**
|
|
72
|
+
* Bind a civil date (+ optional wall time) to a zone → the exact instant.
|
|
73
|
+
* `civilDateToInstant(night, hotelZone, { hour: 14 })` = check-in instant;
|
|
74
|
+
* with no `time`, local midnight — the DST-exact "start of that day in that
|
|
75
|
+
* zone".
|
|
76
|
+
*
|
|
77
|
+
* Two-pass offset resolution: the offset is looked up AT the candidate
|
|
78
|
+
* instant, then re-checked, so days where a DST transition sits between the
|
|
79
|
+
* wall time and the first guess still resolve correctly. Honest limit: a
|
|
80
|
+
* wall time that does not exist (inside a spring-forward gap) resolves to
|
|
81
|
+
* the instant the shifted clock reaches — the same choice Temporal's
|
|
82
|
+
* `disambiguation: 'compatible'` makes.
|
|
83
|
+
*/
|
|
84
|
+
declare function civilDateToInstant(cd: CivilDate, zone: string, time?: {
|
|
85
|
+
hour?: number;
|
|
86
|
+
minute?: number;
|
|
87
|
+
second?: number;
|
|
88
|
+
millisecond?: number;
|
|
89
|
+
}): Date;
|
|
90
|
+
/**
|
|
91
|
+
* Pure calendar-day arithmetic — `addCivilDays('2026-02-28', 1)` →
|
|
92
|
+
* `'2026-03-01'`. Zone-free by definition (a civil date has no zone);
|
|
93
|
+
* use it to iterate hotel nights / statement days.
|
|
94
|
+
*/
|
|
95
|
+
declare function addCivilDays(cd: CivilDate, days: number): CivilDate;
|
|
96
|
+
/**
|
|
97
|
+
* Whole days from `a` to `b` (positive when `b` is later) — the NIGHTS
|
|
98
|
+
* count for a `[checkIn, checkOut)` stay expressed as civil dates.
|
|
99
|
+
*/
|
|
100
|
+
/**
|
|
101
|
+
* The ISO-8601 week a civil date belongs to, as `YYYY-Www`.
|
|
102
|
+
*
|
|
103
|
+
* Zone-free by definition — a civil date has no zone — so callers resolve the
|
|
104
|
+
* date in their business timezone FIRST (`civilDateOf`) and label it here.
|
|
105
|
+
*
|
|
106
|
+
* ISO week 1 is the week containing the first Thursday, which means the week
|
|
107
|
+
* YEAR can differ from the date's own: 2025-12-29 is `2026-W01`. Naive
|
|
108
|
+
* "day-of-year / 7" numbering gets that wrong every few years, silently
|
|
109
|
+
* splitting one business week across two report buckets.
|
|
110
|
+
*/
|
|
111
|
+
declare function isoWeekOfCivilDate(cd: CivilDate): string;
|
|
112
|
+
declare function civilDaysBetween(a: CivilDate, b: CivilDate): number;
|
|
113
|
+
//#endregion
|
|
114
|
+
export { civilDate as a, civilDaysBetween as c, isoWeekOfCivilDate as d, listTimeZones as f, zoneOffsetMinutes as h, addCivilDays as i, isCivilDate as l, zoneOffsetLabel as m, LocalTimeParts as n, civilDateOf as o, localTimeParts as p, TimeZoneError as r, civilDateToInstant as s, CivilDate as t, isValidTimeZone as u };
|
package/dist/timezone.d.mts
CHANGED
|
@@ -1,100 +1,2 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
|
|
3
|
-
import { UtcOffsetMinutes } from "./calendar.mjs";
|
|
4
|
-
|
|
5
|
-
//#region src/scheduling/timezone.d.ts
|
|
6
|
-
declare class TimeZoneError extends Error {
|
|
7
|
-
constructor(message: string);
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* Is `zone` a valid IANA timezone name on this runtime's ICU data?
|
|
11
|
-
* Use at BOOT to validate host config (an offer's `timezone`, an org
|
|
12
|
-
* setting) — fail loud at wiring time, not on the first localized read.
|
|
13
|
-
*/
|
|
14
|
-
declare function isValidTimeZone(zone: string): boolean;
|
|
15
|
-
/**
|
|
16
|
-
* Every IANA timezone name this runtime supports — the data source for a
|
|
17
|
-
* Google-Calendar-style zone picker. Straight from ICU via
|
|
18
|
-
* `Intl.supportedValuesOf` (Node >= 18); no bundled tz list to go stale.
|
|
19
|
-
*
|
|
20
|
-
* UIs typically label each entry with its current offset:
|
|
21
|
-
* `listTimeZones().map((z) => ({ zone: z, label: zoneOffsetLabel(now, z) }))`.
|
|
22
|
-
*/
|
|
23
|
-
declare function listTimeZones(): readonly string[];
|
|
24
|
-
/**
|
|
25
|
-
* The zone's UTC offset AT `instant`, in minutes east of UTC — DST-exact.
|
|
26
|
-
* `zoneOffsetMinutes(july, 'Europe/London')` → 60; `(january, …)` → 0;
|
|
27
|
-
* `(any, 'Asia/Dhaka')` → 360.
|
|
28
|
-
*
|
|
29
|
-
* This is the value `/calendar`'s docstring tells hosts to "resolve and pass
|
|
30
|
-
* in": `startOfMonth(instant, zoneOffsetMinutes(instant, zone))`.
|
|
31
|
-
*/
|
|
32
|
-
declare function zoneOffsetMinutes(instant: Date, zone: string): UtcOffsetMinutes;
|
|
33
|
-
/**
|
|
34
|
-
* The zone's offset label AT `instant` — `'GMT+06:00'` / `'GMT-05:30'` /
|
|
35
|
-
* `'GMT'`. Ready-made display text for zone pickers.
|
|
36
|
-
*/
|
|
37
|
-
declare function zoneOffsetLabel(instant: Date, zone: string): string;
|
|
38
|
-
interface LocalTimeParts {
|
|
39
|
-
/** ISO weekday in the zone — 1=Mon … 7=Sun (matches `/cadence`). */
|
|
40
|
-
isoWeekday: IsoWeekday;
|
|
41
|
-
/** Hour of day in the zone, 0–23. */
|
|
42
|
-
hour: number;
|
|
43
|
-
/** Minute of hour, 0–59. */
|
|
44
|
-
minute: number;
|
|
45
|
-
/** `hour * 60 + minute` — the shape "HH:MM window" checks want. */
|
|
46
|
-
minutesOfDay: number;
|
|
47
|
-
}
|
|
48
|
-
/**
|
|
49
|
-
* The wall-clock weekday + time of `instant` in `zone` — what pricing
|
|
50
|
-
* schedules ("peak Fri 17:00–22:00"), slot grids, and working-hours checks
|
|
51
|
-
* evaluate against. DST-exact per instant.
|
|
52
|
-
*/
|
|
53
|
-
declare function localTimeParts(instant: Date, zone: string): LocalTimeParts;
|
|
54
|
-
/**
|
|
55
|
-
* A calendar day — `'YYYY-MM-DD'` — with NO time and NO zone until one is
|
|
56
|
-
* bound. The type for hotel nights, POS business dates, statement periods,
|
|
57
|
-
* VAT filing years. Lexicographic order == chronological order, so it's
|
|
58
|
-
* index- and range-query-friendly as a Mongo string key.
|
|
59
|
-
*/
|
|
60
|
-
type CivilDate = Brand<string, 'CivilDate'>;
|
|
61
|
-
/** Runtime guard for external input. */
|
|
62
|
-
declare function isCivilDate(value: unknown): value is CivilDate;
|
|
63
|
-
/** Validate + brand a `'YYYY-MM-DD'` string. Throws on malformed input. */
|
|
64
|
-
declare function civilDate(value: string): CivilDate;
|
|
65
|
-
/**
|
|
66
|
-
* The calendar day `instant` falls on IN `zone` — e.g. the POS business
|
|
67
|
-
* date: `civilDateOf(new Date(), 'Asia/Dhaka')`. Never depends on the
|
|
68
|
-
* server's TZ env.
|
|
69
|
-
*/
|
|
70
|
-
declare function civilDateOf(instant: Date, zone: string): CivilDate;
|
|
71
|
-
/**
|
|
72
|
-
* Bind a civil date (+ optional wall time) to a zone → the exact instant.
|
|
73
|
-
* `civilDateToInstant(night, hotelZone, { hour: 14 })` = check-in instant;
|
|
74
|
-
* with no `time`, local midnight — the DST-exact "start of that day in that
|
|
75
|
-
* zone".
|
|
76
|
-
*
|
|
77
|
-
* Two-pass offset resolution: the offset is looked up AT the candidate
|
|
78
|
-
* instant, then re-checked, so days where a DST transition sits between the
|
|
79
|
-
* wall time and the first guess still resolve correctly. Honest limit: a
|
|
80
|
-
* wall time that does not exist (inside a spring-forward gap) resolves to
|
|
81
|
-
* the instant the shifted clock reaches — the same choice Temporal's
|
|
82
|
-
* `disambiguation: 'compatible'` makes.
|
|
83
|
-
*/
|
|
84
|
-
declare function civilDateToInstant(cd: CivilDate, zone: string, time?: {
|
|
85
|
-
hour?: number;
|
|
86
|
-
minute?: number;
|
|
87
|
-
}): Date;
|
|
88
|
-
/**
|
|
89
|
-
* Pure calendar-day arithmetic — `addCivilDays('2026-02-28', 1)` →
|
|
90
|
-
* `'2026-03-01'`. Zone-free by definition (a civil date has no zone);
|
|
91
|
-
* use it to iterate hotel nights / statement days.
|
|
92
|
-
*/
|
|
93
|
-
declare function addCivilDays(cd: CivilDate, days: number): CivilDate;
|
|
94
|
-
/**
|
|
95
|
-
* Whole days from `a` to `b` (positive when `b` is later) — the NIGHTS
|
|
96
|
-
* count for a `[checkIn, checkOut)` stay expressed as civil dates.
|
|
97
|
-
*/
|
|
98
|
-
declare function civilDaysBetween(a: CivilDate, b: CivilDate): number;
|
|
99
|
-
//#endregion
|
|
100
|
-
export { CivilDate, LocalTimeParts, TimeZoneError, addCivilDays, civilDate, civilDateOf, civilDateToInstant, civilDaysBetween, isCivilDate, isValidTimeZone, listTimeZones, localTimeParts, zoneOffsetLabel, zoneOffsetMinutes };
|
|
1
|
+
import { a as civilDate, c as civilDaysBetween, d as isoWeekOfCivilDate, f as listTimeZones, h as zoneOffsetMinutes, i as addCivilDays, l as isCivilDate, m as zoneOffsetLabel, n as LocalTimeParts, o as civilDateOf, p as localTimeParts, r as TimeZoneError, s as civilDateToInstant, t as CivilDate, u as isValidTimeZone } from "./timezone-tlG7ygwx.mjs";
|
|
2
|
+
export { CivilDate, LocalTimeParts, TimeZoneError, addCivilDays, civilDate, civilDateOf, civilDateToInstant, civilDaysBetween, isCivilDate, isValidTimeZone, isoWeekOfCivilDate, listTimeZones, localTimeParts, zoneOffsetLabel, zoneOffsetMinutes };
|
package/dist/timezone.mjs
CHANGED
|
@@ -78,7 +78,19 @@ function listTimeZones() {
|
|
|
78
78
|
cachedZones = Object.freeze(intl.supportedValuesOf("timeZone"));
|
|
79
79
|
return cachedZones;
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
/**
|
|
82
|
+
* ANCHORED on purpose.
|
|
83
|
+
*
|
|
84
|
+
* The unanchored form (`/GMT(?:([+-])(\d{2}):(\d{2}))?/`) made the offset group
|
|
85
|
+
* OPTIONAL *and* skippable: any label the runtime emits that this pattern cannot
|
|
86
|
+
* fully parse — `'GMT+5:30'` from an ICU build that does not zero-pad, or a
|
|
87
|
+
* locale that prefixes text — still matched the bare `GMT` alternative and
|
|
88
|
+
* resolved to offset **0**. A half-read offset became "UTC" with no error, which
|
|
89
|
+
* silently shifts every business-day boundary derived from it. Anchoring makes an
|
|
90
|
+
* unrecognised label throw instead; `\d{1,2}` accepts the unpadded variant rather
|
|
91
|
+
* than mis-reading it.
|
|
92
|
+
*/
|
|
93
|
+
const OFFSET_RE = /^GMT(?:([+-])(\d{1,2}):(\d{2}))?$/;
|
|
82
94
|
/**
|
|
83
95
|
* The zone's UTC offset AT `instant`, in minutes east of UTC — DST-exact.
|
|
84
96
|
* `zoneOffsetMinutes(july, 'Europe/London')` → 60; `(january, …)` → 0;
|
|
@@ -204,7 +216,9 @@ function civilDateToInstant(cd, zone, time = {}) {
|
|
|
204
216
|
if (!m) throw new TimeZoneError(`Invalid civil date '${cd}'.`);
|
|
205
217
|
const hour = time.hour ?? 0;
|
|
206
218
|
const minute = time.minute ?? 0;
|
|
207
|
-
const
|
|
219
|
+
const second = time.second ?? 0;
|
|
220
|
+
const millisecond = time.millisecond ?? 0;
|
|
221
|
+
const wallAsUtc = Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]), hour, minute, second, millisecond);
|
|
208
222
|
const firstOffset = zoneOffsetMinutes(new Date(wallAsUtc), zone);
|
|
209
223
|
let instantMs = wallAsUtc - firstOffset * MINUTE_MS;
|
|
210
224
|
const refined = zoneOffsetMinutes(new Date(instantMs), zone);
|
|
@@ -226,6 +240,27 @@ function addCivilDays(cd, days) {
|
|
|
226
240
|
* Whole days from `a` to `b` (positive when `b` is later) — the NIGHTS
|
|
227
241
|
* count for a `[checkIn, checkOut)` stay expressed as civil dates.
|
|
228
242
|
*/
|
|
243
|
+
/**
|
|
244
|
+
* The ISO-8601 week a civil date belongs to, as `YYYY-Www`.
|
|
245
|
+
*
|
|
246
|
+
* Zone-free by definition — a civil date has no zone — so callers resolve the
|
|
247
|
+
* date in their business timezone FIRST (`civilDateOf`) and label it here.
|
|
248
|
+
*
|
|
249
|
+
* ISO week 1 is the week containing the first Thursday, which means the week
|
|
250
|
+
* YEAR can differ from the date's own: 2025-12-29 is `2026-W01`. Naive
|
|
251
|
+
* "day-of-year / 7" numbering gets that wrong every few years, silently
|
|
252
|
+
* splitting one business week across two report buckets.
|
|
253
|
+
*/
|
|
254
|
+
function isoWeekOfCivilDate(cd) {
|
|
255
|
+
const m = CIVIL_RE.exec(cd);
|
|
256
|
+
if (!m) throw new TimeZoneError(`Invalid civil date '${cd}'.`);
|
|
257
|
+
const utc = Date.UTC(Number(m[1]), Number(m[2]) - 1, Number(m[3]));
|
|
258
|
+
const dow = new Date(utc).getUTCDay() || 7;
|
|
259
|
+
const thursday = new Date(utc + (4 - dow) * 864e5);
|
|
260
|
+
const weekYear = thursday.getUTCFullYear();
|
|
261
|
+
const week = Math.floor((thursday.getTime() - Date.UTC(weekYear, 0, 1)) / 864e5 / 7) + 1;
|
|
262
|
+
return `${weekYear}-W${String(week).padStart(2, "0")}`;
|
|
263
|
+
}
|
|
229
264
|
function civilDaysBetween(a, b) {
|
|
230
265
|
const pa = CIVIL_RE.exec(a);
|
|
231
266
|
const pb = CIVIL_RE.exec(b);
|
|
@@ -235,4 +270,4 @@ function civilDaysBetween(a, b) {
|
|
|
235
270
|
return Math.round((mb - ma) / 864e5);
|
|
236
271
|
}
|
|
237
272
|
//#endregion
|
|
238
|
-
export { TimeZoneError, addCivilDays, civilDate, civilDateOf, civilDateToInstant, civilDaysBetween, isCivilDate, isValidTimeZone, listTimeZones, localTimeParts, zoneOffsetLabel, zoneOffsetMinutes };
|
|
273
|
+
export { TimeZoneError, addCivilDays, civilDate, civilDateOf, civilDateToInstant, civilDaysBetween, isCivilDate, isValidTimeZone, isoWeekOfCivilDate, listTimeZones, localTimeParts, zoneOffsetLabel, zoneOffsetMinutes };
|
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { MinorUnits } from "./money.mjs";
|
|
1
|
+
import { t as MinorUnits, w as CurrencyCode } from "./money-DPo9fLBi.mjs";
|
|
3
2
|
|
|
4
3
|
//#region src/money/unit-cost-rate.d.ts
|
|
5
4
|
/** Fixed, ecosystem-wide rate scale: 6 decimal places below the minor unit. */
|