hazo_core 2.0.3 → 2.3.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/README.md CHANGED
@@ -70,8 +70,8 @@ import { loadConfig, defineConfig, createLogger, createDebug,
70
70
 
71
71
  ```ts
72
72
  import { withRetry, isUuid, parseListLimit, parseListOffset,
73
- createDebouncedSaver } from 'hazo_core';
74
- // all five are env-agnostic and also available from 'hazo_core/client'
73
+ createDebouncedSaver, rateLimit, withRateLimit, getClientIp } from 'hazo_core';
74
+ // all are env-agnostic and also available from 'hazo_core/client'
75
75
  ```
76
76
 
77
77
  ### Browser-safe subset
@@ -7,6 +7,10 @@
7
7
  ; Override with HAZO_INCLUDE_STACK=1 to force on.
8
8
  include_stack = false
9
9
 
10
+ [format]
11
+ ; BCP 47 locale for number/currency/date formatting (default: en-AU)
12
+ ; locale = en-AU
13
+
10
14
  [env]
11
15
  ; This section is an example of the per-env overlay convention.
12
16
  ; Create hazo_core_config.<env>.ini alongside this file to override values
@@ -0,0 +1,49 @@
1
+ /** Options for {@link rateLimit}. */
2
+ export interface RateLimitOptions {
3
+ /** Bucket identifier (e.g. IP address or user ID). */
4
+ key: string;
5
+ /** Namespace / feature name (prevents cross-feature key collisions). */
6
+ scope: string;
7
+ /** Maximum requests allowed within the window. */
8
+ limit: number;
9
+ /** Window duration in milliseconds. */
10
+ window_ms: number;
11
+ }
12
+ export type RateLimitResult = {
13
+ ok: true;
14
+ } | {
15
+ ok: false;
16
+ retry_after_seconds: number;
17
+ };
18
+ /**
19
+ * Fixed-window token-bucket check. Increments the bucket for `scope:key` and
20
+ * reports whether the caller is still under `limit` within `window_ms`.
21
+ *
22
+ * @example rateLimit({ key: '1.2.3.4', scope: 'login', limit: 5, window_ms: 60_000 })
23
+ */
24
+ export declare function rateLimit(opts: RateLimitOptions): RateLimitResult;
25
+ /** Clear all buckets. Used in tests only. */
26
+ export declare function _clearBuckets(): void;
27
+ type RateLimitRouteHandler = (req: Request, ...args: unknown[]) => Promise<Response> | Response;
28
+ /**
29
+ * Wraps an HTTP route handler with rate limiting. Returns 429 with
30
+ * `Retry-After`/`X-RateLimit-Limit` headers when the limit is exceeded.
31
+ *
32
+ * Keys by client IP (`getClientIp`) by default; pass `getKey` to key by
33
+ * something else (e.g. a session/user id).
34
+ *
35
+ * Does NOT import from 'next' — uses the standard Request/Response types.
36
+ *
37
+ * @example
38
+ * export const POST = withRateLimit(myHandler, { scope: 'login', limit: 5, window_ms: 15 * 60 * 1000 });
39
+ */
40
+ export declare function withRateLimit(handler: RateLimitRouteHandler, opts: Omit<RateLimitOptions, 'key'> & {
41
+ getKey?: (req: Request) => string;
42
+ }): RateLimitRouteHandler;
43
+ /**
44
+ * Best-effort client IP from standard proxy headers.
45
+ * Checks `x-forwarded-for` (first entry), then `x-real-ip`; falls back to `'unknown'`.
46
+ */
47
+ export declare function getClientIp(req: Request): string;
48
+ export {};
49
+ //# sourceMappingURL=rate_limit.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate_limit.d.ts","sourceRoot":"","sources":["../../src/http/rate_limit.ts"],"names":[],"mappings":"AAeA,qCAAqC;AACrC,MAAM,WAAW,gBAAgB;IAC/B,sDAAsD;IACtD,GAAG,EAAE,MAAM,CAAC;IACZ,wEAAwE;IACxE,KAAK,EAAE,MAAM,CAAC;IACd,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,uCAAuC;IACvC,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,MAAM,eAAe,GACvB;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,GACZ;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,mBAAmB,EAAE,MAAM,CAAA;CAAE,CAAC;AAS/C;;;;;GAKG;AACH,wBAAgB,SAAS,CAAC,IAAI,EAAE,gBAAgB,GAAG,eAAe,CAsBjE;AAED,6CAA6C;AAC7C,wBAAgB,aAAa,IAAI,IAAI,CAEpC;AAMD,KAAK,qBAAqB,GAAG,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,IAAI,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;AAEhG;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,qBAAqB,EAC9B,IAAI,EAAE,IAAI,CAAC,gBAAgB,EAAE,KAAK,CAAC,GAAG;IAAE,MAAM,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,MAAM,CAAA;CAAE,GAC1E,qBAAqB,CAsBvB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAIhD"}
@@ -0,0 +1,84 @@
1
+ // file_description: In-memory token-bucket rate limiter plus a framework-agnostic
2
+ // HTTP route-handler wrapper.
3
+ //
4
+ // `rateLimit`/`_clearBuckets` are a simple per-process Map-backed fixed-window
5
+ // counter — single-process only; swap for a Postgres/Redis-backed store before
6
+ // running multiple instances behind a load balancer.
7
+ //
8
+ // `withRateLimit`/`getClientIp` wrap a route handler using the standard
9
+ // Request/Response types (not 'next/server'), so the same code works as-is in
10
+ // a Next.js App Router route handler — NextRequest extends Request and a
11
+ // returned plain Response is a valid handler return value — mirroring
12
+ // `withRequestIdRouteHandler` in `request_id_middleware.ts`.
13
+ //
14
+ // Promoted from taxclientdocs' lib/rate-limit/{token-bucket,middleware}.ts.
15
+ const _buckets = new Map();
16
+ /**
17
+ * Fixed-window token-bucket check. Increments the bucket for `scope:key` and
18
+ * reports whether the caller is still under `limit` within `window_ms`.
19
+ *
20
+ * @example rateLimit({ key: '1.2.3.4', scope: 'login', limit: 5, window_ms: 60_000 })
21
+ */
22
+ export function rateLimit(opts) {
23
+ const { key, scope, limit, window_ms } = opts;
24
+ const bucketKey = `${scope}:${key}`;
25
+ const now = Date.now();
26
+ const existing = _buckets.get(bucketKey);
27
+ if (!existing || now - existing.window_start >= window_ms) {
28
+ // New window
29
+ _buckets.set(bucketKey, { count: 1, window_start: now });
30
+ return { ok: true };
31
+ }
32
+ if (existing.count < limit) {
33
+ existing.count += 1;
34
+ return { ok: true };
35
+ }
36
+ // Limit exceeded
37
+ const elapsed = now - existing.window_start;
38
+ const retry_after_seconds = Math.ceil((window_ms - elapsed) / 1000);
39
+ return { ok: false, retry_after_seconds };
40
+ }
41
+ /** Clear all buckets. Used in tests only. */
42
+ export function _clearBuckets() {
43
+ _buckets.clear();
44
+ }
45
+ /**
46
+ * Wraps an HTTP route handler with rate limiting. Returns 429 with
47
+ * `Retry-After`/`X-RateLimit-Limit` headers when the limit is exceeded.
48
+ *
49
+ * Keys by client IP (`getClientIp`) by default; pass `getKey` to key by
50
+ * something else (e.g. a session/user id).
51
+ *
52
+ * Does NOT import from 'next' — uses the standard Request/Response types.
53
+ *
54
+ * @example
55
+ * export const POST = withRateLimit(myHandler, { scope: 'login', limit: 5, window_ms: 15 * 60 * 1000 });
56
+ */
57
+ export function withRateLimit(handler, opts) {
58
+ const getKey = opts.getKey ?? getClientIp;
59
+ return async (req, ...args) => {
60
+ const key = getKey(req);
61
+ const result = rateLimit({ ...opts, key });
62
+ if (!result.ok) {
63
+ return Response.json({ error: 'Too many requests. Please try again later.' }, {
64
+ status: 429,
65
+ headers: {
66
+ 'Retry-After': String(result.retry_after_seconds),
67
+ 'X-RateLimit-Limit': String(opts.limit),
68
+ },
69
+ });
70
+ }
71
+ return handler(req, ...args);
72
+ };
73
+ }
74
+ /**
75
+ * Best-effort client IP from standard proxy headers.
76
+ * Checks `x-forwarded-for` (first entry), then `x-real-ip`; falls back to `'unknown'`.
77
+ */
78
+ export function getClientIp(req) {
79
+ const xff = req.headers.get('x-forwarded-for');
80
+ if (xff)
81
+ return xff.split(',')[0].trim();
82
+ return req.headers.get('x-real-ip') ?? 'unknown';
83
+ }
84
+ //# sourceMappingURL=rate_limit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate_limit.js","sourceRoot":"","sources":["../../src/http/rate_limit.ts"],"names":[],"mappings":"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"}
@@ -12,11 +12,13 @@ export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoC
12
12
  export type { HazoErrorOptions, HazoValidationErrorOptions, ValidationIssue, HazoAuthErrorOptions, HazoNotFoundErrorOptions, HazoConflictErrorOptions, HazoConfigErrorOptions, HazoExternalErrorOptions, HazoRateLimitErrorOptions, HazoUnavailableErrorOptions, HazoInternalErrorOptions, } from './errors/index.js';
13
13
  export { setBrowserCorrelationId, getContext, getCorrelationId, withContext, } from './context/client.js';
14
14
  export type { HazoContext } from './context/types.js';
15
- export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
16
- export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, } from './utils/index.js';
15
+ export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
16
+ export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, PartialDatePrecision, PartialDateQualifier, PartialDateEra, PartialDate, PartialDateRange, ParsedPartialDate, } from './utils/index.js';
17
17
  export { fetchWithRequestId } from './http/fetch_with_request_id.client.js';
