@nhtio/encoder 1.20260611.0 → 1.20260624.1

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/index.d.ts CHANGED
@@ -36,6 +36,17 @@ declare type CountryOrUnknown = Country | 'XX';
36
36
  */
37
37
  declare type CountryTimezone = 'Europe/Andorra' | 'Asia/Dubai' | 'Asia/Kabul' | 'America/Antigua' | 'America/Anguilla' | 'Europe/Tirane' | 'Asia/Yerevan' | 'Africa/Luanda' | 'Antarctica/Casey' | 'America/Argentina/Buenos_Aires' | 'Pacific/Pago_Pago' | 'Europe/Vienna' | 'Australia/Sydney' | 'America/Aruba' | 'Europe/Mariehamn' | 'Asia/Baku' | 'Europe/Sarajevo' | 'America/Barbados' | 'Asia/Dhaka' | 'Europe/Brussels' | 'Africa/Ouagadougou' | 'Europe/Sofia' | 'Asia/Bahrain' | 'Africa/Bujumbura' | 'Africa/Porto-Novo' | 'America/St_Barthelemy' | 'Atlantic/Bermuda' | 'Asia/Brunei' | 'America/La_Paz' | 'America/Kralendijk' | 'America/Sao_Paulo' | 'America/Nassau' | 'Asia/Thimphu' | 'Africa/Gaborone' | 'Europe/Minsk' | 'America/Belize' | 'America/Toronto' | 'Indian/Cocos' | 'Africa/Kinshasa' | 'Africa/Bangui' | 'Africa/Brazzaville' | 'Europe/Zurich' | 'Africa/Abidjan' | 'Pacific/Rarotonga' | 'America/Santiago' | 'Africa/Douala' | 'Asia/Shanghai' | 'America/Bogota' | 'America/Costa_Rica' | 'America/Havana' | 'Atlantic/Cape_Verde' | 'America/Curacao' | 'Indian/Christmas' | 'Asia/Nicosia' | 'Europe/Prague' | 'Europe/Berlin' | 'Africa/Djibouti' | 'Europe/Copenhagen' | 'America/Dominica' | 'America/Santo_Domingo' | 'Africa/Algiers' | 'America/Guayaquil' | 'Europe/Tallinn' | 'Africa/Cairo' | 'Africa/El_Aaiun' | 'Africa/Asmara' | 'Europe/Madrid' | 'Africa/Addis_Ababa' | 'Europe/Helsinki' | 'Pacific/Fiji' | 'Atlantic/Stanley' | 'Pacific/Pohnpei' | 'Atlantic/Faroe' | 'Europe/Paris' | 'Africa/Libreville' | 'Europe/London' | 'America/Grenada' | 'Asia/Tbilisi' | 'America/Cayenne' | 'Europe/Guernsey' | 'Africa/Accra' | 'Europe/Gibraltar' | 'America/Godthab' | 'Africa/Banjul' | 'Africa/Conakry' | 'America/Guadeloupe' | 'Africa/Malabo' | 'Europe/Athens' | 'Atlantic/South_Georgia' | 'America/Guatemala' | 'Pacific/Guam' | 'Africa/Bissau' | 'America/Guyana' | 'Asia/Hong_Kong' | 'America/Tegucigalpa' | 'Europe/Zagreb' | 'America/Port-au-Prince' | 'Europe/Budapest' | 'Asia/Jakarta' | 'Europe/Dublin' | 'Asia/Jerusalem' | 'Europe/Isle_of_Man' | 'Asia/Kolkata' | 'Indian/Chagos' | 'Asia/Baghdad' | 'Asia/Tehran' | 'Atlantic/Reykjavik' | 'Europe/Rome' | 'Europe/Jersey' | 'America/Jamaica' | 'Asia/Amman' | 'Asia/Tokyo' | 'Africa/Nairobi' | 'Asia/Bishkek' | 'Asia/Phnom_Penh' | 'Pacific/Tarawa' | 'Indian/Comoro' | 'America/St_Kitts' | 'Asia/Pyongyang' | 'Asia/Seoul' | 'Asia/Kuwait' | 'America/Cayman' | 'Asia/Almaty' | 'Asia/Vientiane' | 'Asia/Beirut' | 'America/St_Lucia' | 'Europe/Vaduz' | 'Asia/Colombo' | 'Africa/Monrovia' | 'Africa/Maseru' | 'Europe/Vilnius' | 'Europe/Luxembourg' | 'Europe/Riga' | 'Africa/Tripoli' | 'Africa/Casablanca' | 'Europe/Monaco' | 'Europe/Chisinau' | 'Europe/Podgorica' | 'America/Marigot' | 'Indian/Antananarivo' | 'Pacific/Majuro' | 'Europe/Skopje' | 'Africa/Bamako' | 'Asia/Yangon' | 'Asia/Ulaanbaatar' | 'Asia/Macau' | 'Pacific/Saipan' | 'America/Martinique' | 'Africa/Nouakchott' | 'America/Montserrat' | 'Europe/Malta' | 'Indian/Mauritius' | 'Indian/Maldives' | 'Africa/Blantyre' | 'America/Mexico_City' | 'Asia/Kuala_Lumpur' | 'Africa/Maputo' | 'Africa/Windhoek' | 'Pacific/Noumea' | 'Africa/Niamey' | 'Pacific/Norfolk' | 'Africa/Lagos' | 'America/Managua' | 'Europe/Amsterdam' | 'Europe/Oslo' | 'Asia/Kathmandu' | 'Pacific/Nauru' | 'Pacific/Niue' | 'Pacific/Auckland' | 'Asia/Muscat' | 'America/Panama' | 'America/Lima' | 'Pacific/Tahiti' | 'Pacific/Port_Moresby' | 'Asia/Manila' | 'Asia/Karachi' | 'Europe/Warsaw' | 'America/Miquelon' | 'Pacific/Pitcairn' | 'America/Puerto_Rico' | 'Asia/Gaza' | 'Europe/Lisbon' | 'Pacific/Palau' | 'America/Asuncion' | 'Asia/Qatar' | 'Indian/Reunion' | 'Europe/Bucharest' | 'Europe/Belgrade' | 'Europe/Moscow' | 'Africa/Kigali' | 'Asia/Riyadh' | 'Pacific/Guadalcanal' | 'Indian/Mahe' | 'Africa/Khartoum' | 'Europe/Stockholm' | 'Asia/Singapore' | 'Atlantic/St_Helena' | 'Europe/Ljubljana' | 'Arctic/Longyearbyen' | 'Europe/Bratislava' | 'Africa/Freetown' | 'Europe/San_Marino' | 'Africa/Dakar' | 'Africa/Mogadishu' | 'America/Paramaribo' | 'Africa/Juba' | 'Africa/Sao_Tome' | 'America/El_Salvador' | 'America/Lower_Princes' | 'Asia/Damascus' | 'Africa/Mbabane' | 'America/Grand_Turk' | 'Africa/Ndjamena' | 'Indian/Kerguelen' | 'Africa/Lome' | 'Asia/Bangkok' | 'Asia/Dushanbe' | 'Pacific/Fakaofo' | 'Asia/Dili' | 'Asia/Ashgabat' | 'Africa/Tunis' | 'Pacific/Tongatapu' | 'Europe/Istanbul' | 'America/Port_of_Spain' | 'Pacific/Funafuti' | 'Asia/Taipei' | 'Africa/Dar_es_Salaam' | 'Europe/Kiev' | 'Africa/Kampala' | 'Pacific/Wake' | 'America/New_York' | 'America/Montevideo' | 'Asia/Tashkent' | 'Europe/Vatican' | 'America/St_Vincent' | 'America/Caracas' | 'America/Tortola' | 'America/St_Thomas' | 'Asia/Ho_Chi_Minh' | 'Pacific/Efate' | 'Pacific/Wallis' | 'Pacific/Apia' | 'Asia/Aden' | 'Indian/Mayotte' | 'Africa/Johannesburg' | 'Africa/Lusaka' | 'Africa/Harare';
