hazo_core 1.2.1 → 1.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
@@ -66,6 +66,14 @@ import { loadConfig, defineConfig, createLogger, createDebug,
66
66
  fetchWithRequestId, createRequestIdMiddleware, REQUEST_ID_HEADER } from 'hazo_core';
67
67
  ```
68
68
 
69
+ ### Utilities
70
+
71
+ ```ts
72
+ import { withRetry, isUuid, parseListLimit, parseListOffset,
73
+ createDebouncedSaver } from 'hazo_core';
74
+ // all five are env-agnostic and also available from 'hazo_core/client'
75
+ ```
76
+
69
77
  ### Browser-safe subset
70
78
 
71
79
  ```ts
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Parse a limit query-string param.
3
+ *
4
+ * @param raw The raw string from `searchParams.get('limit')` (may be null).
5
+ * @param opts `default` — value used when raw is absent/invalid.
6
+ * `max` — upper clamp applied after parsing.
7
+ * @returns An integer in [1, max].
8
+ * @example parseListLimit('50', { default: 20, max: 100 }) // 50
9
+ * @example parseListLimit(null, { default: 20, max: 100 }) // 20
10
+ * @example parseListLimit('abc', { default: 20, max: 100 }) // 20
11
+ * @example parseListLimit('9999', { default: 20, max: 100 }) // 100
12
+ */
13
+ export declare function parseListLimit(raw: string | null, opts: {
14
+ default: number;
15
+ max: number;
16
+ }): number;
17
+ /**
18
+ * Parse an offset query-string param.
19
+ *
20
+ * @param raw The raw string from `searchParams.get('offset')` (may be null).
21
+ * @param opts Optional `default` — value used when raw is absent/invalid (default 0).
22
+ * @returns An integer >= 0.
23
+ * @example parseListOffset('40', {}) // 40
24
+ * @example parseListOffset(null, {}) // 0
25
+ * @example parseListOffset('-5', {}) // 0
26
+ */
27
+ export declare function parseListOffset(raw: string | null, opts?: {
28
+ default?: number;
29
+ }): number;
30
+ //# sourceMappingURL=list_params.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_params.d.ts","sourceRoot":"","sources":["../../src/http/list_params.ts"],"names":[],"mappings":"AAYA;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAC5B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,IAAI,EAAE;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,GACrC,MAAM,CAMR;AAED;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,GAAG,EAAE,MAAM,GAAG,IAAI,EAClB,IAAI,CAAC,EAAE;IAAE,OAAO,CAAC,EAAE,MAAM,CAAA;CAAE,GAC1B,MAAM,CAMR"}
@@ -0,0 +1,53 @@
1
+ // file_description: Safe pagination parameter parsers for list API routes.
2
+ //
3
+ // `parseInt` without a radix is not safe — callers may pass garbage or omit the
4
+ // param entirely, which causes parseInt to return NaN. Math.min/max propagate NaN
5
+ // silently, resulting in e.g. `limit=NaN` being sent downstream (PostgREST, an ORM,
6
+ // etc). These helpers use `parseInt(raw, 10)` with an explicit radix, check for
7
+ // non-finite/negative results, and fall back to caller-supplied defaults.
8
+ //
9
+ // Promoted from taxclientdocs' lib/api/list-params.ts into hazo_core — pure string
10
+ // parsing with no app- or framework-specific behaviour. Browser-safe (no Node
11
+ // deps), so also exported from the client entry point.
12
+ /**
13
+ * Parse a limit query-string param.
14
+ *
15
+ * @param raw The raw string from `searchParams.get('limit')` (may be null).
16
+ * @param opts `default` — value used when raw is absent/invalid.
17
+ * `max` — upper clamp applied after parsing.
18
+ * @returns An integer in [1, max].
19
+ * @example parseListLimit('50', { default: 20, max: 100 }) // 50
20
+ * @example parseListLimit(null, { default: 20, max: 100 }) // 20
21
+ * @example parseListLimit('abc', { default: 20, max: 100 }) // 20
22
+ * @example parseListLimit('9999', { default: 20, max: 100 }) // 100
23
+ */
24
+ export function parseListLimit(raw, opts) {
25
+ if (raw === null || raw === '')
26
+ return opts.default;
27
+ const parsed = parseInt(raw, 10);
28
+ if (!isFinite(parsed))
29
+ return opts.default;
30
+ if (parsed < 1)
31
+ return 1;
32
+ return Math.min(parsed, opts.max);
33
+ }
34
+ /**
35
+ * Parse an offset query-string param.
36
+ *
37
+ * @param raw The raw string from `searchParams.get('offset')` (may be null).
38
+ * @param opts Optional `default` — value used when raw is absent/invalid (default 0).
39
+ * @returns An integer >= 0.
40
+ * @example parseListOffset('40', {}) // 40
41
+ * @example parseListOffset(null, {}) // 0
42
+ * @example parseListOffset('-5', {}) // 0
43
+ */
44
+ export function parseListOffset(raw, opts) {
45
+ const fallback = opts?.default ?? 0;
46
+ if (raw === null || raw === '')
47
+ return fallback;
48
+ const parsed = parseInt(raw, 10);
49
+ if (!isFinite(parsed) || parsed < 0)
50
+ return fallback;
51
+ return parsed;
52
+ }
53
+ //# sourceMappingURL=list_params.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"list_params.js","sourceRoot":"","sources":["../../src/http/list_params.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAC3E,EAAE;AACF,gFAAgF;AAChF,kFAAkF;AAClF,oFAAoF;AACpF,gFAAgF;AAChF,0EAA0E;AAC1E,EAAE;AACF,mFAAmF;AACnF,8EAA8E;AAC9E,uDAAuD;AAEvD;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,cAAc,CAC5B,GAAkB,EAClB,IAAsC;IAEtC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC;IACpD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;QAAE,OAAO,IAAI,CAAC,OAAO,CAAC;IAC3C,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAC;IACzB,OAAO,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC;AACpC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,GAAkB,EAClB,IAA2B;IAE3B,MAAM,QAAQ,GAAG,IAAI,EAAE,OAAO,IAAI,CAAC,CAAC;IACpC,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,KAAK,EAAE;QAAE,OAAO,QAAQ,CAAC;IAChD,MAAM,MAAM,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACjC,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC;QAAE,OAAO,QAAQ,CAAC;IACrD,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -12,10 +12,11 @@ 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, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, } from './utils/index.js';
16
- export type { DateFormat } from './utils/index.js';
15
+ export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, 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, } 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
+ export { parseListLimit, parseListOffset } from './http/list_params.js';
19
20
  export { createLogger } from './logger/index.client.js';