18
18
  export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
19
19
  export { parseListLimit, parseListOffset } from './http/list_params.js';
20
+ export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
21
+ export type { RateLimitOptions, RateLimitResult } from './http/rate_limit.js';
20
22
  export { createLogger } from './logger/index.client.js';
21
23
  export type { HazoCoreLogger } from './logger/index.js';
22
24
  //# sourceMappingURL=index.client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAIxE,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.client.d.ts","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAGvE,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAC7B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5F,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAI9E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AACxD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC"}
@@ -15,11 +15,12 @@ export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoC
15
15
  // Context (browser — mutable ref, NOT AsyncLocalStorage)
16
16
  export { setBrowserCorrelationId, getContext, getCorrelationId, withContext, } from './context/client.js';
17
17
  // Safe utils (no Node deps)
18
- export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
18
+ export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
19
19
  // HTTP — browser-safe variants (Fetch API, no AsyncLocalStorage)
20
20
  export { fetchWithRequestId } from './http/fetch_with_request_id.client.js';
21
21
  export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
22
22
  export { parseListLimit, parseListOffset } from './http/list_params.js';
23
+ export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
23
24
  // Logger — client-side stub emits to the browser console (server version
24
25
  // requires node:module + process.stderr, neither available in browsers/edge)
25
26
  export { createLogger } from './logger/index.client.js';
@@ -1 +1 @@
1
- {"version":3,"file":"index.client.js","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEvE,4DAA4D;AAC5D,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAG7B,4BAA4B;AAC5B,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAU1B,iEAAiE;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExE,yEAAyE;AACzE,6EAA6E;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
1
+ {"version":3,"file":"index.client.js","sourceRoot":"","sources":["../src/index.client.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,2BAA2B;AAC3B,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,sDAAsD;AACtD,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEvE,4DAA4D;AAC5D,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,yDAAyD;AACzD,OAAO,EACL,uBAAuB,EACvB,UAAU,EACV,gBAAgB,EAChB,WAAW,GACZ,MAAM,qBAAqB,CAAC;AAG7B,4BAA4B;AAC5B,OAAO,EACL,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAgB1B,iEAAiE;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAG5F,yEAAyE;AACzE,6EAA6E;AAC7E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC"}
package/dist/index.d.ts CHANGED
@@ -6,8 +6,8 @@
6
6
  */
7
7
  export { REQUEST_ID_HEADER, HAZO_ERROR_SYMBOL, HAZO_SINGLETONS_KEY } from './constants.js';
8
8
  export { registerSingleton, getSingleton, globalSingleton, resetGlobalSingleton } from './singleton/index.js';
9
- export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
10
- export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, } from './utils/index.js';
9
+ export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
10
+ export type { DateFormat, RetryOptions, DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, FormatCurrencyOptions, PartialDatePrecision, PartialDateQualifier, PartialDateEra, PartialDate, PartialDateRange, ParsedPartialDate, } from './utils/index.js';
11
11
  export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoConflictError, HazoConfigError, HazoExternalError, HazoRateLimitError, HazoUnavailableError, HazoInternalError, fromZodValidation, fromZodConfig, } from './errors/index.js';
12
12
  export type { HazoErrorOptions, HazoValidationErrorOptions, ValidationIssue, HazoAuthErrorOptions, HazoNotFoundErrorOptions, HazoConflictErrorOptions, HazoConfigErrorOptions, HazoExternalErrorOptions, HazoRateLimitErrorOptions, HazoUnavailableErrorOptions, HazoInternalErrorOptions, } from './errors/index.js';
13
13
  export { withContext, getContext, getCorrelationId, } from './context/index.js';
@@ -22,4 +22,6 @@ export { createRequestIdMiddleware, withRequestIdRouteHandler, } from './http/re
22
22
  export { fetchWithRequestId } from './http/fetch_with_request_id.js';
23
23
  export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
24
24
  export { parseListLimit, parseListOffset } from './http/list_params.js';
25
+ export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
26
+ export type { RateLimitOptions, RateLimitResult } from './http/rate_limit.js';
25
27
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9G,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,GACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACjH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAG3F,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAG9G,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EACV,UAAU,EACV,YAAY,EACZ,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACpB,oBAAoB,EACpB,cAAc,EACd,WAAW,EACX,gBAAgB,EAChB,iBAAiB,GAClB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EACV,gBAAgB,EAChB,0BAA0B,EAC1B,eAAe,EACf,oBAAoB,EACpB,wBAAwB,EACxB,wBAAwB,EACxB,sBAAsB,EACtB,wBAAwB,EACxB,yBAAyB,EACzB,2BAA2B,EAC3B,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAC5B,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAGtD,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AACjH,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AAGxD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAGtD,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAC5F,YAAY,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC"}
package/dist/index.js CHANGED
@@ -9,7 +9,7 @@ export { REQUEST_ID_HEADER, HAZO_ERROR_SYMBOL, HAZO_SINGLETONS_KEY } from './con
9
9
  // Singleton registry
10
10
  export { registerSingleton, getSingleton, globalSingleton, resetGlobalSingleton } from './singleton/index.js';
11
11
  // Utilities
12
- export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, } from './utils/index.js';
12
+ export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatPercent, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './utils/index.js';
13
13
  // Errors
14
14
  export { HazoError, HazoValidationError, HazoAuthError, HazoNotFoundError, HazoConflictError, HazoConfigError, HazoExternalError, HazoRateLimitError, HazoUnavailableError, HazoInternalError, fromZodValidation, fromZodConfig, } from './errors/index.js';
15
15
  // Context (server — AsyncLocalStorage)
@@ -25,4 +25,5 @@ export { createRequestIdMiddleware, withRequestIdRouteHandler, } from './http/re
25
25
  export { fetchWithRequestId } from './http/fetch_with_request_id.js';
26
26
  export { get_origin_url, create_redirect_url } from './http/get_origin_url.js';