38
38
 
39
+ /**
40
+ * A class that opts in to custom encoding/decoding.
41
+ *
42
+ * Implement `[ENCODE_METHOD]()` on instances to produce an Encodable snapshot,
43
+ * and `static [DECODE_METHOD](data)` to reconstruct the instance.
44
+ * Pass the class to `registerClass()` so the decoder can find it.
45
+ */
46
+ export declare interface CustomEncodable {
47
+ [ENCODE_METHOD](): Encodable;
48
+ }
49
+
39
50
  declare type DateInput = DateTime | DateObjectUnits | Date;
40
51
 
41
52
  /**
@@ -1485,6 +1496,11 @@ declare type DayNumbers =
1485
1496
  | 30
1486
1497
  | 31;
1487
1498
 
1499
+ declare interface DecodableConstructor {
1500
+ readonly name: string;
1501
+ [DECODE_METHOD](data: Encodable): any;
1502
+ }
1503
+
1488
1504
  /**
1489
1505
  * Decodes a compressed base64 string back into a value
1490
1506
  * @param base64 The compressed base64 string representing an encoded value
@@ -1496,6 +1512,9 @@ declare type DayNumbers =
1496
1512
  */
1497
1513
  export declare const decode: <T extends Encodable = Encodable>(base64: string) => T;