20
21
  export type { HazoCoreLogger } from './logger/index.js';
21
22
  //# 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,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAI/E,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,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,GACf,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"}
@@ -15,10 +15,11 @@ 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, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, } from './utils/index.js';
18
+ export { generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, getCurrentEnv, withRetry, isUuid, createDebouncedSaver, } 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
+ export { parseListLimit, parseListOffset } from './http/list_params.js';
22
23
  // Logger — client-side stub emits to the browser console (server version
23
24
  // requires node:module + process.stderr, neither available in browsers/edge)
24
25
  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,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAG1B,iEAAiE;AACjE,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAE/E,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,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,aAAa,EACb,SAAS,EACT,MAAM,EACN,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAS1B,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"}
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, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './utils/index.js';
10
- export type { DateFormat } from './utils/index.js';
9
+ export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, 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, } 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';
@@ -21,4 +21,5 @@ export type { HazoCoreDebug } from './debug/index.js';
21
21
  export { createRequestIdMiddleware, withRequestIdRouteHandler, } from './http/request_id_middleware.js';
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
+ export { parseListLimit, parseListOffset } from './http/list_params.js';
24
25
  //# 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,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAC1B,YAAY,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAGnD,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"}
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,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,GACf,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"}
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, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './utils/index.js';
12
+ export { getCurrentEnv, generateRequestId, generateId, optional_import, safeJsonParse, sleep, formatBytes, formatDateShort, formatDateLong, formatDateSlash, formatCurrency, formatNumber, formatBoolean, getInitials, format_date, format_date_range, DEFAULT_DATE_FORMAT, withRetry, isUuid, createDebouncedSaver, } 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)
@@ -24,4 +24,5 @@ export { createDebug } from './debug/index.js';
24
24
  export { createRequestIdMiddleware, withRequestIdRouteHandler, } from './http/request_id_middleware.js';
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
+ export { parseListLimit, parseListOffset } from './http/list_params.js';
27
28
  //# 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,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,GACpB,MAAM,kBAAkB,CAAC;AAG1B,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"}
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,YAAY,EACZ,aAAa,EACb,WAAW,EACX,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,SAAS,EACT,MAAM,EACN,oBAAoB,GACrB,MAAM,kBAAkB,CAAC;AAS1B,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"}
@@ -0,0 +1,52 @@
1
+ /** Context passed to the `save` callback describing which path triggered it. */
2
+ export interface DebouncedSaveContext {
3
+ /**
4
+ * True only for the `flush()` path (unmount/navigation). Callers should issue a
5
+ * `keepalive` request in that case so it outlives the page; false for the normal
6
+ * debounced path.
7
+ */
8
+ keepalive: boolean;
9
+ }
10
+ /** Options for {@link createDebouncedSaver}. */
11
+ export interface CreateDebouncedSaverOptions<T> {
12
+ /** Debounce window in milliseconds. */
13
+ delayMs: number;
14
+ /** Persist the data. Called at most once per queued change. */
15
+ save: (data: T, ctx: DebouncedSaveContext) => void;
16
+ }
17
+ /** Handle returned by {@link createDebouncedSaver}. */
18
+ export interface DebouncedSaver<T> {
19
+ /** Queue `data` to be saved after the debounce delay, replacing any pending save. */
20
+ schedule(data: T): void;
21
+ /** Fire the pending save immediately (keepalive) and cancel the timer. No-op if nothing is pending. */
22
+ flush(): void;
23
+ /** Drop the pending save without firing it. */
24
+ cancel(): void;
25
+ /** True while a save is queued and not yet fired. */
26
+ hasPending(): boolean;
27
+ }
28
+ /**
29
+ * Create a debounced saver: `schedule()` queues a save after `delayMs` of
30
+ * inactivity, collapsing rapid successive calls into a single save of the latest
31
+ * data. `flush()` fires any pending save immediately (marked `keepalive: true`) —
32
+ * call it on unmount/navigation instead of just cancelling the timer, so in-flight
33
+ * changes are not lost.
34
+ *
35
+ * @example
36
+ * ```ts
37
+ * const saver = createDebouncedSaver<FormData>({
38
+ * delayMs: 2000,
39
+ * save: (data, { keepalive }) => fetch('/api/save', {
40
+ * method: 'POST',
41
+ * body: JSON.stringify(data),
42
+ * keepalive,
43
+ * }),
44
+ * });
45
+ *
46
+ * saver.schedule(formData); // fires after 2s of inactivity
47
+ * // on unmount:
48
+ * saver.flush(); // fires immediately with keepalive: true
49
+ * ```
50
+ */
51
+ export declare function createDebouncedSaver<T>(opts: CreateDebouncedSaverOptions<T>): DebouncedSaver<T>;
52
+ //# sourceMappingURL=debounced_saver.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounced_saver.d.ts","sourceRoot":"","sources":["../../src/utils/debounced_saver.ts"],"names":[],"mappings":"AAmBA,gFAAgF;AAChF,MAAM,WAAW,oBAAoB;IACnC;;;;OAIG;IACH,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,gDAAgD;AAChD,MAAM,WAAW,2BAA2B,CAAC,CAAC;IAC5C,uCAAuC;IACvC,OAAO,EAAE,MAAM,CAAC;IAChB,+DAA+D;IAC/D,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,EAAE,GAAG,EAAE,oBAAoB,KAAK,IAAI,CAAC;CACpD;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc,CAAC,CAAC;IAC/B,qFAAqF;IACrF,QAAQ,CAAC,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACxB,uGAAuG;IACvG,KAAK,IAAI,IAAI,CAAC;IACd,+CAA+C;IAC/C,MAAM,IAAI,IAAI,CAAC;IACf,qDAAqD;IACrD,UAAU,IAAI,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,oBAAoB,CAAC,CAAC,EACpC,IAAI,EAAE,2BAA2B,CAAC,CAAC,CAAC,GACnC,cAAc,CAAC,CAAC,CAAC,CAyCnB"}
@@ -0,0 +1,80 @@
1
+ // file_description: Framework-agnostic debounced saver with an explicit `flush()`.
2
+ //
3
+ // Built to fix a lost-write bug on a client-survey autosave: the page used a bare
4
+ // debounce timer that was *cancelled* on unmount, so any change made within the
5
+ // debounce window (notably an async result landing shortly before navigation) was
6
+ // silently discarded when the user navigated away.
7
+ //
8
+ // The fix is `flush()`: instead of cancelling the pending timer on unmount, the
9
+ // caller flushes it, firing the queued save immediately. The flush path is flagged
10
+ // `keepalive: true` in the callback context so the caller can issue a `keepalive`
11
+ // fetch that survives page teardown.
12
+ //
13
+ // Pure and IO-free: the actual persistence is the injected `save` callback, so this
14
+ // is unit-testable in a node environment with fake timers (no DOM/fetch required).
15
+ // Uses only `setTimeout`/`clearTimeout`, so it is browser-safe and exported from
16
+ // both the server and client entry points.
17
+ //
18
+ // Promoted from taxclientdocs' lib/debounced-save.ts into hazo_core.
19
+ /**
20
+ * Create a debounced saver: `schedule()` queues a save after `delayMs` of
21
+ * inactivity, collapsing rapid successive calls into a single save of the latest
22
+ * data. `flush()` fires any pending save immediately (marked `keepalive: true`) —
23
+ * call it on unmount/navigation instead of just cancelling the timer, so in-flight
24
+ * changes are not lost.
25
+ *
26
+ * @example
27
+ * ```ts
28
+ * const saver = createDebouncedSaver<FormData>({
29
+ * delayMs: 2000,
30
+ * save: (data, { keepalive }) => fetch('/api/save', {
31
+ * method: 'POST',
32
+ * body: JSON.stringify(data),
33
+ * keepalive,
34
+ * }),
35
+ * });
36
+ *
37
+ * saver.schedule(formData); // fires after 2s of inactivity
38
+ * // on unmount:
39
+ * saver.flush(); // fires immediately with keepalive: true
40
+ * ```
41
+ */
42
+ export function createDebouncedSaver(opts) {
43
+ const { delayMs, save } = opts;
44
+ let timer = null;
45
+ let pending = null;
46
+ const clearTimer = () => {
47
+ if (timer !== null) {
48
+ clearTimeout(timer);
49
+ timer = null;
50
+ }
51
+ };
52
+ return {
53
+ schedule(data) {
54
+ pending = { data };
55
+ clearTimer();
56
+ timer = setTimeout(() => {
57
+ timer = null;
58
+ const queued = pending;
59
+ pending = null;
60
+ if (queued)
61
+ save(queued.data, { keepalive: false });
62
+ }, delayMs);
63
+ },
64
+ flush() {
65
+ clearTimer();
66
+ const queued = pending;
67
+ pending = null;
68
+ if (queued)
69
+ save(queued.data, { keepalive: true });
70
+ },
71
+ cancel() {
72
+ clearTimer();
73
+ pending = null;
74
+ },
75
+ hasPending() {
76
+ return pending !== null;
77
+ },
78
+ };
79
+ }
80
+ //# sourceMappingURL=debounced_saver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"debounced_saver.js","sourceRoot":"","sources":["../../src/utils/debounced_saver.ts"],"names":[],"mappings":"AAAA,mFAAmF;AACnF,EAAE;AACF,kFAAkF;AAClF,gFAAgF;AAChF,kFAAkF;AAClF,mDAAmD;AACnD,EAAE;AACF,gFAAgF;AAChF,mFAAmF;AACnF,kFAAkF;AAClF,qCAAqC;AACrC,EAAE;AACF,oFAAoF;AACpF,mFAAmF;AACnF,iFAAiF;AACjF,2CAA2C;AAC3C,EAAE;AACF,qEAAqE;AAgCrE;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,UAAU,oBAAoB,CAClC,IAAoC;IAEpC,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE,GAAG,IAAI,CAAC;IAE/B,IAAI,KAAK,GAAyC,IAAI,CAAC;IACvD,IAAI,OAAO,GAAuB,IAAI,CAAC;IAEvC,MAAM,UAAU,GAAG,GAAS,EAAE;QAC5B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACnB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,KAAK,GAAG,IAAI,CAAC;QACf,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,QAAQ,CAAC,IAAO;YACd,OAAO,GAAG,EAAE,IAAI,EAAE,CAAC;YACnB,UAAU,EAAE,CAAC;YACb,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,KAAK,GAAG,IAAI,CAAC;gBACb,MAAM,MAAM,GAAG,OAAO,CAAC;gBACvB,OAAO,GAAG,IAAI,CAAC;gBACf,IAAI,MAAM;oBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACtD,CAAC,EAAE,OAAO,CAAC,CAAC;QACd,CAAC;QAED,KAAK;YACH,UAAU,EAAE,CAAC;YACb,MAAM,MAAM,GAAG,OAAO,CAAC;YACvB,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,MAAM;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,MAAM;YACJ,UAAU,EAAE,CAAC;YACb,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;QAED,UAAU;YACR,OAAO,OAAO,KAAK,IAAI,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -34,6 +34,11 @@ 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 { withRetry } from './retry.js';
38
+ export type { RetryOptions } from './retry.js';
39
+ export { isUuid } from './uuid.js';
40
+ export { createDebouncedSaver } from './debounced_saver.js';
41
+ export type { DebouncedSaveContext, CreateDebouncedSaverOptions, DebouncedSaver, } from './debounced_saver.js';
37
42
  /**
38
43
  * Format a date as "28 May 2026"
39
44
  */