27
27
  export { parseListLimit, parseListOffset } from './http/list_params.js';
28
+ export { rateLimit, _clearBuckets, withRateLimit, getClientIp } from './http/rate_limit.js';
28
29
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,qBAAqB;AACrB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,YAAY;AACZ,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAU1B,SAAS;AACT,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,uCAAuC;AACvC,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAG5B,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGjH,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO;AACP,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,YAAY;AACZ,OAAO,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAE3F,qBAAqB;AACrB,OAAO,EAAE,iBAAiB,EAAE,YAAY,EAAE,eAAe,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAE9G,YAAY;AACZ,OAAO,EACL,aAAa,EACb,iBAAiB,EACjB,UAAU,EACV,eAAe,EACf,aAAa,EACb,KAAK,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,EACpB,uBAAuB,EACvB,kBAAkB,EAClB,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,uBAAuB,GACxB,MAAM,kBAAkB,CAAC;AAgB1B,SAAS;AACT,OAAO,EACL,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,iBAAiB,EACjB,iBAAiB,EACjB,eAAe,EACf,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,GACd,MAAM,mBAAmB,CAAC;AAe3B,uCAAuC;AACvC,OAAO,EACL,WAAW,EACX,UAAU,EACV,gBAAgB,GACjB,MAAM,oBAAoB,CAAC;AAG5B,SAAS;AACT,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAGjH,SAAS;AACT,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAGjD,QAAQ;AACR,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAG/C,OAAO;AACP,OAAO,EACL,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAC;AACrE,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxE,OAAO,EAAE,SAAS,EAAE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC"}
@@ -18,7 +18,14 @@
18
18
  * 'iso' — YYYY-MM-DD (locale-independent, SSR-safe)
19
19
  * 'dmy' — DD/MM/YYYY
20
20
  * 'mdy' — MM/DD/YYYY
21
- * 'locale' — Use environment locale (NOT SSR-safe; may cause hydration mismatch)
21
+ * 'locale' — Use environment locale (NOT SSR-safe; may cause hydration mismatch).
22
+ * @deprecated SSR-unsafe: the server and browser can resolve different
23
+ * default locales, so the same date renders differently on each,
24
+ * which is exactly the shape of bug that causes Next.js hydration
25
+ * mismatches. `format_date` THROWS when called with 'locale' outside
26
+ * production (see below) to surface this during development; in
27
+ * production it still renders (unchanged behavior for existing
28
+ * deployments). Prefer an explicit locale, or 'iso'/'dmy'/'mdy'.
22
29
  */
23
30
  export type DateFormat = 'iso' | 'dmy' | 'mdy' | 'locale';