1498
1514
 
1515
+ /** Static method: reconstruct an instance from an Encodable snapshot */
1516
+ export declare const DECODE_METHOD: unique symbol;
1517
+
1499
1518
  declare type DefaultValidity = CanBeInvalid extends true ? boolean : true;
1500
1519
 
1501
1520
  declare interface DiffOptions {
@@ -1996,7 +2015,7 @@ declare type DurationUnits = DurationUnit | DurationUnit[];
1996
2015
  */
1997
2016
  export declare type Encodable = EncodablePrimitive | Date | RegExp | ArrayBuffer | DataView | DateTime | Duration | Interval | EncodableTypedArray | Encodable[] | {
1998
2017
  [key: string]: Encodable;
1999
- } | Map<Encodable, Encodable> | Set<Encodable> | Error | EvalError | RangeError | ReferenceError | SyntaxError | TypeError | URIError | PhoneModel | Function | ((...args: any[]) => any);
2018
+ } | Map<Encodable, Encodable> | Set<Encodable> | Error | EvalError | RangeError | ReferenceError | SyntaxError | TypeError | URIError | PhoneModel | Function | ((...args: any[]) => any) | CustomEncodable;
2000
2019
 
2001
2020
  /**
2002
2021
  * Defines the union of all encodable primitive types.
@@ -2018,6 +2037,9 @@ export declare type EncodableTypedArray = Int8Array | Uint8Array | Uint8ClampedA
2018
2037
  */
2019
2038
  export declare const encode: <T extends Encodable = Encodable>(what: T) => string;
2020
2039
 
2040
+ /** Instance method: serialize the object into an Encodable snapshot */
2041
+ export declare const ENCODE_METHOD: unique symbol;
2042
+
2021
2043
  declare type EndOfOptions = _UseLocaleWeekOption;
2022
2044
 