@@ -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;AAU7C;;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,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAOvE;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,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD"}
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,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,SAAQ,GAAG,MAAM,CAOvE;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,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAOhD"}
@@ -88,6 +88,18 @@ export function formatBytes(bytes, decimals = 2) {
88
88
  // ---------------------------------------------------------------------------
89
89
  export { format_date, format_date_range, DEFAULT_DATE_FORMAT, } from './dates.js';
90
90
  // ---------------------------------------------------------------------------
91
+ // Retry with backoff
92
+ // ---------------------------------------------------------------------------
93
+ export { withRetry } from './retry.js';
94
+ // ---------------------------------------------------------------------------
95
+ // UUID validation
96
+ // ---------------------------------------------------------------------------
97
+ export { isUuid } from './uuid.js';
98
+ // ---------------------------------------------------------------------------
99
+ // Debounced saver
100
+ // ---------------------------------------------------------------------------
101
+ export { createDebouncedSaver } from './debounced_saver.js';
102
+ // ---------------------------------------------------------------------------
91
103
  // Date formatters
92
104
  // ---------------------------------------------------------------------------
93
105
  function toDate(date) {
@@ -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,34 @@
1
+ /** Options for {@link withRetry}. */
2
+ export interface RetryOptions {
3
+ /** Total number of attempts. Default 3. */
4
+ attempts?: number;
5
+ /** Base backoff delay in ms for the first wait. Default 500. */
6
+ baseDelayMs?: number;
7
+ /** Cap on backoff delay in ms. Default 2000. */
8
+ maxDelayMs?: number;
9
+ }
10
+ /**
11
+ * Run `fn` up to `attempts` times. Returns the first non-null/non-undefined result.
12
+ *
13
+ * A thrown error OR a null/undefined return is treated as a failed attempt and
14
+ * triggers a retry. Between attempts, waits with exponential backoff:
15
+ * `baseDelayMs`, `baseDelayMs * 2`, … capped at `maxDelayMs`. No wait after the
16
+ * final attempt. If every attempt fails (throws or returns null/undefined),
17
+ * resolves to `null`.
18
+ *
19
+ * @param fn Async function to execute on each attempt.
20
+ * @param opts Retry configuration (attempts, baseDelayMs, maxDelayMs).
21
+ * @param sleep Injectable sleep for tests; defaults to a setTimeout-based sleep.
22
+ * @example
23
+ * ```ts
24
+ * const result = await withRetry(
25
+ * () => fetchFlakyThing(),
26
+ * { attempts: 3, baseDelayMs: 500, maxDelayMs: 2000 },
27
+ * );
28
+ * if (result === null) {
29
+ * // every attempt failed
30
+ * }
31
+ * ```
32
+ */
33
+ export declare function withRetry<T>(fn: () => Promise<T | null>, opts?: RetryOptions, sleep?: (ms: number) => Promise<void>): Promise<T | null>;
34
+ //# sourceMappingURL=retry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.d.ts","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAQA,qCAAqC;AACrC,MAAM,WAAW,YAAY;IAC3B,2CAA2C;IAC3C,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAMD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAsB,SAAS,CAAC,CAAC,EAC/B,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,EAC3B,IAAI,CAAC,EAAE,YAAY,EACnB,KAAK,GAAE,CAAC,EAAE,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAgB,GAClD,OAAO,CAAC,CAAC,GAAG,IAAI,CAAC,CAyBnB"}
@@ -0,0 +1,56 @@
1
+ // file_description: Generic retry-with-exponential-backoff helper for transient,
2
+ // idempotent async calls (LLM calls, flaky external APIs, etc). Pure; no IO beyond
3
+ // the injectable `sleep` function, so it is unit-testable with fake timers.
4
+ //
5
+ // Promoted from taxclientdocs' lib/classification/retry.ts (withClassificationRetry)
6
+ // into hazo_core as a general-purpose helper — the retry/backoff shape has no
7
+ // classification-specific behaviour.
8
+ /** Default real sleep implementation. */
9
+ const defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
10
+ /**
11
+ * Run `fn` up to `attempts` times. Returns the first non-null/non-undefined result.
12
+ *
13
+ * A thrown error OR a null/undefined return is treated as a failed attempt and
14
+ * triggers a retry. Between attempts, waits with exponential backoff:
15
+ * `baseDelayMs`, `baseDelayMs * 2`, … capped at `maxDelayMs`. No wait after the
16
+ * final attempt. If every attempt fails (throws or returns null/undefined),
17
+ * resolves to `null`.
18
+ *
19
+ * @param fn Async function to execute on each attempt.
20
+ * @param opts Retry configuration (attempts, baseDelayMs, maxDelayMs).
21
+ * @param sleep Injectable sleep for tests; defaults to a setTimeout-based sleep.
22
+ * @example
23
+ * ```ts
24
+ * const result = await withRetry(
25
+ * () => fetchFlakyThing(),
26
+ * { attempts: 3, baseDelayMs: 500, maxDelayMs: 2000 },
27
+ * );
28
+ * if (result === null) {
29
+ * // every attempt failed
30
+ * }
31
+ * ```
32
+ */
33
+ export async function withRetry(fn, opts, sleep = defaultSleep) {
34
+ const attempts = opts?.attempts ?? 3;
35
+ const baseDelayMs = opts?.baseDelayMs ?? 500;
36
+ const maxDelayMs = opts?.maxDelayMs ?? 2000;
37
+ for (let attempt = 1; attempt <= attempts; attempt++) {
38
+ let result = null;
39
+ try {
40
+ result = await fn();
41
+ }
42
+ catch {
43
+ // Swallow transient errors and treat as a failed attempt.
44
+ }
45
+ if (result != null) {
46
+ return result;
47
+ }
48
+ // Wait before the next attempt, but not after the last one.
49
+ if (attempt < attempts) {
50
+ const delay = Math.min(baseDelayMs * Math.pow(2, attempt - 1), maxDelayMs);
51
+ await sleep(delay);
52
+ }
53
+ }
54
+ return null;
55
+ }
56
+ //# sourceMappingURL=retry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"retry.js","sourceRoot":"","sources":["../../src/utils/retry.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,mFAAmF;AACnF,4EAA4E;AAC5E,EAAE;AACF,qFAAqF;AACrF,8EAA8E;AAC9E,qCAAqC;AAYrC,yCAAyC;AACzC,MAAM,YAAY,GAAG,CAAC,EAAU,EAAiB,EAAE,CACjD,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,MAAM,CAAC,KAAK,UAAU,SAAS,CAC7B,EAA2B,EAC3B,IAAmB,EACnB,QAAuC,YAAY;IAEnD,MAAM,QAAQ,GAAG,IAAI,EAAE,QAAQ,IAAI,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,IAAI,EAAE,WAAW,IAAI,GAAG,CAAC;IAC7C,MAAM,UAAU,GAAG,IAAI,EAAE,UAAU,IAAI,IAAI,CAAC;IAE5C,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,QAAQ,EAAE,OAAO,EAAE,EAAE,CAAC;QACrD,IAAI,MAAM,GAAa,IAAI,CAAC;QAC5B,IAAI,CAAC;YACH,MAAM,GAAG,MAAM,EAAE,EAAE,CAAC;QACtB,CAAC;QAAC,MAAM,CAAC;YACP,0DAA0D;QAC5D,CAAC;QAED,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;YACnB,OAAO,MAAM,CAAC;QAChB,CAAC;QAED,4DAA4D;QAC5D,IAAI,OAAO,GAAG,QAAQ,EAAE,CAAC;YACvB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,CAAC;YAC3E,MAAM,KAAK,CAAC,KAAK,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * True iff `value` is a canonical 8-4-4-4-12 hex UUID (case-insensitive).
3
+ *
4
+ * @param value The candidate string; `null`/`undefined` return `false`.
5
+ * @example isUuid('f47ac10b-58cc-4372-a567-0e02b2c3d479') // true
6
+ * @example isUuid('f_1779965617794_qqz9a') // false
7
+ */
8
+ export declare function isUuid(value: string | null | undefined): boolean;
9
+ //# sourceMappingURL=uuid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.d.ts","sourceRoot":"","sources":["../../src/utils/uuid.ts"],"names":[],"mappings":"AAcA;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,OAAO,CAEhE"}
@@ -0,0 +1,22 @@
1
+ // file_description: UUID validation for API route parameters.
2
+ //
3
+ // Postgres/PostgREST-backed apps frequently accept a path/query id that must be a
4
+ // UUID before it's safe to send to `id=eq.<value>` — a non-UUID value (e.g. a
5
+ // synthetic client-generated id) causes an opaque "invalid input syntax for type
6
+ // uuid" 400 from PostgREST. Validating up front with `isUuid` lets routes return a
7
+ // clear, actionable error instead.
8
+ //
9
+ // Promoted from taxclientdocs' lib/api/uuid.ts into hazo_core — the check itself
10
+ // has no app-specific behaviour.
11
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
12
+ /**
13
+ * True iff `value` is a canonical 8-4-4-4-12 hex UUID (case-insensitive).
14
+ *
15
+ * @param value The candidate string; `null`/`undefined` return `false`.
16
+ * @example isUuid('f47ac10b-58cc-4372-a567-0e02b2c3d479') // true
17
+ * @example isUuid('f_1779965617794_qqz9a') // false
18
+ */
19
+ export function isUuid(value) {
20
+ return typeof value === 'string' && UUID_RE.test(value);
21
+ }
22
+ //# sourceMappingURL=uuid.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"uuid.js","sourceRoot":"","sources":["../../src/utils/uuid.ts"],"names":[],"mappings":"AAAA,8DAA8D;AAC9D,EAAE;AACF,kFAAkF;AAClF,8EAA8E;AAC9E,iFAAiF;AACjF,mFAAmF;AACnF,mCAAmC;AACnC,EAAE;AACF,iFAAiF;AACjF,iCAAiC;AAEjC,MAAM,OAAO,GACX,iEAAiE,CAAC;AAEpE;;;;;;GAMG;AACH,MAAM,UAAU,MAAM,CAAC,KAAgC;IACrD,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hazo_core",
3
- "version": "1.2.1",
3
+ "version": "1.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",
@@ -70,7 +70,7 @@
70
70
  },
71
71
  "peerDependencies": {
72
72
  "hazo_debug": "^3.1.1",
73
- "hazo_logs": "^2.0.3"
73
+ "hazo_logs": "^2.1.1"
74
74
  },
75
75
  "peerDependenciesMeta": {
76
76
  "hazo_logs": {