24
31
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;GAMG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,MAAM,GAAE,UAAgC,GACvC,MAAM,CAsCR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,EAAE,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACpC,MAAM,GAAE,UAAgC,GACvC,MAAM,CAQR"}
1
+ {"version":3,"file":"dates.d.ts","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,UAAU,GAAG,KAAK,GAAG,KAAK,GAAG,KAAK,GAAG,QAAQ,CAAC;AAE1D;;GAEG;AACH,eAAO,MAAM,mBAAmB,EAAE,UAAkB,CAAC;AAErD;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,MAAM,GAAE,UAAgC,GACvC,MAAM,CA8CR;AAED;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACtC,EAAE,EAAE,IAAI,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI,EACpC,MAAM,GAAE,UAAgC,GACvC,MAAM,CAQR"}
@@ -51,7 +51,13 @@ export function format_date(date, format = DEFAULT_DATE_FORMAT) {
51
51
  case 'mdy':
52
52
  return `${month}/${day}/${year}`;
53
53
  case 'locale':
54
- // Uses environment locale — not SSR-safe (may cause hydration mismatch in Next.js)
54
+ // Uses environment locale — not SSR-safe (may cause hydration mismatch in Next.js).
55
+ // Outside production this throws instead of silently rendering inconsistent output
56
+ // (FR-032 Stage 4); production behavior is unchanged so already-deployed callers
57
+ // that rely on it don't break.
58
+ if (process.env['NODE_ENV'] !== 'production') {
59
+ throw new Error("format_date('locale') is SSR-unsafe — pass an explicit locale or use 'iso'/'dmy'/'mdy'.");
60
+ }
55
61
  return date_obj.toLocaleDateString();
56
62
  default:
57
63
  return `${year}-${month}-${day}`;
@@ -1 +1 @@
1
- {"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAWH;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAe,KAAK,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAAsC,EACtC,SAAqB,mBAAmB;IAExC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,uBAAuB;IACvB,IAAI,QAAc,CAAC;IACnB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,oFAAoF;QACpF,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,gBAAgB;IAChB,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAExD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK;YACR,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QAEnC,KAAK,KAAK;YACR,OAAO,GAAG,GAAG,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAEnC,KAAK,KAAK;YACR,OAAO,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAEnC,KAAK,QAAQ;YACX,mFAAmF;YACnF,OAAO,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QAEvC;YACE,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAsC,EACtC,EAAoC,EACpC,SAAqB,mBAAmB;IAExC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAEvC,IAAI,QAAQ,IAAI,MAAM;QAAE,OAAO,GAAG,QAAQ,MAAM,MAAM,EAAE,CAAC;IACzD,IAAI,QAAQ;QAAE,OAAO,QAAQ,QAAQ,EAAE,CAAC;IACxC,IAAI,MAAM;QAAE,OAAO,MAAM,MAAM,EAAE,CAAC;IAClC,OAAO,EAAE,CAAC;AACZ,CAAC"}
1
+ {"version":3,"file":"dates.js","sourceRoot":"","sources":["../../src/utils/dates.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAkBH;;GAEG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAe,KAAK,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAAsC,EACtC,SAAqB,mBAAmB;IAExC,IAAI,CAAC,IAAI;QAAE,OAAO,EAAE,CAAC;IAErB,uBAAuB;IACvB,IAAI,QAAc,CAAC;IACnB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC7B,oFAAoF;QACpF,QAAQ,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,GAAG,WAAW,CAAC,CAAC;IACtE,CAAC;SAAM,CAAC;QACN,QAAQ,GAAG,IAAI,CAAC;IAClB,CAAC;IAED,gBAAgB;IAChB,IAAI,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;QAC9B,OAAO,OAAO,IAAI,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,MAAM,IAAI,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,MAAM,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC;IAExD,QAAQ,MAAM,EAAE,CAAC;QACf,KAAK,KAAK;YACR,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;QAEnC,KAAK,KAAK;YACR,OAAO,GAAG,GAAG,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAEnC,KAAK,KAAK;YACR,OAAO,GAAG,KAAK,IAAI,GAAG,IAAI,IAAI,EAAE,CAAC;QAEnC,KAAK,QAAQ;YACX,oFAAoF;YACpF,mFAAmF;YACnF,iFAAiF;YACjF,+BAA+B;YAC/B,IAAI,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,YAAY,EAAE,CAAC;gBAC7C,MAAM,IAAI,KAAK,CACb,yFAAyF,CAC1F,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,kBAAkB,EAAE,CAAC;QAEvC;YACE,OAAO,GAAG,IAAI,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,iBAAiB,CAC/B,IAAsC,EACtC,EAAoC,EACpC,SAAqB,mBAAmB;IAExC,MAAM,QAAQ,GAAG,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IAC3C,MAAM,MAAM,GAAG,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,CAAC;IAEvC,IAAI,QAAQ,IAAI,MAAM;QAAE,OAAO,GAAG,QAAQ,MAAM,MAAM,EAAE,CAAC;IACzD,IAAI,QAAQ;QAAE,OAAO,QAAQ,QAAQ,EAAE,CAAC;IACxC,IAAI,MAAM;QAAE,OAAO,MAAM,MAAM,EAAE,CAAC;IAClC,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -34,17 +34,31 @@ export declare function sleep(ms: number): Promise<void>;
34
34
  export declare function formatBytes(bytes: number, decimals?: number): string;
35
35
  export { format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './dates.js';
36
36
  export type { DateFormat } from './dates.js';
37
+ export { getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './partial_date.js';
38
+ export type { PartialDatePrecision, PartialDateQualifier, PartialDateEra, PartialDate, PartialDateRange, ParsedPartialDate, } from './partial_date.js';
37
39
  export { withRetry } from './retry.js';
38
40
  export type { RetryOptions } from './retry.js';
39
41
  export { isUuid } from './uuid.js';
40
42
  export { createDebouncedSaver } from './debounced_saver.js';
41
43
  export type { DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, } from './debounced_saver.js';
44
+ /**
45
+ * Best-effort load of `[format].locale` from `hazo_core_config.ini`. Cached
46
+ * per process; safe to call repeatedly. Exported (module-internal — not part
47
+ * of the public `hazo_core`/`hazo_core/client` surface) so tests can `await`
48
+ * it directly instead of polling. `configDir` is test-only; production calls
49
+ * always use `loadConfig`'s default (`process.cwd()/config`).
50
+ */
51
+ export declare function __loadIniFormatLocaleForTests(configDir?: string): Promise<void>;
52
+ /** Test-only: clear cached locale resolution state between test cases. */
53
+ export declare function __resetFormatLocaleCacheForTests(): void;
42
54
  /**
43
55
  * Format a date as "28 May 2026"
56
+ * @deprecated Use hazo_i18n/format when available
44
57
  */
45
58
  export declare function formatDateShort(date: Date | string): string;
46
59
  /**
47
60
  * Format a date as "Wednesday, 28 May 2026"
61
+ * @deprecated Use hazo_i18n/format when available
48
62
  */
49
63
  export declare function formatDateLong(date: Date | string): string;
50
64
  /**
@@ -69,10 +83,12 @@ export interface FormatCurrencyOptions {
69
83
  compact?: boolean;
70
84
  }
71
85
  /**
72
- * Format a number as currency in `en-AU` locale.
86
+ * Format a number as currency. Locale defaults to `en-AU` — override via
87
+ * HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's `[format].locale`.
73
88
  *
74
89
  * @param amount - The value to format.
75
90
  * @param options - {@link FormatCurrencyOptions} (currency, fractionDigits, absolute, compact).
91
+ * @deprecated Use hazo_i18n/format when available
76
92
  */
77
93
  export declare function formatCurrency(amount: number, options?: FormatCurrencyOptions): string;
78
94
  /**
@@ -80,18 +96,23 @@ export declare function formatCurrency(amount: number, options?: FormatCurrencyO
80
96
  *
81
97
  * @param fraction - Value in the 0–1 range (0.05 = 5%).
82
98
  * @param decimals - Fraction digits to show. Default 1.
99
+ * @deprecated Use hazo_i18n/format when available
83
100
  */
84
101
  export declare function formatPercent(fraction: number, decimals?: number): string;
85
102
  /**
86
- * Format a number with optional decimal places.
103
+ * Format a number with optional decimal places. Locale defaults to `en-AU` —
104
+ * override via HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's
105
+ * `[format].locale`.
87
106
  * @example formatNumber(1234567.89) → "1,234,567.89"
88
107
  * @example formatNumber(1234567.89, 0) → "1,234,568"
108
+ * @deprecated Use hazo_i18n/format when available
89
109
  */
90
110
  export declare function formatNumber(n: number, decimals?: number): string;
91
111
  /**
92
112
  * Format a boolean as a human-readable string.
93
113
  * @example formatBoolean(true) → "Yes"
94
114
  * @example formatBoolean(false) → "No"
115
+ * @deprecated Use hazo_i18n/format when available — hardcodes "Yes"/"No" (English-only)
95
116
  */
96
117
  export declare function formatBoolean(val: boolean): string;
97
118
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAMzC;;;;GAIG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAE1C;AAED;;;GAGG;AACH,wBAAgB,UAAU,IAAI,MAAM,CAEnC;AAMD;;;;;;GAMG;AACH,wBAAsB,eAAe,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CASvE;AAMD;;GAEG;AACH,wBAAgB,aAAa,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,CAAC,GAAG,IAAI,CAMjE;AAMD;;GAEG;AACH,wBAAgB,KAAK,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAE/C;AAMD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAW/D;AAMD,OAAO,EACL,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AAM7C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,YAAY,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAM/C,OAAO,EAAE,MAAM,EAAE,MAAM,WAAW,CAAC;AAMnC,OAAO,EAAE,oBAAoB,EAAE,MAAM,sBAAsB,CAAC;AAC5D,YAAY,EACV,oBAAoB,EACpB,2BAA2B,EAC3B,cAAc,GACf,MAAM,sBAAsB,CAAC;AAU9B;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAO3D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAQ1D;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM,CAM3D;AAMD;;;;GAIG;AACH,0CAA0C;AAC1C,MAAM,WAAW,qBAAqB;IACpC,+CAA+C;IAC/C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;+CAC2C;IAC3C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,qBAA0B,GAAG,MAAM,CAU1F;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,SAAI,GAAG,MAAM,CAGpE;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,CAKjE;AAMD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,OAAO,GAAG,MAAM,CAElD;AAMD;;;;;GAKG;AACH;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,MAAM,CAQpE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
@@ -2,6 +2,10 @@
2
2
  // The type assertion avoids the TS2305 error when checked against the wrong installed version.
3
3
  import * as uuidPkg from 'uuid';
4
4
  const uuidv7 = uuidPkg['v7'];
5
+ // zod is a plain dependency (no Node built-ins) so it's safe to import statically
6
+ // here even though this file is also re-exported by the browser entry
7
+ // (index.client.ts) — see the "Format locale resolution" section below.
8
+ import { z } from 'zod';
5
9
  export { getCurrentEnv } from './env.js';
6
10
  // ---------------------------------------------------------------------------
7
11
  // Request ID generation
@@ -88,6 +92,10 @@ export function formatBytes(bytes, decimals = 2) {
88
92
  // ---------------------------------------------------------------------------
89
93
  export { format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './dates.js';
90
94
  // ---------------------------------------------------------------------------
95
+ // Partial/fuzzy dates (year-only, month-year, GEDCOM qualifiers, BCE, ranges)
96
+ // ---------------------------------------------------------------------------
97
+ export { getPartialDatePrecision, isValidPartialDate, isPartialDateRange, parsePartialDate, formatPartialDate, serializePartialDate, comparePartialDate, formatPartialDateString, } from './partial_date.js';
98
+ // ---------------------------------------------------------------------------
91
99
  // Retry with backoff
92
100
  // ---------------------------------------------------------------------------
93
101
  export { withRetry } from './retry.js';
@@ -100,6 +108,102 @@ export { isUuid } from './uuid.js';
100
108
  // ---------------------------------------------------------------------------
101
109
  export { createDebouncedSaver } from './debounced_saver.js';
102
110
  // ---------------------------------------------------------------------------
111
+ // Format locale resolution (FR-032 Stage 3)
112
+ //
113
+ // formatCurrency/formatNumber/formatDateShort/formatDateLong used to hardcode
114
+ // the Intl locale to the literal 'en-AU'. This section makes that
115
+ // configurable while defaulting to 'en-AU' so existing consumers see no
116
+ // output change unless they opt in.
117
+ //
118
+ // Resolution order: HAZO_CORE_FORMAT_LOCALE env var > [format].locale in
119
+ // hazo_core_config.ini (via loadConfig) > 'en-AU' default.
120
+ //
121
+ // The INI lookup goes through `loadConfig`, which pulls in `node:fs` /
122
+ // `dotenv` (via ../config/index.js) — imports that must never land in the
123
+ // browser bundle produced from this same file via index.client.ts. It is
124
+ // therefore loaded with `optional_import`, not a static import, and — per
125
+ // the 2.0.3 CHANGE_LOG entry — the specifier is passed as a *variable*
126
+ // (`configModulePath`), not a string literal: Vite's import-analysis plugin
127
+ // resolves literal dynamic-import specifiers before honoring
128
+ // `@vite-ignore`/`webpackIgnore`/`turbopackIgnore`, so a literal would still
129
+ // get eagerly bundled. In a real browser the load simply fails (no such
130
+ // chunk to fetch); `optional_import` swallows that and formatters fall back
131
+ // to the env var or default. Because the load is async, the INI value can
132
+ // only take effect once it resolves — the very first formatter call(s) in a
133
+ // process may still see the env-var-or-default value even when an INI
134
+ // override exists; subsequent calls pick it up.
135
+ // ---------------------------------------------------------------------------
136
+ const DEFAULT_FORMAT_LOCALE = 'en-AU';
137
+ const formatConfigSchema = z.object({
138
+ format: z
139
+ .object({
140
+ locale: z.string().optional(),
141
+ })
142
+ .prefault({}),
143
+ });
144
+ let cachedIniFormatLocale;
145
+ let iniFormatLocalePromise = null;
146
+ let warnedFormatLocale = false;
147
+ /**
148
+ * Best-effort load of `[format].locale` from `hazo_core_config.ini`. Cached
149
+ * per process; safe to call repeatedly. Exported (module-internal — not part
150
+ * of the public `hazo_core`/`hazo_core/client` surface) so tests can `await`
151
+ * it directly instead of polling. `configDir` is test-only; production calls
152
+ * always use `loadConfig`'s default (`process.cwd()/config`).
153
+ */
154
+ export function __loadIniFormatLocaleForTests(configDir) {
155
+ if (iniFormatLocalePromise)
156
+ return iniFormatLocalePromise;
157
+ const configModulePath = '../config/index.js';
158
+ iniFormatLocalePromise = optional_import(configModulePath).then((mod) => {
159
+ if (!mod)
160
+ return;
161
+ try {
162
+ // `configDir` is only ever passed by tests (production always uses
163
+ // loadConfig's cwd-based default) — when present, force a fresh read.
164
+ // loadConfig's cache key is `${pkg}:${env}` and does not include
165
+ // configDir, so without this, two tests pointing pkg 'core' at
166
+ // different temp directories would collide on the same cache entry.
167
+ if (configDir) {
168
+ mod.reloadConfig('core');
169
+ }
170
+ const config = mod.loadConfig({
171
+ pkg: 'core',
172
+ ...(configDir ? { configDir } : {}),
173
+ schema: formatConfigSchema,
174
+ envAliases: { 'format.locale': ['HAZO_CORE_FORMAT_LOCALE'] },
175
+ });
176
+ cachedIniFormatLocale = config.format.locale;
177
+ }
178
+ catch {
179
+ // Config unavailable or invalid — formatters fall back to env var/default.
180
+ }
181
+ });
182
+ return iniFormatLocalePromise;
183
+ }
184
+ /** Test-only: clear cached locale resolution state between test cases. */
185
+ export function __resetFormatLocaleCacheForTests() {
186
+ cachedIniFormatLocale = undefined;
187
+ iniFormatLocalePromise = null;
188
+ warnedFormatLocale = false;
189
+ }
190
+ /**
191
+ * Resolve the BCP 47 locale used by formatCurrency/formatNumber/
192
+ * formatDateShort/formatDateLong. See the section comment above for
193
+ * resolution order and the async-INI caveat.
194
+ */
195
+ function resolveFormatLocale() {
196
+ void __loadIniFormatLocaleForTests();
197
+ const locale = process.env['HAZO_CORE_FORMAT_LOCALE'] ?? cachedIniFormatLocale ?? DEFAULT_FORMAT_LOCALE;
198
+ if (process.env['NODE_ENV'] !== 'production' && !warnedFormatLocale) {
199
+ warnedFormatLocale = true;
200
+ console.warn(`[hazo_core] Number/currency/date formatters are using locale "${locale}". ` +
201
+ 'Override via the HAZO_CORE_FORMAT_LOCALE env var or a [format].locale key in ' +
202
+ 'hazo_core_config.ini. (This notice only appears outside production.)');
203
+ }
204
+ return locale;
205
+ }
206
+ // ---------------------------------------------------------------------------
103
207
  // Date formatters
104
208
  // ---------------------------------------------------------------------------
105
209
  function toDate(date) {
@@ -107,10 +211,11 @@ function toDate(date) {
107
211
  }
108
212
  /**
109
213
  * Format a date as "28 May 2026"
214
+ * @deprecated Use hazo_i18n/format when available
110
215
  */
111
216
  export function formatDateShort(date) {
112
217
  const d = toDate(date);
113
- return d.toLocaleDateString('en-AU', {
218
+ return d.toLocaleDateString(resolveFormatLocale(), {
114
219
  day: 'numeric',
115
220
  month: 'short',
116
221
  year: 'numeric',
@@ -118,10 +223,11 @@ export function formatDateShort(date) {
118
223
  }
119
224
  /**
120
225
  * Format a date as "Wednesday, 28 May 2026"
226
+ * @deprecated Use hazo_i18n/format when available
121
227
  */
122
228
  export function formatDateLong(date) {
123
229
  const d = toDate(date);
124
- return d.toLocaleDateString('en-AU', {
230
+ return d.toLocaleDateString(resolveFormatLocale(), {
125
231
  weekday: 'long',
126
232
  day: 'numeric',
127
233
  month: 'long',
@@ -139,15 +245,17 @@ export function formatDateSlash(date) {
139
245
  return `${day}/${month}/${year}`;
140
246
  }
141
247
  /**
142
- * Format a number as currency in `en-AU` locale.
248
+ * Format a number as currency. Locale defaults to `en-AU` — override via
249
+ * HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's `[format].locale`.
143
250
  *
144
251
  * @param amount - The value to format.
145
252
  * @param options - {@link FormatCurrencyOptions} (currency, fractionDigits, absolute, compact).
253
+ * @deprecated Use hazo_i18n/format when available
146
254
  */
147
255
  export function formatCurrency(amount, options = {}) {
148
256
  const { currency = 'AUD', fractionDigits = 2, absolute = false, compact = false } = options;
149
257
  const value = absolute ? Math.abs(amount) : amount;
150
- return new Intl.NumberFormat('en-AU', {
258
+ return new Intl.NumberFormat(resolveFormatLocale(), {
151
259
  style: 'currency',
152
260
  currency,
153
261
  minimumFractionDigits: fractionDigits,
@@ -160,18 +268,22 @@ export function formatCurrency(amount, options = {}) {
160
268
  *
161
269
  * @param fraction - Value in the 0–1 range (0.05 = 5%).
162
270
  * @param decimals - Fraction digits to show. Default 1.
271
+ * @deprecated Use hazo_i18n/format when available
163
272
  */
164
273
  export function formatPercent(fraction, decimals = 1) {
165
274
  const safe = Number.isFinite(fraction) ? fraction : 0;
166
275
  return `${(safe * 100).toFixed(decimals)}%`;
167
276
  }
168
277
  /**
169
- * Format a number with optional decimal places.
278
+ * Format a number with optional decimal places. Locale defaults to `en-AU` —
279
+ * override via HAZO_CORE_FORMAT_LOCALE or hazo_core_config.ini's
280
+ * `[format].locale`.
170
281
  * @example formatNumber(1234567.89) → "1,234,567.89"
171
282
  * @example formatNumber(1234567.89, 0) → "1,234,568"
283
+ * @deprecated Use hazo_i18n/format when available
172
284
  */
173
285
  export function formatNumber(n, decimals) {
174
- return new Intl.NumberFormat('en-AU', {
286
+ return new Intl.NumberFormat(resolveFormatLocale(), {
175
287
  minimumFractionDigits: decimals,
176
288
  maximumFractionDigits: decimals,
177
289
  }).format(n);
@@ -183,6 +295,7 @@ export function formatNumber(n, decimals) {
183
295
  * Format a boolean as a human-readable string.
184
296
  * @example formatBoolean(true) → "Yes"
185
297
  * @example formatBoolean(false) → "No"
298
+ * @deprecated Use hazo_i18n/format when available — hardcodes "Yes"/"No" (English-only)
186
299
  */
187
300
  export function formatBoolean(val) {
188
301
  return val ? 'Yes' : 'No';
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Pure helpers for genealogy-style partial/fuzzy dates (year-only, year-month,
3
+ * GEDCOM qualifiers ABT/BEF/AFT/EST/CAL, BET...AND ranges, BCE eras).
4
+ */
5
+ export type PartialDatePrecision = 'year' | 'month' | 'day';
6
+ export type PartialDateQualifier = 'circa' | 'before' | 'after' | 'estimated' | 'calculated';
7
+ export type PartialDateEra = 'CE' | 'BCE';
8
+ export interface PartialDate {
9
+ year: number;
10
+ month?: number;
11
+ day?: number;
12
+ qualifier?: PartialDateQualifier;
13
+ era?: PartialDateEra;
14
+ }
15
+ export interface PartialDateRange {
16
+ from: PartialDate;
17
+ to: PartialDate;
18
+ }
19
+ export type ParsedPartialDate = PartialDate | PartialDateRange | {
20
+ freeform: string;
21
+ };
22
+ /**
23
+ * Derives precision from which fields are populated. Precision is never
24
+ * stored on the object — it is always computed from month/day presence.
25
+ */
26
+ export declare function getPartialDatePrecision(d: PartialDate): PartialDatePrecision;
27
+ /**
28
+ * Structural invariants for a PartialDate:
29
+ * - year is a finite positive integer (BCE-ness is carried by `era`, never a negative year)
30
+ * - month, if present, is an integer 1-12
31
+ * - day, if present, is an integer 1-31 AND month must also be present
32
+ * - era, if present, is 'CE' or 'BCE'
33
+ * - qualifier, if present, is one of the 5 valid qualifiers
34
+ */
35
+ export declare function isValidPartialDate(d: PartialDate): boolean;
36
+ /** Type guard distinguishing a PartialDateRange from a plain PartialDate/freeform result. */
37
+ export declare function isPartialDateRange(d: ParsedPartialDate): d is PartialDateRange;
38
+ /**
39
+ * Parses a partial-date string. Tries, in order: strict ISO (YYYY, YYYY-MM,
40
+ * YYYY-MM-DD), GEDCOM `BET ... AND ...` ranges, GEDCOM qualifier prefixes
41
+ * (ABT/BEF/AFT/EST/CAL), then bare GEDCOM day/month/year/BCE. Empty or
42
+ * whitespace-only input returns null; unparseable non-empty input returns
43
+ * `{ freeform: <trimmed input> }`. Never throws.
44
+ */
45
+ export declare function parsePartialDate(input: string): ParsedPartialDate | null;
46
+ /**
47
+ * Renders a PartialDate/PartialDateRange for display. `opts.precision`, when
48
+ * given, may only coarsen the rendering (e.g. requesting 'year' on a
49
+ * day-precision date drops the month/day) — it can never invent detail finer
50
+ * than the value actually has, so a request finer than the value's own
51
+ * precision is clamped down to that own precision. Never mutates `d`.
52
+ */
53
+ export declare function formatPartialDate(d: PartialDate | PartialDateRange, opts?: {
54
+ precision?: PartialDatePrecision;
55
+ locale?: string;
56
+ }): string;
57
+ /**
58
+ * Convenience wrapper for callers that hold a raw string rather than an
59
+ * already-parsed PartialDate (matches the shape of kinstripe's prior
60
+ * `formatPartialDate(s: string, opts)`, kept as a separate function here
61
+ * since #formatPartialDate now takes a PartialDate, not a string).
62
+ */
63
+ export declare function formatPartialDateString(input: string, opts?: {
64
+ precision?: PartialDatePrecision;
65
+ locale?: string;
66
+ }): string;
67
+ /**
68
+ * Serializes a PartialDate/PartialDateRange back to a string. A plain date
69
+ * (no qualifier, no BCE era) round-trips through the ISO form; a qualified
70
+ * and/or BCE date round-trips through the GEDCOM form. `parsePartialDate`
71
+ * accepts the output of this function.
72
+ */
73
+ export declare function serializePartialDate(d: PartialDate | PartialDateRange): string;
74
+ /**
75
+ * Chronological comparator, like a standard `Array#sort` comparator
76
+ * (negative when `a` is earlier than `b`, zero when tied, positive when
77
+ * `a` is later). Each rule below applies only when every prior rule ties:
78
+ *
79
+ * 1. Era — BCE sorts before CE.
80
+ * 2. Year — within CE, smaller year is earlier; within BCE, a LARGER
81
+ * year number is chronologically earlier (200 BCE happened
82
+ * before 100 BCE, so it sorts first).
83
+ * 3. Month — absent (coarser) sorts before present; otherwise numeric.
84
+ * 4. Day — same rule as month.
85
+ * 5. Qualifier — 'before' sorts before no-qualifier/circa/estimated/
86
+ * calculated, which all sort before 'after'. circa/estimated/
87
+ * calculated/undefined are mutually equal at this step.
88
+ */
89
+ export declare function comparePartialDate(a: PartialDate, b: PartialDate): number;
90
+ //# sourceMappingURL=partial_date.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partial_date.d.ts","sourceRoot":"","sources":["../../src/utils/partial_date.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,MAAM,oBAAoB,GAAG,MAAM,GAAG,OAAO,GAAG,KAAK,CAAC;AAC5D,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,GAAG,WAAW,GAAG,YAAY,CAAC;AAC7F,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,KAAK,CAAC;AAE1C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,SAAS,CAAC,EAAE,oBAAoB,CAAC;IACjC,GAAG,CAAC,EAAE,cAAc,CAAC;CACtB;AAED,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,WAAW,CAAC;IAClB,EAAE,EAAE,WAAW,CAAC;CACjB;AAED,MAAM,MAAM,iBAAiB,GAAG,WAAW,GAAG,gBAAgB,GAAG;IAAE,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC;AAiDtF;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,CAAC,EAAE,WAAW,GAAG,oBAAoB,CAI5E;AAED;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,GAAG,OAAO,CAa1D;AAED,6FAA6F;AAC7F,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,iBAAiB,GAAG,CAAC,IAAI,gBAAgB,CAE9E;AA0FD;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,GAAG,iBAAiB,GAAG,IAAI,CAmBxE;AAWD;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAC/B,CAAC,EAAE,WAAW,GAAG,gBAAgB,EACjC,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CA8BR;AAED;;;;;GAKG;AACH,wBAAgB,uBAAuB,CACrC,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE;IAAE,SAAS,CAAC,EAAE,oBAAoB,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAC3D,MAAM,CAKR;AAwCD;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EAAE,WAAW,GAAG,gBAAgB,GAAG,MAAM,CAK9E;AAYD;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,EAAE,WAAW,GAAG,MAAM,CAwBzE"}
@@ -0,0 +1,357 @@
1
+ /**
2
+ * Pure helpers for genealogy-style partial/fuzzy dates (year-only, year-month,
3
+ * GEDCOM qualifiers ABT/BEF/AFT/EST/CAL, BET...AND ranges, BCE eras).
4
+ */
5
+ // ---------------------------------------------------------------------------
6
+ // Internal tables
7
+ // ---------------------------------------------------------------------------
8
+ const MONTH_ABBREVS = [
9
+ 'JAN', 'FEB', 'MAR', 'APR', 'MAY', 'JUN', 'JUL', 'AUG', 'SEP', 'OCT', 'NOV', 'DEC',
10
+ ];
11
+ const MONTH_ABBREV_TO_INDEX = Object.fromEntries(MONTH_ABBREVS.map((m, i) => [m, i + 1]));
12
+ const QUALIFIER_PREFIX_TO_NAME = {
13
+ ABT: 'circa',
14
+ BEF: 'before',
15
+ AFT: 'after',
16
+ EST: 'estimated',
17
+ CAL: 'calculated',
18
+ };
19
+ const QUALIFIER_NAME_TO_PREFIX = {
20
+ circa: 'ABT',
21
+ before: 'BEF',
22
+ after: 'AFT',
23
+ estimated: 'EST',
24
+ calculated: 'CAL',
25
+ };
26
+ const QUALIFIER_WORD = {
27
+ circa: 'circa',
28
+ before: 'before',
29
+ after: 'after',
30
+ estimated: 'estimated',
31
+ calculated: 'calculated',
32
+ };
33
+ const VALID_QUALIFIERS = [
34
+ 'circa', 'before', 'after', 'estimated', 'calculated',
35
+ ];
36
+ const VALID_ERAS = ['CE', 'BCE'];
37
+ const PRECISION_ORDER = { year: 0, month: 1, day: 2 };
38
+ // ---------------------------------------------------------------------------
39
+ // Precision / validity
40
+ // ---------------------------------------------------------------------------
41
+ /**
42
+ * Derives precision from which fields are populated. Precision is never
43
+ * stored on the object — it is always computed from month/day presence.
44
+ */
45
+ export function getPartialDatePrecision(d) {
46
+ if (d.day !== undefined)
47
+ return 'day';
48
+ if (d.month !== undefined)
49
+ return 'month';
50
+ return 'year';
51
+ }
52
+ /**
53
+ * Structural invariants for a PartialDate:
54
+ * - year is a finite positive integer (BCE-ness is carried by `era`, never a negative year)
55
+ * - month, if present, is an integer 1-12
56
+ * - day, if present, is an integer 1-31 AND month must also be present
57
+ * - era, if present, is 'CE' or 'BCE'
58
+ * - qualifier, if present, is one of the 5 valid qualifiers
59
+ */
60
+ export function isValidPartialDate(d) {
61
+ if (!d || typeof d !== 'object')
62
+ return false;
63
+ if (!Number.isInteger(d.year) || d.year <= 0)
64
+ return false;
65
+ if (d.month !== undefined && (!Number.isInteger(d.month) || d.month < 1 || d.month > 12)) {
66
+ return false;
67
+ }
68
+ if (d.day !== undefined) {
69
+ if (!Number.isInteger(d.day) || d.day < 1 || d.day > 31)
70
+ return false;
71
+ if (d.month === undefined)
72
+ return false;
73
+ }
74
+ if (d.era !== undefined && !VALID_ERAS.includes(d.era))
75
+ return false;
76
+ if (d.qualifier !== undefined && !VALID_QUALIFIERS.includes(d.qualifier))
77
+ return false;
78
+ return true;
79
+ }
80
+ /** Type guard distinguishing a PartialDateRange from a plain PartialDate/freeform result. */
81
+ export function isPartialDateRange(d) {
82
+ return !!d && typeof d === 'object' && 'from' in d && 'to' in d;
83
+ }
84
+ // ---------------------------------------------------------------------------
85
+ // Parsing
86
+ // ---------------------------------------------------------------------------
87
+ /**
88
+ * Parses a "bare" day/month/year expression with an optional trailing BCE
89
+ * suffix — no qualifier prefix. Shared by the standalone GEDCOM path and by
90
+ * each side of a BET...AND range.
91
+ */
92
+ function parseBareDate(raw) {
93
+ let s = raw.trim();
94
+ if (!s)
95
+ return null;
96
+ let era;
97
+ const bceMatch = s.match(/^(.*?)\s+BCE$/i);
98
+ if (bceMatch) {
99
+ era = 'BCE';
100
+ s = bceMatch[1].trim();
101
+ }
102
+ const upper = s.toUpperCase();
103
+ let m = upper.match(/^(\d{1,2})\s+([A-Z]{3})\s+(\d{1,4})$/);
104
+ if (m) {
105
+ const monthIdx = MONTH_ABBREV_TO_INDEX[m[2]];
106
+ if (monthIdx === undefined)
107
+ return null;
108
+ const result = { year: parseInt(m[3], 10), month: monthIdx, day: parseInt(m[1], 10) };
109
+ if (era)
110
+ result.era = era;
111
+ return result;
112
+ }
113
+ m = upper.match(/^([A-Z]{3})\s+(\d{1,4})$/);
114
+ if (m) {
115
+ const monthIdx = MONTH_ABBREV_TO_INDEX[m[1]];
116
+ if (monthIdx === undefined)
117
+ return null;
118
+ const result = { year: parseInt(m[2], 10), month: monthIdx };
119
+ if (era)
120
+ result.era = era;
121
+ return result;
122
+ }
123
+ m = upper.match(/^(\d{1,4})$/);
124
+ if (m) {
125
+ const result = { year: parseInt(m[1], 10) };
126
+ if (era)
127
+ result.era = era;
128
+ return result;
129
+ }
130
+ return null;
131
+ }
132
+ /** Parses a strict ISO date (YYYY, YYYY-MM, or YYYY-MM-DD). */
133
+ function parseIsoDate(s) {
134
+ const isoMatch = s.match(/^(\d{4})(-(\d{2})(-(\d{2}))?)?$/);
135
+ if (!isoMatch)
136
+ return null;
137
+ const candidate = { year: parseInt(isoMatch[1], 10) };
138
+ if (isoMatch[3])
139
+ candidate.month = parseInt(isoMatch[3], 10);
140
+ if (isoMatch[5])
141
+ candidate.day = parseInt(isoMatch[5], 10);
142
+ return isValidPartialDate(candidate) ? candidate : null;
143
+ }
144
+ /**
145
+ * Parses one "side" of a date expression: either a strict ISO date, or an
146
+ * optional GEDCOM qualifier prefix (ABT/BEF/AFT/EST/CAL) followed by a bare
147
+ * day/month/year/BCE expression. Used both standalone and recursively inside
148
+ * BET...AND ranges (a plain, non-qualified date serializes as ISO even
149
+ * inside a range, so ranges must accept ISO sides to round-trip).
150
+ */
151
+ function parseGedcomSide(raw) {
152
+ const s = raw.trim();
153
+ if (!s)
154
+ return null;
155
+ const iso = parseIsoDate(s);
156
+ if (iso)
157
+ return iso;
158
+ const upper = s.toUpperCase();
159
+ const prefixMatch = upper.match(/^(ABT|BEF|AFT|EST|CAL)\s+(.+)$/);
160
+ if (prefixMatch) {
161
+ const qualifier = QUALIFIER_PREFIX_TO_NAME[prefixMatch[1]];
162
+ const bare = parseBareDate(prefixMatch[2]);
163
+ if (!bare)
164
+ return null;
165
+ const result = { ...bare, qualifier };
166
+ return isValidPartialDate(result) ? result : null;
167
+ }
168
+ const bare = parseBareDate(upper);
169
+ if (!bare)
170
+ return null;
171
+ return isValidPartialDate(bare) ? bare : null;
172
+ }
173
+ /**
174
+ * Parses a partial-date string. Tries, in order: strict ISO (YYYY, YYYY-MM,
175
+ * YYYY-MM-DD), GEDCOM `BET ... AND ...` ranges, GEDCOM qualifier prefixes
176
+ * (ABT/BEF/AFT/EST/CAL), then bare GEDCOM day/month/year/BCE. Empty or
177
+ * whitespace-only input returns null; unparseable non-empty input returns
178
+ * `{ freeform: <trimmed input> }`. Never throws.
179
+ */
180
+ export function parsePartialDate(input) {
181
+ if (typeof input !== 'string')
182
+ return null;
183
+ const trimmed = input.trim();
184
+ if (trimmed === '')
185
+ return null;
186
+ const iso = parseIsoDate(trimmed);
187
+ if (iso)
188
+ return iso;
189
+ const betMatch = trimmed.match(/^BET\s+(.+?)\s+AND\s+(.+)$/i);
190
+ if (betMatch) {
191
+ const from = parseGedcomSide(betMatch[1]);
192
+ const to = parseGedcomSide(betMatch[2]);
193
+ if (from && to)
194
+ return { from, to };
195
+ }
196
+ const side = parseGedcomSide(trimmed);
197
+ if (side)
198
+ return side;
199
+ return { freeform: trimmed };
200
+ }
201
+ // ---------------------------------------------------------------------------
202
+ // Formatting
203
+ // ---------------------------------------------------------------------------
204
+ function monthName(month, locale) {
205
+ // Fixed dummy year — only the month field is ever read back out.
206
+ return new Intl.DateTimeFormat(locale, { month: 'long' }).format(new Date(2000, month - 1, 1));
207
+ }
208
+ /**
209
+ * Renders a PartialDate/PartialDateRange for display. `opts.precision`, when
210
+ * given, may only coarsen the rendering (e.g. requesting 'year' on a
211
+ * day-precision date drops the month/day) — it can never invent detail finer
212
+ * than the value actually has, so a request finer than the value's own
213
+ * precision is clamped down to that own precision. Never mutates `d`.
214
+ */
215
+ export function formatPartialDate(d, opts) {
216
+ if (isPartialDateRange(d)) {
217
+ return `between ${formatPartialDate(d.from, opts)} and ${formatPartialDate(d.to, opts)}`;
218
+ }
219
+ const ownPrecision = getPartialDatePrecision(d);
220
+ let effectivePrecision = ownPrecision;
221
+ if (opts?.precision !== undefined && PRECISION_ORDER[opts.precision] < PRECISION_ORDER[ownPrecision]) {
222
+ effectivePrecision = opts.precision;
223
+ }
224
+ const locale = opts?.locale ?? 'en';
225
+ let datePart;
226
+ if (effectivePrecision === 'day') {
227
+ datePart = `${d.day} ${monthName(d.month, locale)} ${d.year}`;
228
+ }
229
+ else if (effectivePrecision === 'month') {
230
+ datePart = `${monthName(d.month, locale)} ${d.year}`;
231
+ }
232
+ else {
233
+ datePart = `${d.year}`;
234
+ }
235
+ if (d.era === 'BCE') {
236
+ datePart = `${datePart} BCE`;
237
+ }
238
+ if (d.qualifier) {
239
+ datePart = `${QUALIFIER_WORD[d.qualifier]} ${datePart}`;
240
+ }
241
+ return datePart;
242
+ }
243
+ /**
244
+ * Convenience wrapper for callers that hold a raw string rather than an
245
+ * already-parsed PartialDate (matches the shape of kinstripe's prior
246
+ * `formatPartialDate(s: string, opts)`, kept as a separate function here
247
+ * since #formatPartialDate now takes a PartialDate, not a string).
248
+ */
249
+ export function formatPartialDateString(input, opts) {
250
+ const parsed = parsePartialDate(input);
251
+ if (parsed === null)
252
+ return '';
253
+ if ('freeform' in parsed)
254
+ return parsed.freeform;
255
+ return formatPartialDate(parsed, opts);
256
+ }
257
+ // ---------------------------------------------------------------------------
258
+ // Serialization
259
+ // ---------------------------------------------------------------------------
260
+ function serializeSide(d) {
261
+ const pad = (n) => String(n).padStart(2, '0');
262
+ let core;
263
+ if (d.qualifier || d.era === 'BCE') {
264
+ // GEDCOM-flavoured rendering (month abbreviation, unpadded day).
265
+ if (d.day !== undefined && d.month !== undefined) {
266
+ core = `${d.day} ${MONTH_ABBREVS[d.month - 1]} ${d.year}`;
267
+ }
268
+ else if (d.month !== undefined) {
269
+ core = `${MONTH_ABBREVS[d.month - 1]} ${d.year}`;
270
+ }
271
+ else {
272
+ core = `${d.year}`;
273
+ }
274
+ if (d.qualifier) {
275
+ core = `${QUALIFIER_NAME_TO_PREFIX[d.qualifier]} ${core}`;
276
+ }
277
+ }
278
+ else {
279
+ // Plain ISO rendering.
280
+ if (d.day !== undefined && d.month !== undefined) {
281
+ core = `${d.year}-${pad(d.month)}-${pad(d.day)}`;
282
+ }
283
+ else if (d.month !== undefined) {
284
+ core = `${d.year}-${pad(d.month)}`;
285
+ }
286
+ else {
287
+ core = `${d.year}`;
288
+ }
289
+ }
290
+ if (d.era === 'BCE') {
291
+ core = `${core} BCE`;
292
+ }
293
+ return core;
294
+ }
295
+ /**
296
+ * Serializes a PartialDate/PartialDateRange back to a string. A plain date
297
+ * (no qualifier, no BCE era) round-trips through the ISO form; a qualified
298
+ * and/or BCE date round-trips through the GEDCOM form. `parsePartialDate`
299
+ * accepts the output of this function.
300
+ */
301
+ export function serializePartialDate(d) {
302
+ if (isPartialDateRange(d)) {
303
+ return `BET ${serializeSide(d.from)} AND ${serializeSide(d.to)}`;
304
+ }
305
+ return serializeSide(d);
306
+ }
307
+ // ---------------------------------------------------------------------------
308
+ // Comparison
309
+ // ---------------------------------------------------------------------------
310
+ function qualifierRank(q) {
311
+ if (q === 'before')
312
+ return -1;
313
+ if (q === 'after')
314
+ return 1;
315
+ return 0; // circa / estimated / calculated / undefined are mutually equal here
316
+ }
317
+ /**
318
+ * Chronological comparator, like a standard `Array#sort` comparator
319
+ * (negative when `a` is earlier than `b`, zero when tied, positive when
320
+ * `a` is later). Each rule below applies only when every prior rule ties:
321
+ *
322
+ * 1. Era — BCE sorts before CE.
323
+ * 2. Year — within CE, smaller year is earlier; within BCE, a LARGER
324
+ * year number is chronologically earlier (200 BCE happened
325
+ * before 100 BCE, so it sorts first).
326
+ * 3. Month — absent (coarser) sorts before present; otherwise numeric.
327
+ * 4. Day — same rule as month.
328
+ * 5. Qualifier — 'before' sorts before no-qualifier/circa/estimated/
329
+ * calculated, which all sort before 'after'. circa/estimated/
330
+ * calculated/undefined are mutually equal at this step.
331
+ */
332
+ export function comparePartialDate(a, b) {
333
+ const eraA = a.era ?? 'CE';
334
+ const eraB = b.era ?? 'CE';
335
+ if (eraA !== eraB) {
336
+ return eraA === 'BCE' ? -1 : 1;
337
+ }
338
+ if (a.year !== b.year) {
339
+ return eraA === 'BCE' ? b.year - a.year : a.year - b.year;
340
+ }
341
+ if (a.month === undefined && b.month !== undefined)
342
+ return -1;
343
+ if (a.month !== undefined && b.month === undefined)
344
+ return 1;
345
+ if (a.month !== undefined && b.month !== undefined && a.month !== b.month) {
346
+ return a.month - b.month;
347
+ }
348
+ if (a.day === undefined && b.day !== undefined)
349
+ return -1;
350
+ if (a.day !== undefined && b.day === undefined)
351
+ return 1;
352
+ if (a.day !== undefined && b.day !== undefined && a.day !== b.day) {
353
+ return a.day - b.day;
354
+ }
355
+ return qualifierRank(a.qualifier) - qualifierRank(b.qualifier);
356
+ }
357
+ //# sourceMappingURL=partial_date.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"partial_date.js","sourceRoot":"","sources":["../../src/utils/partial_date.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_core",
3
- "version": "2.0.3",
3
+ "version": "2.3.0",
4
4
  "description": "Foundation package for all hazo_* packages — errors, correlation ID, config, logger, debug, singletons, utils",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",