2023
2045
  declare interface ExplainedFormat {
@@ -2638,6 +2660,15 @@ declare type PossibleWeeksInYear = 52 | 53;
2638
2660
 
2639
2661
  declare type QuarterNumbers = 1 | 2 | 3 | 4;
2640
2662
 
2663
+ /**
2664
+ * Register a class so the decoder can reconstruct it from a snapshot.
2665
+ * The class must have a static `[DECODE_METHOD]` that accepts an Encodable
2666
+ * snapshot and returns an instance of the class.
2667
+ *
2668
+ * @param ctor - The class constructor to register
2669
+ */
2670
+ export declare const registerClass: (ctor: DecodableConstructor) => void;
2671
+
2641
2672
  declare type ResolvedLocaleOptions = Required<LocaleOptions>;
2642
2673
 
2643
2674
  declare type SecondNumbers =
package/index.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { i as isObject, a as isArray, b as isSet, c as isMap, d as isLuxonSystemZone, e as isLuxonInterval, f as isLuxonDuration, g as isLuxonDateTime, h as isPhoneObject, j as isTypedArray, k as isBigIntTypedArray, l as isPrimitive, m as isUniterableObject, n as isError, o as isBigInt, p as isUnsafeInteger, q as isNegativeInfinity, r as isPositiveInfinity, s as isNegativeZero, I as Info, t as Interval, D as DateTime, u as Duration, P as Phone } from "./type_guards-UkDoe__i.mjs";
1
+ import { i as isObject, a as isCustomEncodable, E as ENCODE_METHOD, b as isArray, c as isSet, d as isMap, e as isLuxonSystemZone, f as isLuxonInterval, I as Interval, D as DateTime, g as isLuxonDuration, h as Duration, j as isLuxonDateTime, k as isPhoneObject, l as isTypedArray, m as isBigIntTypedArray, n as isPrimitive, o as isUniterableObject, p as isError, q as isBigInt, r as isUnsafeInteger, s as isNegativeInfinity, t as isPositiveInfinity, u as isNegativeZero, v as DECODE_METHOD, w as Info, P as Phone } from "./type_guards-DMqlMT2e.mjs";
2
2
  import { FunctionSerializer } from "./function_serializer.mjs";
3
- import { E as E_UNENCODABLE_VALUE, a as E_CIRCULAR_REFERENCE, b as E_ENCODING_FAILED, B as BaseException, c as E_UNDECODABLE_VALUE, d as E_NOT_AN_ENCODED_VALUE, e as E_INVALID_VERSION, f as E_INCOMPATIBLE_VERSION } from "./exceptions-WJOP87c3.mjs";
3
+ import { E as E_UNENCODABLE_VALUE, a as E_CIRCULAR_REFERENCE, b as E_ENCODING_FAILED, B as BaseException, c as E_UNDECODABLE_VALUE, d as E_NOT_AN_ENCODED_VALUE, e as E_INVALID_VERSION, f as E_INCOMPATIBLE_VERSION } from "./exceptions-CqtGXEDJ.mjs";
4
4
  var re = { exports: {} };
5
5
  var constants;
6
6
  var hasRequiredConstants;
@@ -2728,6 +2728,16 @@ const atou = (base64) => {
2728
2728
  }
2729
2729
  return decodeURIComponent(escape(binary));
2730
2730
  };
2731
+ const registry = /* @__PURE__ */ new Map();
2732
+ const registerClass = (ctor) => {
2733
+ if (typeof ctor.name !== "string" || ctor.name === "") {
2734
+ throw new TypeError("Cannot register an anonymous class — give it an explicit name.");
2735
+ }
2736
+ registry.set(ctor.name, ctor);
2737
+ };
2738
+ const getRegisteredClass = (name) => {
2739
+ return registry.get(name);
2740
+ };
2731
2741
  const VOID = -1;
2732
2742
  const PRIMITIVE = 0;
2733
2743
  const ARRAY = 1;
@@ -2936,6 +2946,13 @@ const serialize = (value, { json, lossy } = {}) => {
2936
2946
  const stripUndefinedValuesFromObject = (obj) => {
2937
2947
  return Object.fromEntries(Object.entries(obj).filter(([_, value]) => value !== void 0));
2938
2948
  };
2949
+ const fixedOffsetToZoneName = (fixed) => {
2950
+ const sign = fixed >= 0 ? "+" : "-";
2951
+ const abs = Math.abs(fixed);
2952
+ const hours = Math.floor(abs / 60);
2953
+ const minutes = abs % 60;
2954
+ return minutes === 0 ? `UTC${sign}${hours}` : `UTC${sign}${hours}:${String(minutes).padStart(2, "0")}`;
2955
+ };
2939
2956
  const toStructuredData = (value, seen = /* @__PURE__ */ new WeakSet()) => {
2940
2957
  switch (true) {
2941
2958
  case isNegativeZero(value): {
@@ -3025,7 +3042,19 @@ const toStructuredData = (value, seen = /* @__PURE__ */ new WeakSet()) => {
3025
3042
  throw new E_CIRCULAR_REFERENCE();
3026
3043
  }
3027
3044
  seen.add(value);
3028
- const dto = value;
3045
+ const dto = value instanceof DateTime ? value : typeof value.toMillis === "function" ? value : (() => {
3046
+ const raw = value;
3047
+ const zone = raw._zone && typeof raw._zone.zoneName === "string" ? raw._zone.zoneName : raw._zone && typeof raw._zone.fixed === "number" ? fixedOffsetToZoneName(raw._zone.fixed) : void 0;
3048
+ const locale = raw.loc && typeof raw.loc.locale === "string" ? raw.loc.locale : void 0;
3049
+ const outputCalendar = raw.loc && typeof raw.loc.outputCalendar === "string" ? raw.loc.outputCalendar : void 0;
3050
+ const numberingSystem = raw.loc && typeof raw.loc.numberingSystem === "string" ? raw.loc.numberingSystem : void 0;
3051
+ return DateTime.fromMillis(typeof raw.ts === "number" ? raw.ts : 0, {
3052
+ zone,
3053
+ locale,
3054
+ outputCalendar,
3055
+ numberingSystem
3056
+ });
3057
+ })();
3029
3058
  return {
3030
3059
  _t: "luxon:DateTime",
3031
3060
  _s: toStructuredData(
@@ -3045,16 +3074,27 @@ const toStructuredData = (value, seen = /* @__PURE__ */ new WeakSet()) => {
3045
3074
  throw new E_CIRCULAR_REFERENCE();
3046
3075
  }
3047
3076
  seen.add(value);
3077
+ const dur = value instanceof Duration ? value : typeof value.get === "function" ? value : (() => {
3078
+ const raw = value;
3079
+ const locale = raw.loc && typeof raw.loc.locale === "string" ? raw.loc.locale : void 0;
3080
+ const rawValues = raw.values && typeof raw.values === "object" ? raw.values : {};
3081
+ const values = Object.fromEntries(
3082
+ Object.entries(rawValues).filter(
3083
+ ([, val]) => typeof val === "number" && Number.isFinite(val)
3084
+ )
3085
+ );
3086
+ return Duration.fromObject(values, { locale });
3087
+ })();
3048
3088
  const dto = {
3049
- years: value.years,
3050
- quarters: value.quarters,
3051
- months: value.months,
3052
- weeks: value.weeks,
3053
- days: value.days,
3054
- hours: value.hours,
3055
- minutes: value.minutes,
3056
- seconds: value.seconds,
3057
- milliseconds: value.milliseconds
3089
+ years: dur.years,
3090
+ quarters: dur.quarters,
3091
+ months: dur.months,
3092
+ weeks: dur.weeks,
3093
+ days: dur.days,
3094
+ hours: dur.hours,
3095
+ minutes: dur.minutes,
3096
+ seconds: dur.seconds,
3097
+ milliseconds: dur.milliseconds
3058
3098
  };
3059
3099
  Object.entries(dto).forEach(([key, val]) => {
3060
3100
  if (Number.isNaN(val) || val === 0) {
@@ -3071,8 +3111,17 @@ const toStructuredData = (value, seen = /* @__PURE__ */ new WeakSet()) => {
3071
3111
  throw new E_CIRCULAR_REFERENCE();
3072
3112
  }
3073
3113
  seen.add(value);
3074
- const start = value.start ? value.start.toISO({ extendedZone: true }) : null;
3075
- const end = value.end ? value.end.toISO({ extendedZone: true }) : null;
3114
+ const iv = value instanceof Interval ? value : typeof value.toISO === "function" ? value : (() => {
3115
+ const raw = value;
3116
+ const startMs = raw.s && typeof raw.s.ts === "number" ? raw.s.ts : null;
3117
+ const endMs = raw.e && typeof raw.e.ts === "number" ? raw.e.ts : null;
3118
+ return Interval.fromDateTimes(
3119
+ startMs !== null ? DateTime.fromMillis(startMs) : DateTime.invalid("missing start"),
3120
+ endMs !== null ? DateTime.fromMillis(endMs) : DateTime.invalid("missing end")
3121
+ );
3122
+ })();
3123
+ const start = iv.start ? iv.start.toISO({ extendedZone: true }) : null;
3124
+ const end = iv.end ? iv.end.toISO({ extendedZone: true }) : null;
3076
3125
  if (!start || !end) {
3077
3126
  throw new E_UNENCODABLE_VALUE(value);
3078
3127
  }
@@ -3134,6 +3183,25 @@ const toStructuredData = (value, seen = /* @__PURE__ */ new WeakSet()) => {
3134
3183
  _s: utoa(JSON.stringify(value.map((item) => toStructuredData(item, seen))))
3135
3184
  };
3136
3185
  }
3186
+ case isCustomEncodable(value): {
3187
+ if (seen.has(value)) {
3188
+ throw new E_CIRCULAR_REFERENCE();
3189
+ }
3190
+ seen.add(value);
3191
+ const className = value.constructor.name;
3192
+ try {
3193
+ const snapshot = value[ENCODE_METHOD]();
3194
+ return {
3195
+ _t: `custom:${className}`,
3196
+ _s: toStructuredData(snapshot, seen)
3197
+ };
3198
+ } catch (e) {
3199
+ if (e instanceof BaseException) {
3200
+ throw e;
3201
+ }
3202
+ throw new E_ENCODING_FAILED(value, e);
3203
+ }
3204
+ }
3137
3205
  case isObject(value): {
3138
3206
  if (seen.has(value)) {
3139
3207
  throw new E_CIRCULAR_REFERENCE();
@@ -3260,19 +3328,44 @@ const fromStructuredData = (data) => {
3260
3328
  throw err2;
3261
3329
  }
3262
3330
  }
3263
- default:
3331
+ default: {
3332
+ if (data._t.startsWith("custom:")) {
3333
+ const className = data._t.slice("custom:".length);
3334
+ const ctor = getRegisteredClass(className);
3335
+ if (!ctor) {
3336
+ const err2 = new E_UNDECODABLE_VALUE(data._t);
3337
+ err2.cause = new Error(
3338
+ `No class registered for "${className}". Call registerClass(${className}) before decoding.`
3339
+ );
3340
+ throw err2;
3341
+ }
3342
+ try {
3343
+ const snapshot = fromStructuredData(data._s);
3344
+ return ctor[DECODE_METHOD](snapshot);
3345
+ } catch (e) {
3346
+ if (e instanceof BaseException) {
3347
+ throw e;
3348
+ }
3349
+ const err2 = new E_UNDECODABLE_VALUE(data._t);
3350
+ if (e instanceof Error) {
3351
+ err2.cause = e;
3352
+ }
3353
+ throw err2;
3354
+ }
3355
+ }
3264
3356
  throw new E_UNDECODABLE_VALUE(data._t);
3357
+ }
3265
3358
  }
3266
3359
  };
3267
3360
  const { parse: $parse, stringify: $stringify } = JSON;
3268
3361
  const options = { json: true, lossy: true };
3269
3362
  const parse = (str) => deserialize($parse(str));
3270
3363
  const stringify = (any) => $stringify(serialize(any, options));
3271
- const version = "1.20260611.0";
3364
+ const version = "1.20260624.1";
3272
3365
  const encode = (what) => {
3273
3366
  const structured = toStructuredData(what);
3274
3367
  const serialized = serialize(structured, { lossy: true, json: true });
3275
- const json = stringify({ version: "1.20260611.0", serialized });
3368
+ const json = stringify({ version: "1.20260624.1", serialized });
3276
3369
  return utoa(json);
3277
3370
  };
3278
3371
  const decode = (base64) => {
@@ -3283,11 +3376,11 @@ const decode = (base64) => {
3283
3376
  throw new E_NOT_AN_ENCODED_VALUE(base64);
3284
3377
  }
3285
3378
  const { version: payloadVersion, serialized } = parsed;
3286
- if (semverExports.valid("1.20260611.0")) {
3379
+ if (semverExports.valid("1.20260624.1")) {
3287
3380
  if (!semverExports.valid(semverExports.coerce(payloadVersion))) {
3288
3381
  throw new E_INVALID_VERSION(payloadVersion);
3289
3382
  }
3290
- if (semverExports.gt(semverExports.coerce(payloadVersion), "1.20260611.0")) {
3383
+ if (semverExports.gt(semverExports.coerce(payloadVersion), "1.20260624.1")) {
3291
3384
  throw new E_INCOMPATIBLE_VERSION(payloadVersion);
3292
3385
  }
3293
3386
  }
@@ -3303,8 +3396,11 @@ const decode = (base64) => {
3303
3396
  }
3304
3397
  };
3305
3398
  export {
3399
+ DECODE_METHOD,
3400
+ ENCODE_METHOD,
3306
3401
  decode,
3307
3402
  encode,
3403
+ registerClass,
3308
3404
  version
3309
3405
  };
3310
3406
  //# sourceMappingURL=index.mjs.map