@magmacomputing/tempo-plugin-geo 1.3.0 → 1.4.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/dist/index.js CHANGED
@@ -274,7 +274,7 @@ function isNumeric(str) {
274
274
  return false;
275
275
  }
276
276
  }
277
- var isType, isPrimitive, isReference, isIterable, isString, isText, isNumber, RE_BIGINT_LITERAL, isInteger, isArray, isArrayLike, isObject, isDate, isRegExp, isSymbol, isSymbolFor, isSafeKey, isNullish, isUndefined, isDefined, isFunction, isCallable, isMap, isSet, isError, isLocale, isEmpty;
277
+ var isType, isPrimitive, isReference, isIterable, isString, isText, isNumber, RE_BIGINT_LITERAL, isInteger, isBoolean, isArray, isArrayLike, isObject, isDate, isRegExp, isSymbol, isSymbolFor, isSafeKey, isNullish, isUndefined, isDefined, isFunction, isCallable, isMap, isSet, isError, isLocale, isEmpty;
278
278
  var init_assertion_library = __esm({
279
279
  "../../library/dist/common/primitives/assertion.library.js"() {
280
280
  "use strict";
@@ -289,6 +289,7 @@ var init_assertion_library = __esm({
289
289
  isNumber = (obj) => Number.isFinite(obj);
290
290
  RE_BIGINT_LITERAL = /^[+-]?[0-9]+n$/;
291
291
  isInteger = (obj) => typeof obj === "bigint";
292
+ isBoolean = (obj) => typeof obj === "boolean";
292
293
  isArray = (obj) => Array.isArray(obj);
293
294
  isArrayLike = (obj) => protoType(obj) === "Object" && "length" in obj && Object.keys(obj).every((key) => key === "length" || isNumber(Number(key)));
294
295
  isObject = (obj) => isType(obj, "Object");
@@ -2774,8 +2775,8 @@ __export(sdk_exports, {
2774
2775
  __reExport(sdk_exports, sdk_star);
2775
2776
  import * as sdk_star from "@magmacomputing/tempo/plugin/sdk";
2776
2777
  import { definePlugin as originalPlugin, defineTerm as originalTerm } from "@magmacomputing/tempo/plugin/sdk";
2777
- var definePlugin = (config) => originalPlugin({ ...config, version: "1.3.0" });
2778
- var defineTerm = (config) => originalTerm({ ...config, version: "1.3.0" });
2778
+ var definePlugin = (config) => originalPlugin({ ...config, version: "1.4.1" });
2779
+ var defineTerm = (config) => originalTerm({ ...config, version: "1.4.1" });
2779
2780
 
2780
2781
  // ../../library/dist/common/runtime/mapper.library.js
2781
2782
  init_utility_library();
@@ -2794,9 +2795,13 @@ function evaluate(...values) {
2794
2795
  }
2795
2796
 
2796
2797
  // ../../library/dist/common/runtime/mapper.library.js
2797
- init_international_library();
2798
+ init_cache_class();
2798
2799
  var MAP_KEY2 = "_magma_geo_";
2799
2800
  var DEFAULT_GEO_TTL = 24 * 60 * 60 * 1e3;
2801
+ var DEFAULT_REVERSE_GEO_ENDPOINT = "https://api.bigdatacloud.net/data/reverse-geocode-client";
2802
+ var DEFAULT_REVERSE_GEO_TIMEOUT = 3e3;
2803
+ var DEFAULT_REVERSE_GEO_MAX_BYTES = 64 * 1024;
2804
+ var DEFAULT_SPATIAL_CACHE_SIZE = 1e3;
2800
2805
  var GEO_PROPERTIES = [
2801
2806
  "latitude",
2802
2807
  "lat",
@@ -2811,13 +2816,33 @@ var GEO_PROPERTIES = [
2811
2816
  "timezone",
2812
2817
  "tz"
2813
2818
  ];
2814
- var normalizeLat = (lat) => isNumber(lat) && lat >= -90 && lat <= 90 ? Math.round(lat * 1e3) / 1e3 : void 0;
2815
- var normalizeLng = (lng) => isNumber(lng) && lng >= -180 && lng <= 180 ? Math.round(lng * 1e3) / 1e3 : void 0;
2816
- var normalizeCoords = (lat, lng) => {
2817
- const nLat = normalizeLat(lat);
2818
- const nLng = normalizeLng(lng);
2819
- return nLat !== void 0 && nLng !== void 0 ? { lat: nLat, lng: nLng } : void 0;
2819
+ var parseCoordNumber = (val) => {
2820
+ if (!isDefined(val) || isBoolean(val))
2821
+ return NaN;
2822
+ if (isString(val)) {
2823
+ const trimmed = val.trim();
2824
+ return trimmed.length > 0 ? Number(trimmed) : NaN;
2825
+ }
2826
+ return isNumber(val) ? val : NaN;
2820
2827
  };
2828
+ var normalizeLat = (lat, round = true) => {
2829
+ const n = parseCoordNumber(lat);
2830
+ if (!isNumber(n) || n < -90 || n > 90)
2831
+ return void 0;
2832
+ return round ? Math.round(n * 1e3) / 1e3 : n;
2833
+ };
2834
+ var normalizeLng = (lng, round = true) => {
2835
+ const n = parseCoordNumber(lng);
2836
+ if (!isNumber(n) || n < -180 || n > 180)
2837
+ return void 0;
2838
+ return round ? Math.round(n * 1e3) / 1e3 : n;
2839
+ };
2840
+ var normalizeCoords = (lat, lng, round = true) => {
2841
+ const nLat = normalizeLat(lat, round);
2842
+ const nLng = normalizeLng(lng, round);
2843
+ return isDefined(nLat) && isDefined(nLng) ? { lat: nLat, lng: nLng } : void 0;
2844
+ };
2845
+ var normalizeElevation = (elevation) => isNumber(elevation) ? Math.round(elevation * 1e3) / 1e3 : void 0;
2821
2846
  var resolveSphere = (sphere, lat) => {
2822
2847
  if (sphere === "north" || sphere === "south" || sphere === "equator")
2823
2848
  return sphere;
@@ -2825,35 +2850,47 @@ var resolveSphere = (sphere, lat) => {
2825
2850
  return lat > 1e-3 ? "north" : lat < -1e-3 ? "south" : "equator";
2826
2851
  return void 0;
2827
2852
  };
2828
- var coerceGeo = (input) => {
2853
+ var parseCoordinatePair = (input, normalize = true) => {
2829
2854
  if (isString(input) && input.includes(",")) {
2830
- const segments = input.split(",").map((s) => s.trim());
2831
- const parts = segments.map((s) => s === "" ? NaN : Number(s));
2832
- if (parts.length >= 2 && !isNaN(parts[0]) && !isNaN(parts[1])) {
2833
- const coords = normalizeCoords(parts[0], parts[1]);
2834
- if (coords) {
2835
- const result2 = { latitude: coords.lat, longitude: coords.lng };
2836
- const sphere2 = resolveSphere(void 0, coords.lat);
2837
- if (sphere2)
2838
- result2.sphere = sphere2;
2839
- return result2;
2855
+ const parts = input.split(",").map((s) => s.trim());
2856
+ return parts.length >= 2 ? normalizeCoords(parts[0], parts[1], normalize) : void 0;
2857
+ }
2858
+ return Array.isArray(input) && input.length >= 2 ? normalizeCoords(input[0], input[1], normalize) : void 0;
2859
+ };
2860
+ var assembleGeoConfig = (coords, meta) => {
2861
+ const lat = "lat" in coords ? coords.lat : coords.latitude;
2862
+ const lng = "lng" in coords ? coords.lng : coords.longitude;
2863
+ const nLat = normalizeLat(lat);
2864
+ const nLng = normalizeLng(lng);
2865
+ const sphere = resolveSphere(meta?.sphere, nLat ?? lat);
2866
+ const elevation = normalizeElevation(meta?.elevation);
2867
+ return {
2868
+ latitude: nLat ?? lat,
2869
+ longitude: nLng ?? lng,
2870
+ ...sphere ? { sphere } : {},
2871
+ ...isString(meta?.city) && !isEmpty(meta.city) ? { city: meta.city.trim() } : {},
2872
+ ...isString(meta?.country) && !isEmpty(meta.country) ? { country: meta.country.trim() } : {},
2873
+ ...elevation !== void 0 ? { elevation } : {},
2874
+ ...isString(meta?.timezone) && !isEmpty(meta.timezone) ? { timezone: meta.timezone.trim() } : {}
2875
+ };
2876
+ };
2877
+ var extractCustomProperties = (source, excludedKeys = GEO_PROPERTIES) => {
2878
+ const custom = {};
2879
+ if (isReference(source)) {
2880
+ for (const key of Object.keys(source)) {
2881
+ if (isSafeKey(key) && !excludedKeys.includes(key)) {
2882
+ custom[key] = source[key];
2840
2883
  }
2841
2884
  }
2842
- return void 0;
2843
2885
  }
2886
+ return custom;
2887
+ };
2888
+ var coerceGeo = (input) => {
2889
+ const pair = parseCoordinatePair(input);
2890
+ if (pair)
2891
+ return assembleGeoConfig(pair);
2844
2892
  if (isPrimitive(input))
2845
2893
  return void 0;
2846
- if (Array.isArray(input) && input.length >= 2) {
2847
- const coords = normalizeCoords(input[0], input[1]);
2848
- if (coords) {
2849
- const result2 = { latitude: coords.lat, longitude: coords.lng };
2850
- const sphere2 = resolveSphere(void 0, coords.lat);
2851
- if (sphere2)
2852
- result2.sphere = sphere2;
2853
- return result2;
2854
- }
2855
- return void 0;
2856
- }
2857
2894
  const geo = input.geo ?? input;
2858
2895
  const cfg = input.config?.geo ?? input.config;
2859
2896
  const lat = evaluate(geo?.latitude, geo?.lat, input.latitude, input.lat, cfg?.latitude, cfg?.lat);
@@ -2870,8 +2907,9 @@ var coerceGeo = (input) => {
2870
2907
  result.latitude = nLat;
2871
2908
  if (nLng !== void 0)
2872
2909
  result.longitude = nLng;
2873
- if (isNumber(elevation))
2874
- result.elevation = Math.round(elevation * 1e3) / 1e3;
2910
+ const nElevation = normalizeElevation(elevation);
2911
+ if (nElevation !== void 0)
2912
+ result.elevation = nElevation;
2875
2913
  const resolvedSphere = resolveSphere(sphere, result.latitude);
2876
2914
  if (resolvedSphere)
2877
2915
  result.sphere = resolvedSphere;
@@ -2882,12 +2920,8 @@ var coerceGeo = (input) => {
2882
2920
  if (isString(timezone))
2883
2921
  result.timezone = timezone;
2884
2922
  const explicitGeo = isReference(input.geo) ? input.geo : isReference(input.config?.geo) ? input.config.geo : void 0;
2885
- if (isReference(explicitGeo)) {
2886
- for (const key of Object.keys(explicitGeo)) {
2887
- if (isSafeKey(key) && !GEO_PROPERTIES.includes(key))
2888
- result[key] = explicitGeo[key];
2889
- }
2890
- }
2923
+ const customKeys = extractCustomProperties(explicitGeo);
2924
+ Object.assign(result, customKeys);
2891
2925
  return Object.keys(result).length > 0 ? result : void 0;
2892
2926
  };
2893
2927
  var resolveCacheKey = (keyOrOpts) => {
@@ -2924,35 +2958,23 @@ var getStashedGeo = (keyOrOpts) => {
2924
2958
  return void 0;
2925
2959
  }
2926
2960
  }
2927
- if (isString(parsed) && parsed.includes(",")) {
2928
- const parts = parsed.split(",").map((s) => parseFloat(s.trim()));
2929
- const coords = normalizeCoords(parts[0], parts[1]);
2930
- if (coords) {
2931
- return {
2932
- latitude: coords.lat,
2933
- longitude: coords.lng,
2934
- sphere: resolveSphere(void 0, coords.lat)
2935
- };
2936
- }
2937
- }
2961
+ const pair = parseCoordinatePair(parsed);
2962
+ if (pair)
2963
+ return assembleGeoConfig(pair);
2938
2964
  if (isObject(parsed)) {
2939
2965
  const rawCoords = parsed.geolocation?.coords ?? parsed.coords ?? parsed;
2940
2966
  const lat = rawCoords?.latitude ?? rawCoords?.lat;
2941
2967
  const lng = rawCoords?.longitude ?? rawCoords?.lng ?? rawCoords?.lon ?? rawCoords?.long;
2942
2968
  const coords = normalizeCoords(lat, lng);
2943
2969
  if (coords) {
2944
- const result = { latitude: coords.lat, longitude: coords.lng };
2945
2970
  const elevation = parsed.elevation ?? rawCoords.elevation;
2946
- if (isNumber(elevation))
2947
- result.elevation = Math.round(elevation * 1e3) / 1e3;
2948
- result.sphere = resolveSphere(parsed.sphere, coords.lat);
2949
- if (isString(parsed.country))
2950
- result.country = parsed.country;
2951
- if (isString(parsed.city))
2952
- result.city = parsed.city;
2953
- if (isString(parsed.timezone))
2954
- result.timezone = parsed.timezone;
2955
- return result;
2971
+ return assembleGeoConfig(coords, {
2972
+ elevation,
2973
+ sphere: parsed.sphere,
2974
+ country: parsed.country,
2975
+ city: parsed.city,
2976
+ timezone: parsed.timezone
2977
+ });
2956
2978
  }
2957
2979
  }
2958
2980
  } catch {
@@ -2982,7 +3004,7 @@ var geoLookup = async (opts = {}) => {
2982
3004
  const stashed = getStashedGeo(opts);
2983
3005
  if (stashed && isNumber(stashed.latitude) && isNumber(stashed.longitude)) {
2984
3006
  const { latitude, longitude, ...rest } = stashed;
2985
- return {
3007
+ const cachedRes = {
2986
3008
  ...rest,
2987
3009
  status: "cached",
2988
3010
  lat: latitude,
@@ -2990,6 +3012,17 @@ var geoLookup = async (opts = {}) => {
2990
3012
  latitude,
2991
3013
  longitude
2992
3014
  };
3015
+ const shouldReverse = opts.reverse === true || opts.autoReverse === true;
3016
+ if (shouldReverse && (!cachedRes.city || !cachedRes.country)) {
3017
+ const reversed = await reverseGeocode(cachedRes, opts);
3018
+ if (reversed) {
3019
+ if (!cachedRes.city && isText(reversed.city))
3020
+ cachedRes.city = reversed.city;
3021
+ if (!cachedRes.country && isText(reversed.country))
3022
+ cachedRes.country = reversed.country;
3023
+ }
3024
+ }
3025
+ return cachedRes;
2993
3026
  }
2994
3027
  }
2995
3028
  let res;
@@ -3043,15 +3076,17 @@ var geoLookup = async (opts = {}) => {
3043
3076
  res.latitude = coords.lat;
3044
3077
  res.longitude = coords.lng;
3045
3078
  res.sphere = sphere;
3046
- const stashPayload = {
3047
- latitude: coords.lat,
3048
- longitude: coords.lng,
3049
- sphere,
3050
- ...isString(res.city) ? { city: res.city } : {},
3051
- ...isString(res.country) ? { country: res.country } : {},
3052
- ...isNumber(res.elevation) ? { elevation: Math.round(res.elevation * 1e3) / 1e3 } : {},
3053
- ...isString(res.timezone) ? { timezone: res.timezone } : {}
3054
- };
3079
+ const shouldReverse = opts.reverse === true || opts.autoReverse === true;
3080
+ if (shouldReverse && (!res.city || !res.country)) {
3081
+ const reversed = await reverseGeocode(res, opts);
3082
+ if (reversed) {
3083
+ if (!res.city && isText(reversed.city))
3084
+ res.city = reversed.city;
3085
+ if (!res.country && isText(reversed.country))
3086
+ res.country = reversed.country;
3087
+ }
3088
+ }
3089
+ const stashPayload = assembleGeoConfig(coords, res);
3055
3090
  try {
3056
3091
  const ttl = isNumber(opts.ttl) ? opts.ttl : DEFAULT_GEO_TTL;
3057
3092
  stashGeo(stashPayload, ttl, opts);
@@ -3060,471 +3095,266 @@ var geoLookup = async (opts = {}) => {
3060
3095
  }
3061
3096
  return res;
3062
3097
  };
3098
+ var requestModulePromise2 = null;
3099
+ var getRequestModule2 = () => {
3100
+ if (!requestModulePromise2)
3101
+ requestModulePromise2 = Promise.resolve().then(() => (init_request_library(), request_library_exports));
3102
+ return requestModulePromise2;
3103
+ };
3104
+ var reverseGeoCache = new BoundedCache(DEFAULT_SPATIAL_CACHE_SIZE, DEFAULT_GEO_TTL);
3105
+ var isValidGeoEndpoint = (urlStr) => {
3106
+ try {
3107
+ const parsed = new URL(urlStr);
3108
+ return parsed.protocol === "https:" || parsed.hostname === "localhost" || parsed.hostname === "127.0.0.1";
3109
+ } catch {
3110
+ return false;
3111
+ }
3112
+ };
3113
+ var getSpatialCacheKey = (lat, lng, sourceOrOpts) => {
3114
+ const bucket = `${lat.toFixed(2)},${lng.toFixed(2)}`;
3115
+ if (isString(sourceOrOpts) && !isEmpty(sourceOrOpts)) {
3116
+ return `${bucket}:${sourceOrOpts.trim()}`;
3117
+ }
3118
+ if (isObject(sourceOrOpts)) {
3119
+ const hasExplicitProvider = Object.hasOwn(sourceOrOpts, "provider");
3120
+ const provider = hasExplicitProvider ? sourceOrOpts.provider : activeGeoProvider;
3121
+ const providerName = provider && isString(provider.name) && !isEmpty(provider.name) ? provider.name.trim() : void 0;
3122
+ const rawEndpoint = isString(sourceOrOpts.reverseEndpoint ?? sourceOrOpts.reverseGeoEndpoint) && !isEmpty(sourceOrOpts.reverseEndpoint ?? sourceOrOpts.reverseGeoEndpoint) ? (sourceOrOpts.reverseEndpoint ?? sourceOrOpts.reverseGeoEndpoint).trim() : void 0;
3123
+ const endpoint = rawEndpoint && isValidGeoEndpoint(rawEndpoint) ? rawEndpoint : void 0;
3124
+ if (providerName && endpoint)
3125
+ return `${bucket}:${providerName}:${endpoint}`;
3126
+ if (providerName)
3127
+ return `${bucket}:${providerName}`;
3128
+ if (endpoint)
3129
+ return `${bucket}:${endpoint}`;
3130
+ } else if (activeGeoProvider && isString(activeGeoProvider.name) && !isEmpty(activeGeoProvider.name)) {
3131
+ return `${bucket}:${activeGeoProvider.name.trim()}`;
3132
+ }
3133
+ return bucket;
3134
+ };
3063
3135
  async function reverseGeocode(coords, opts) {
3064
- const provider = opts?.provider ?? activeGeoProvider;
3136
+ const coerced = coerceGeo(coords);
3137
+ if (!coerced || !isNumber(coerced.latitude) || !isNumber(coerced.longitude))
3138
+ return null;
3139
+ const lat = coerced.latitude;
3140
+ const lng = coerced.longitude;
3141
+ const key = getSpatialCacheKey(lat, lng, opts);
3142
+ const useCache = opts?.refresh !== true;
3143
+ if (useCache) {
3144
+ const cached = reverseGeoCache.get(key);
3145
+ if (cached) {
3146
+ return {
3147
+ ...cached,
3148
+ latitude: lat,
3149
+ longitude: lng,
3150
+ sphere: resolveSphere(cached.sphere, lat),
3151
+ elevation: isNumber(cached.elevation) ? cached.elevation : coerced.elevation,
3152
+ timezone: isString(cached.timezone) ? cached.timezone : coerced.timezone
3153
+ };
3154
+ }
3155
+ }
3156
+ const hasExplicitProvider = isObject(opts) && Object.hasOwn(opts, "provider");
3157
+ const provider = hasExplicitProvider ? opts.provider : activeGeoProvider;
3065
3158
  if (provider && isFunction(provider.reverseGeocode)) {
3066
- return provider.reverseGeocode(coords, opts);
3159
+ try {
3160
+ const res = await provider.reverseGeocode(coerced, opts);
3161
+ if (res && isObject(res)) {
3162
+ const result = assembleGeoConfig({ lat, lng }, {
3163
+ sphere: res.sphere,
3164
+ city: res.city,
3165
+ country: res.country,
3166
+ elevation: isNumber(res.elevation) ? res.elevation : coerced.elevation,
3167
+ timezone: isString(res.timezone) ? res.timezone : coerced.timezone
3168
+ });
3169
+ const cachePayload = assembleGeoConfig({ lat, lng }, {
3170
+ sphere: res.sphere,
3171
+ city: res.city,
3172
+ country: res.country,
3173
+ timezone: res.timezone
3174
+ });
3175
+ reverseGeoCache.set(key, cachePayload);
3176
+ return result;
3177
+ }
3178
+ if (opts?.fallback === false)
3179
+ return null;
3180
+ } catch (err) {
3181
+ if (opts?.fallback === false)
3182
+ throw err;
3183
+ }
3184
+ } else if (opts?.fallback === false && (provider || hasExplicitProvider)) {
3185
+ return null;
3067
3186
  }
3068
- const resolved = coerceGeo(coords);
3069
- return resolved ?? null;
3187
+ const rawReverseEndpoint = opts?.reverseEndpoint ?? opts?.reverseGeoEndpoint;
3188
+ if (isText(rawReverseEndpoint)) {
3189
+ const rawEndpoint = rawReverseEndpoint.trim();
3190
+ if (!isValidGeoEndpoint(rawEndpoint))
3191
+ return opts?.fallback === false ? null : coerced;
3192
+ }
3193
+ const customEndpoint = isText(rawReverseEndpoint) ? rawReverseEndpoint.trim() : void 0;
3194
+ const fallbackKey = getSpatialCacheKey(lat, lng, customEndpoint ?? "default");
3195
+ if (useCache) {
3196
+ const cachedFallback = reverseGeoCache.get(fallbackKey);
3197
+ if (cachedFallback) {
3198
+ return {
3199
+ ...cachedFallback,
3200
+ latitude: lat,
3201
+ longitude: lng,
3202
+ sphere: resolveSphere(cachedFallback.sphere, lat),
3203
+ elevation: isNumber(cachedFallback.elevation) ? cachedFallback.elevation : coerced.elevation,
3204
+ timezone: isString(cachedFallback.timezone) ? cachedFallback.timezone : coerced.timezone
3205
+ };
3206
+ }
3207
+ }
3208
+ let endpoint;
3209
+ if (customEndpoint) {
3210
+ if (/\{(?:latitude|lat|longitude|lng|lon)\}/i.test(customEndpoint)) {
3211
+ endpoint = customEndpoint.replace(/\{latitude\}/gi, encodeURIComponent(lat)).replace(/\{lat\}/gi, encodeURIComponent(lat)).replace(/\{longitude\}/gi, encodeURIComponent(lng)).replace(/\{lng\}/gi, encodeURIComponent(lng)).replace(/\{lon\}/gi, encodeURIComponent(lng));
3212
+ } else {
3213
+ const sep = customEndpoint.includes("?") ? "&" : "?";
3214
+ endpoint = `${customEndpoint}${sep}latitude=${encodeURIComponent(lat)}&longitude=${encodeURIComponent(lng)}`;
3215
+ }
3216
+ } else {
3217
+ endpoint = `${DEFAULT_REVERSE_GEO_ENDPOINT}?latitude=${lat}&longitude=${lng}&localityLanguage=en`;
3218
+ }
3219
+ try {
3220
+ const timeout = isNumber(opts?.timeout) && opts.timeout > 0 ? opts.timeout : DEFAULT_REVERSE_GEO_TIMEOUT;
3221
+ const maxBytes = isNumber(opts?.maxBytes) && opts.maxBytes > 0 ? opts.maxBytes : DEFAULT_REVERSE_GEO_MAX_BYTES;
3222
+ const { fetchRequest: fetchRequest2 } = await getRequestModule2();
3223
+ const data = await fetchRequest2(endpoint, {}, { timeout, maxBytes });
3224
+ if (isObject(data)) {
3225
+ const city = isText(data.city) ? data.city.trim() : isText(data.locality) ? data.locality.trim() : isText(data.principalSubdivision) ? data.principalSubdivision.trim() : void 0;
3226
+ const country = isText(data.countryCode) ? data.countryCode.trim() : isText(data.countryName) ? data.countryName.trim() : void 0;
3227
+ const result = assembleGeoConfig({ lat, lng }, {
3228
+ city,
3229
+ country,
3230
+ elevation: coerced.elevation,
3231
+ timezone: coerced.timezone
3232
+ });
3233
+ if (isText(city) || isText(country)) {
3234
+ const cachePayload = assembleGeoConfig({ lat, lng }, {
3235
+ city,
3236
+ country
3237
+ });
3238
+ reverseGeoCache.set(fallbackKey, cachePayload);
3239
+ }
3240
+ return result;
3241
+ }
3242
+ } catch {
3243
+ }
3244
+ return coerced;
3070
3245
  }
3071
3246
  async function forwardGeocode(query, opts) {
3072
3247
  const provider = opts?.provider ?? activeGeoProvider;
3073
- if (provider && isFunction(provider.forwardGeocode)) {
3074
- return provider.forwardGeocode(query, opts);
3075
- }
3076
- return null;
3248
+ return provider && isFunction(provider.forwardGeocode) ? provider.forwardGeocode(query, opts) : null;
3077
3249
  }
3078
3250
  var resolveGeoCoordinates = async (input, opts = {}) => {
3251
+ const effectiveOpts = isObject(input) ? { ...input, ...opts } : opts;
3079
3252
  const coerced = coerceGeo(input);
3080
- if (coerced && isNumber(coerced.latitude) && isNumber(coerced.longitude))
3253
+ if (coerced && isNumber(coerced.latitude) && isNumber(coerced.longitude)) {
3254
+ const shouldReverse = effectiveOpts.reverse === true || effectiveOpts.autoReverse === true;
3255
+ if (shouldReverse && (!coerced.city || !coerced.country)) {
3256
+ const reversed = await reverseGeocode(coerced, effectiveOpts);
3257
+ if (reversed) {
3258
+ return {
3259
+ ...reversed,
3260
+ ...coerced,
3261
+ city: isText(coerced.city) ? coerced.city : reversed.city,
3262
+ country: isText(coerced.country) ? coerced.country : reversed.country,
3263
+ lat: coerced.latitude,
3264
+ lng: coerced.longitude,
3265
+ latitude: coerced.latitude,
3266
+ longitude: coerced.longitude
3267
+ };
3268
+ }
3269
+ }
3081
3270
  return {
3082
3271
  ...coerced,
3083
3272
  lat: coerced.latitude,
3084
3273
  lng: coerced.longitude
3085
3274
  };
3086
- const stashed = opts.refresh === true ? void 0 : getStashedGeo(opts);
3087
- if (stashed && isNumber(stashed.latitude) && isNumber(stashed.longitude))
3275
+ }
3276
+ const stashed = effectiveOpts.refresh === true ? void 0 : getStashedGeo(effectiveOpts);
3277
+ if (stashed && isNumber(stashed.latitude) && isNumber(stashed.longitude)) {
3278
+ const shouldReverse = effectiveOpts.reverse === true || effectiveOpts.autoReverse === true;
3279
+ if (shouldReverse && (!stashed.city || !stashed.country)) {
3280
+ const reversed = await reverseGeocode(stashed, effectiveOpts);
3281
+ if (reversed) {
3282
+ return {
3283
+ ...reversed,
3284
+ ...stashed,
3285
+ city: isText(stashed.city) ? stashed.city : reversed.city,
3286
+ country: isText(stashed.country) ? stashed.country : reversed.country,
3287
+ lat: stashed.latitude,
3288
+ lng: stashed.longitude,
3289
+ latitude: stashed.latitude,
3290
+ longitude: stashed.longitude
3291
+ };
3292
+ }
3293
+ }
3088
3294
  return {
3089
3295
  ...stashed,
3090
3296
  lat: stashed.latitude,
3091
3297
  lng: stashed.longitude
3092
3298
  };
3093
- const lookup = await geoLookup(opts);
3299
+ }
3300
+ const lookup = await geoLookup(effectiveOpts);
3094
3301
  const coords = normalizeCoords(lookup.lat, lookup.lng);
3095
3302
  if (isNullish(lookup.error) && coords) {
3096
3303
  const sphere = resolveSphere(lookup.sphere, coords.lat);
3097
- return {
3098
- ...lookup,
3304
+ const base = {
3305
+ ...assembleGeoConfig(coords, { ...lookup, sphere }),
3099
3306
  lat: coords.lat,
3100
3307
  lng: coords.lng,
3101
3308
  latitude: coords.lat,
3102
3309
  longitude: coords.lng,
3103
3310
  sphere
3104
3311
  };
3105
- }
3106
- return null;
3107
- };
3108
- var extractRawCoords = (input) => {
3109
- if (isNullish(input))
3110
- return void 0;
3111
- if (isString(input) && input.includes(",")) {
3112
- const segments = input.split(",").map((s) => s.trim());
3113
- if (segments.length >= 2 && segments[0] !== "" && segments[1] !== "") {
3114
- const lat = Number(segments[0]);
3115
- const lng = Number(segments[1]);
3116
- if (isNumber(lat) && isNumber(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
3117
- return { lat, lng };
3118
- }
3119
- }
3120
- return void 0;
3121
- }
3122
- if (Array.isArray(input) && input.length >= 2) {
3123
- const rawLat = input[0];
3124
- const rawLng = input[1];
3125
- if (rawLat !== null && rawLng !== null && rawLat !== "" && rawLng !== "" && typeof rawLat !== "boolean" && typeof rawLng !== "boolean") {
3126
- const lat = typeof rawLat === "string" && rawLat.trim() === "" ? NaN : Number(rawLat);
3127
- const lng = typeof rawLng === "string" && rawLng.trim() === "" ? NaN : Number(rawLng);
3128
- if (isNumber(lat) && isNumber(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
3129
- return { lat, lng };
3130
- }
3131
- }
3132
- return void 0;
3133
- }
3134
- if (isReference(input)) {
3135
- const geo = input.geo ?? input.config?.geo ?? input;
3136
- const cfg = input.config?.geo ?? input.config;
3137
- const rawLat = evaluate(geo?.latitude, geo?.lat, input.latitude, input.lat, cfg?.latitude, cfg?.lat);
3138
- const rawLng = evaluate(geo?.longitude, geo?.lng, geo?.lon, geo?.long, input.longitude, input.lng, input.lon, input.long, cfg?.longitude, cfg?.lng, cfg?.lon, cfg?.long);
3139
- if (rawLat !== null && rawLng !== null && rawLat !== "" && rawLng !== "" && typeof rawLat !== "boolean" && typeof rawLng !== "boolean") {
3140
- const lat = typeof rawLat === "string" && rawLat.trim() === "" ? NaN : Number(rawLat);
3141
- const lng = typeof rawLng === "string" && rawLng.trim() === "" ? NaN : Number(rawLng);
3142
- if (isNumber(lat) && isNumber(lng) && lat >= -90 && lat <= 90 && lng >= -180 && lng <= 180) {
3143
- return { lat, lng };
3144
- }
3145
- }
3146
- }
3147
- return void 0;
3148
- };
3149
- var toRadianCoordinates = (from, to) => {
3150
- const c1 = coerceGeo(from);
3151
- const c2 = coerceGeo(to);
3152
- if (!c1 || !c2 || !isNumber(c1.latitude) || !isNumber(c1.longitude) || !isNumber(c2.latitude) || !isNumber(c2.longitude))
3153
- return void 0;
3154
- const toRad = Math.PI / 180;
3155
- const lat1 = c1.latitude * toRad;
3156
- const lng1 = c1.longitude * toRad;
3157
- const lat2 = c2.latitude * toRad;
3158
- const lng2 = c2.longitude * toRad;
3159
- return {
3160
- lat1,
3161
- lat2,
3162
- lng1,
3163
- lng2,
3164
- dLat: lat2 - lat1,
3165
- dLng: lng2 - lng1
3166
- };
3167
- };
3168
- function haversineDistance(from, to, unit = "km") {
3169
- const coords = toRadianCoordinates(from, to);
3170
- if (!coords)
3171
- return NaN;
3172
- const { lat1, lat2, dLat, dLng } = coords;
3173
- const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLng / 2) ** 2;
3174
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
3175
- const radius = unit === "miles" ? 3958.7613 : unit === "m" ? 63710088e-1 : 6371.0088;
3176
- const dist = radius * c;
3177
- return unit === "m" ? Math.round(dist) : Math.round(dist * 1e3) / 1e3;
3178
- }
3179
- var resolveCivilTimezoneOffset = (tz, epochMs) => {
3180
- try {
3181
- if (isDefined(globalThis.Temporal) && isFunction(globalThis.Temporal.Instant?.fromEpochMilliseconds)) {
3182
- const zdt = Temporal.Instant.fromEpochMilliseconds(epochMs).toZonedDateTimeISO(tz);
3183
- return zdt.offsetNanoseconds / 6e10;
3184
- }
3185
- const parts = new Intl.DateTimeFormat("en-US", {
3186
- timeZone: tz,
3187
- timeZoneName: "longOffset",
3188
- year: "numeric"
3189
- }).formatToParts(new Date(epochMs));
3190
- const tzPart = parts.find((p) => p.type === "timeZoneName")?.value;
3191
- if (tzPart) {
3192
- if (tzPart === "GMT" || tzPart === "UTC")
3193
- return 0;
3194
- const match = tzPart.match(/GMT([+-])(\d{2}):(\d{2})/);
3195
- if (match) {
3196
- const sign = match[1] === "-" ? -1 : 1;
3197
- return sign * (parseInt(match[2], 10) * 60 + parseInt(match[3], 10));
3198
- }
3199
- }
3200
- } catch {
3201
- }
3202
- return void 0;
3203
- };
3204
- function solarOffset(coords, options) {
3205
- const geo = coerceGeo(coords);
3206
- if (!geo || !isNumber(geo.latitude) || !isNumber(geo.longitude)) {
3207
- return NaN;
3208
- }
3209
- const lng = geo.longitude;
3210
- const tz = options?.timeZone ?? (isReference(coords) ? coords.timezone ?? coords.tz : void 0) ?? geo.timezone;
3211
- const dateVal = options?.date ?? (isReference(coords) ? extractEpochMs(coords) : void 0);
3212
- const epochMs = isDefined(dateVal) ? extractEpochMs(dateVal) : Date.now();
3213
- if (!isNumber(epochMs))
3214
- return NaN;
3215
- const offsetMinutes = isText(tz) ? resolveCivilTimezoneOffset(tz, epochMs) : void 0;
3216
- const refMeridian = offsetMinutes !== void 0 ? offsetMinutes / 60 * 15 : Math.round(lng / 15) * 15;
3217
- const deltaLng = lng - refMeridian;
3218
- let offsetMin = deltaLng * 4;
3219
- if (options?.apparent) {
3220
- const d = new Date(epochMs);
3221
- const startOfYear = Date.UTC(d.getUTCFullYear(), 0, 1);
3222
- const dayOfYear = Math.floor((epochMs - startOfYear) / 864e5) + 1;
3223
- const gamma = 2 * Math.PI / 365 * (dayOfYear - 1);
3224
- const eqTime = 229.18 * (75e-6 + 1868e-6 * Math.cos(gamma) - 0.032077 * Math.sin(gamma) - 0.014615 * Math.cos(2 * gamma) - 0.040849 * Math.sin(2 * gamma));
3225
- offsetMin += eqTime;
3226
- }
3227
- const unit = options?.unit ?? "mi";
3228
- let res;
3229
- if (unit === "ss" || unit === "seconds") {
3230
- res = offsetMin * 60;
3231
- } else if (unit === "hh" || unit === "hours") {
3232
- res = offsetMin / 60;
3233
- } else {
3234
- res = offsetMin;
3235
- }
3236
- const precision = options?.precision ?? 2;
3237
- const factor = Math.pow(10, precision);
3238
- return Math.round(res * factor) / factor;
3239
- }
3240
- function extractEpochMs(input) {
3241
- if (isNullish(input))
3242
- return void 0;
3243
- if (isNumber(input))
3244
- return input;
3245
- if (isDate(input))
3246
- return input.getTime();
3247
- if (isReference(input)) {
3248
- if (isNumber(input.epoch?.ms))
3249
- return input.epoch.ms;
3250
- if (isNumber(input.epochMilliseconds))
3251
- return input.epochMilliseconds;
3252
- if (isNumber(input.timestamp))
3253
- return input.timestamp;
3254
- if (isDate(input.date))
3255
- return input.date.getTime();
3256
- if (isFunction(input.toInstant)) {
3257
- try {
3258
- return input.toInstant().epochMilliseconds;
3259
- } catch {
3312
+ const shouldReverse = effectiveOpts.reverse === true || effectiveOpts.autoReverse === true;
3313
+ if (shouldReverse && (!base.city || !base.country)) {
3314
+ const reversed = await reverseGeocode(base, effectiveOpts);
3315
+ if (reversed) {
3316
+ return {
3317
+ ...reversed,
3318
+ ...base,
3319
+ city: isText(base.city) ? base.city : reversed.city,
3320
+ country: isText(base.country) ? base.country : reversed.country,
3321
+ lat: coords.lat,
3322
+ lng: coords.lng,
3323
+ latitude: coords.lat,
3324
+ longitude: coords.lng,
3325
+ sphere
3326
+ };
3260
3327
  }
3261
3328
  }
3262
- if (isFunction(input.getTime))
3263
- try {
3264
- return input.getTime();
3265
- } catch {
3266
- }
3267
- }
3268
- if (isString(input)) {
3269
- const parsed = Date.parse(input);
3270
- if (isNumber(parsed))
3271
- return parsed;
3329
+ return base;
3272
3330
  }
3273
- return void 0;
3274
- }
3275
- function calculateBearing(from, to, options) {
3276
- const coords = toRadianCoordinates(from, to);
3277
- if (!coords)
3278
- return NaN;
3279
- const { lat1, lat2, dLng } = coords;
3280
- const y = Math.sin(dLng) * Math.cos(lat2);
3281
- const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLng);
3282
- const bearing = (Math.atan2(y, x) * 180 / Math.PI + 360) % 360;
3283
- const precision = options?.precision ?? 1;
3284
- const factor = Math.pow(10, precision);
3285
- return Math.round(bearing * factor) / factor;
3286
- }
3287
- function calculateMidpoint(from, to) {
3288
- const coords = toRadianCoordinates(from, to);
3289
- if (!coords)
3290
- return void 0;
3291
- const { lat1, lat2, lng1, dLng } = coords;
3292
- const Bx = Math.cos(lat2) * Math.cos(dLng);
3293
- const By = Math.cos(lat2) * Math.sin(dLng);
3294
- const latMidRad = Math.atan2(Math.sin(lat1) + Math.sin(lat2), Math.sqrt((Math.cos(lat1) + Bx) ** 2 + By ** 2));
3295
- const lngMidRad = lng1 + Math.atan2(By, Math.cos(lat1) + Bx);
3296
- const midLat = Math.round(latMidRad * 180 / Math.PI * 1e3) / 1e3;
3297
- const midLng = Math.round(((lngMidRad * 180 / Math.PI + 540) % 360 - 180) * 1e3) / 1e3;
3298
- const sphere = midLat > 1e-3 ? "north" : midLat < -1e-3 ? "south" : "equator";
3299
- return {
3300
- latitude: midLat,
3301
- longitude: midLng,
3302
- sphere
3303
- };
3304
- }
3305
- function calculateVelocity(from, to, options) {
3306
- const opts = isString(options) ? { unit: options } : options ?? {};
3307
- const unit = opts.unit ?? "km";
3308
- const timeUnit = opts.timeUnit ?? "hh";
3309
- const dist = haversineDistance(from, to, unit);
3310
- if (isNaN(dist))
3311
- return NaN;
3312
- const t1 = extractEpochMs(from);
3313
- const t2 = extractEpochMs(to);
3314
- if (!isNumber(t1) || !isNumber(t2))
3315
- return NaN;
3316
- const deltaMs = Math.abs(t2 - t1);
3317
- if (deltaMs === 0) {
3318
- return dist === 0 ? 0 : Infinity;
3319
- }
3320
- let deltaUnits;
3321
- if (timeUnit === "ss" || timeUnit === "s" || timeUnit === "seconds" || timeUnit === "second") {
3322
- deltaUnits = deltaMs / 1e3;
3323
- } else if (timeUnit === "mi" || timeUnit === "m" || timeUnit === "minutes" || timeUnit === "minute") {
3324
- deltaUnits = deltaMs / 6e4;
3325
- } else {
3326
- deltaUnits = deltaMs / 36e5;
3327
- }
3328
- const velocity = dist / deltaUnits;
3329
- const precision = opts.precision ?? 2;
3330
- const factor = Math.pow(10, precision);
3331
- return Math.round(velocity * factor) / factor;
3332
- }
3333
- function isImpossibleTravel(from, to, options) {
3334
- const unit = options?.unit ?? "km";
3335
- const defaultMax = unit === "miles" ? 560 : unit === "m" ? 250 : 900;
3336
- const threshold = options?.maxSpeed ?? options?.maxCommercialSpeedKmH ?? defaultMax;
3337
- const velocity = calculateVelocity(from, to, { unit, timeUnit: unit === "m" ? "ss" : "hh" });
3338
- return velocity > threshold;
3339
- }
3340
- function isWithin(from, to, maxDistance, unit = "km") {
3341
- if (!isNumber(maxDistance) || maxDistance < 0)
3342
- return false;
3343
- const c1 = extractRawCoords(from);
3344
- const c2 = extractRawCoords(to);
3345
- if (!c1 || !c2 || !isNumber(c1.lat) || !isNumber(c1.lng) || !isNumber(c2.lat) || !isNumber(c2.lng))
3346
- return false;
3347
- const toRad = Math.PI / 180;
3348
- const lat1 = c1.lat * toRad;
3349
- const lng1 = c1.lng * toRad;
3350
- const lat2 = c2.lat * toRad;
3351
- const lng2 = c2.lng * toRad;
3352
- const dLat = lat2 - lat1;
3353
- const dLng = lng2 - lng1;
3354
- const a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLng / 2) * Math.sin(dLng / 2);
3355
- const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
3356
- const radius = unit === "miles" ? 3958.7613 : unit === "m" ? 63710088e-1 : 6371.0088;
3357
- const dist = radius * c;
3358
- return dist <= maxDistance;
3359
- }
3360
- function inBoundingBox(coords, bbox) {
3361
- const geo = extractRawCoords(coords);
3362
- if (!geo || !isNumber(geo.lat) || !isNumber(geo.lng))
3363
- return false;
3364
- if (isNullish(bbox))
3365
- return false;
3366
- let minLat;
3367
- let maxLat;
3368
- let minLng;
3369
- let maxLng;
3370
- if (Array.isArray(bbox) && bbox.length >= 4) {
3371
- minLat = bbox[0];
3372
- minLng = bbox[1];
3373
- maxLat = bbox[2];
3374
- maxLng = bbox[3];
3375
- } else if (isReference(bbox)) {
3376
- const b = bbox;
3377
- minLat = b.minLat ?? b.minLatitude;
3378
- maxLat = b.maxLat ?? b.maxLatitude;
3379
- minLng = b.minLng ?? b.minLongitude;
3380
- maxLng = b.maxLng ?? b.maxLongitude;
3381
- }
3382
- if (!isNumber(minLat) || !isNumber(maxLat) || !isNumber(minLng) || !isNumber(maxLng))
3383
- return false;
3384
- const lat = geo.lat;
3385
- const lng = geo.lng;
3386
- if (lat < minLat || lat > maxLat)
3387
- return false;
3388
- return minLng <= maxLng ? lng >= minLng && lng <= maxLng : lng >= minLng || lng <= maxLng;
3389
- }
3390
- var COMMON_COUNTRY_NAMES = {
3391
- australia: "AU",
3392
- "united states": "US",
3393
- "united kingdom": "GB",
3394
- "great britain": "GB",
3395
- france: "FR",
3396
- germany: "DE",
3397
- italy: "IT",
3398
- spain: "ES",
3399
- japan: "JP",
3400
- china: "CN",
3401
- canada: "CA",
3402
- brazil: "BR",
3403
- egypt: "EG",
3404
- "saudi arabia": "SA",
3405
- russia: "RU",
3406
- india: "IN",
3407
- mexico: "MX",
3408
- "new zealand": "NZ",
3409
- netherlands: "NL",
3410
- switzerland: "CH",
3411
- austria: "AT",
3412
- belgium: "BE",
3413
- sweden: "SE",
3414
- norway: "NO",
3415
- denmark: "DK",
3416
- finland: "FI",
3417
- poland: "PL",
3418
- turkey: "TR",
3419
- greece: "GR",
3420
- israel: "IL",
3421
- thailand: "TH",
3422
- vietnam: "VN",
3423
- indonesia: "ID",
3424
- malaysia: "MY",
3425
- philippines: "PH",
3426
- "south africa": "ZA",
3427
- "south korea": "KR",
3428
- korea: "KR",
3429
- ireland: "IE",
3430
- portugal: "PT",
3431
- argentina: "AR"
3432
- };
3433
- var COUNTRY_PRIMARY_LOCALES = {
3434
- AU: "en-AU",
3435
- US: "en-US",
3436
- GB: "en-GB",
3437
- CA: "en-CA",
3438
- NZ: "en-NZ",
3439
- IE: "en-IE",
3440
- SA: "ar-SA",
3441
- AE: "ar-AE",
3442
- EG: "ar-EG",
3443
- JP: "ja-JP",
3444
- CN: "zh-CN",
3445
- TW: "zh-TW",
3446
- HK: "zh-HK",
3447
- KR: "ko-KR",
3448
- FR: "fr-FR",
3449
- DE: "de-DE",
3450
- IT: "it-IT",
3451
- ES: "es-ES",
3452
- MX: "es-MX",
3453
- AR: "es-AR",
3454
- BR: "pt-BR",
3455
- PT: "pt-PT",
3456
- RU: "ru-RU",
3457
- IN: "hi-IN",
3458
- NL: "nl-NL",
3459
- SE: "sv-SE",
3460
- NO: "nb-NO",
3461
- DK: "da-DK",
3462
- FI: "fi-FI",
3463
- PL: "pl-PL",
3464
- TR: "tr-TR",
3465
- GR: "el-GR",
3466
- IL: "he-IL",
3467
- TH: "th-TH",
3468
- VN: "vi-VN",
3469
- ID: "id-ID",
3470
- MY: "ms-MY",
3471
- PH: "fil-PH",
3472
- ZA: "en-ZA",
3473
- CH: "de-CH",
3474
- AT: "de-AT",
3475
- BE: "nl-BE"
3331
+ return null;
3476
3332
  };
3477
- function resolveCulturalLocale(currentLocale, countryCode, mode = true) {
3478
- if (mode === false || mode === "none" || mode === "off")
3479
- return void 0;
3480
- const toCode = (val) => {
3481
- const trimmed = val.trim();
3482
- if (trimmed.length === 2)
3483
- return trimmed.toUpperCase();
3484
- return COMMON_COUNTRY_NAMES[trimmed.toLowerCase()];
3485
- };
3486
- let country;
3487
- if (Array.isArray(countryCode)) {
3488
- for (const c of countryCode) {
3489
- if (isString(c)) {
3490
- const mapped = toCode(c);
3491
- if (mapped) {
3492
- country = mapped;
3493
- break;
3494
- }
3495
- }
3496
- }
3497
- } else if (isString(countryCode)) {
3498
- country = toCode(countryCode);
3499
- }
3500
- if (isString(mode) && mode !== "regional" && mode !== "region" && mode !== "native" && mode !== "full") {
3501
- const loc2 = getLC(mode);
3502
- return loc2?.baseName ?? cleanLocaleTag(mode);
3503
- }
3504
- if (!country)
3505
- return void 0;
3506
- if (mode === "native" || mode === "full") {
3507
- const nativeTag = COUNTRY_PRIMARY_LOCALES[country] ?? `en-${country}`;
3508
- const loc2 = getLC(nativeTag);
3509
- return loc2?.baseName ?? nativeTag;
3510
- }
3511
- let baseLang = "en";
3512
- let script;
3513
- if (isString(currentLocale) && currentLocale.length > 0) {
3514
- const loc2 = getLC(currentLocale);
3515
- baseLang = loc2?.language ?? cleanLocaleTag(currentLocale)?.split("-")[0] ?? "en";
3516
- if (loc2?.script)
3517
- script = loc2.script;
3518
- }
3519
- const targetTag = script ? `${baseLang}-${script}-${country}` : `${baseLang}-${country}`;
3520
- const loc = getLC(targetTag);
3521
- return loc?.baseName ?? targetTag;
3522
- }
3523
3333
 
3524
3334
  // src/index.ts
3525
3335
  init_mapper_library2();
3526
3336
  init_mapper_library();
3527
- import { isString as isString2, isNumber as isNumber2, isObject as isObject2, isEmpty as isEmpty2, isSafeKey as isSafeKey2 } from "@magmacomputing/tempo/library";
3337
+ init_assertion_library();
3338
+ import {
3339
+ resolveCulturalLocale
3340
+ } from "@magmacomputing/tempo-fns";
3341
+ var NON_GEO_CONTROL_KEYS = [
3342
+ "setTimezone",
3343
+ "setLocale",
3344
+ "refresh",
3345
+ "ttl",
3346
+ "endpoint",
3347
+ "timeout",
3348
+ "maxBytes",
3349
+ "highAccuracy",
3350
+ "catch",
3351
+ "debug",
3352
+ "geo",
3353
+ "provider",
3354
+ "fallback",
3355
+ "reverse",
3356
+ "autoReverse"
3357
+ ];
3528
3358
  var GeoPlugin = definePlugin({
3529
3359
  name: "geo",
3530
3360
  install(TempoClass, options) {
@@ -3535,10 +3365,10 @@ var GeoPlugin = definePlugin({
3535
3365
  const classOpts = installedClass.config?.pluginOptions?.geo;
3536
3366
  const instanceOpts = instance?.config?.pluginOptions?.geo;
3537
3367
  return {
3538
- ...isObject2(options) ? options : {},
3539
- ...isObject2(classOpts) ? classOpts : {},
3540
- ...isObject2(instanceOpts) ? instanceOpts : {},
3541
- ...isObject2(callSiteOpts) ? callSiteOpts : {}
3368
+ ...isObject(options) ? options : {},
3369
+ ...isObject(classOpts) ? classOpts : {},
3370
+ ...isObject(instanceOpts) ? instanceOpts : {},
3371
+ ...isObject(callSiteOpts) ? callSiteOpts : {}
3542
3372
  };
3543
3373
  };
3544
3374
  if (!Object.hasOwn(installedClass, "geo")) {
@@ -3546,14 +3376,6 @@ var GeoPlugin = definePlugin({
3546
3376
  lookup: (opts) => geoLookup(getEffectiveOptions(opts)),
3547
3377
  resolve: (target, opts) => resolveGeoCoordinates(target, getEffectiveOptions(opts, target)),
3548
3378
  coerce: coerceGeo,
3549
- distance: haversineDistance,
3550
- bearing: calculateBearing,
3551
- midpoint: calculateMidpoint,
3552
- velocity: calculateVelocity,
3553
- isImpossibleTravel,
3554
- isWithin,
3555
- inBoundingBox,
3556
- solarOffset,
3557
3379
  stash: stashGeo,
3558
3380
  clear: clearStashedGeo,
3559
3381
  get: getStashedGeo,
@@ -3580,38 +3402,39 @@ var GeoPlugin = definePlugin({
3580
3402
  const setLocale = effectiveOpts?.setLocale ?? true;
3581
3403
  const coords = await resolveGeoCoordinates(this, effectiveOpts);
3582
3404
  if (coords) {
3583
- const existingGeo = isObject2(this.config.geo) ? this.config.geo : {};
3405
+ const existingGeo = isObject(this.config.geo) ? this.config.geo : {};
3584
3406
  const customKeys = {};
3585
3407
  for (const key of Object.keys(existingGeo)) {
3586
- if (isSafeKey2(key) && !GEO_PROPERTIES.includes(key))
3408
+ if (isSafeKey(key) && !GEO_PROPERTIES.includes(key))
3587
3409
  customKeys[key] = existingGeo[key];
3588
3410
  }
3589
3411
  const callSiteGeo = coerceGeo(opts) ?? {};
3590
- if (isObject2(opts)) {
3412
+ if (isObject(opts)) {
3591
3413
  for (const key of Object.keys(opts)) {
3592
- if (isSafeKey2(key) && !["setTimezone", "setLocale", "refresh", "ttl", "endpoint", "timeout", "catch", "debug", "geo", "provider", "fallback"].includes(key)) {
3414
+ if (isSafeKey(key) && !NON_GEO_CONTROL_KEYS.includes(key)) {
3593
3415
  if (!GEO_PROPERTIES.includes(key))
3594
3416
  customKeys[key] = opts[key];
3595
3417
  }
3596
3418
  }
3597
3419
  }
3598
- const preservedElevation = isNumber2(coords?.elevation) ? coords.elevation : isNumber2(existingGeo.elevation) ? existingGeo.elevation : void 0;
3420
+ const preservedElevation = isNumber(coords?.elevation) ? coords.elevation : isNumber(existingGeo.elevation) ? existingGeo.elevation : void 0;
3599
3421
  const mergedGeo = {
3600
3422
  ...customKeys,
3601
3423
  ...coords,
3602
- ...isNumber2(preservedElevation) ? { elevation: preservedElevation } : {},
3424
+ ...isNumber(preservedElevation) ? { elevation: preservedElevation } : {},
3603
3425
  ...callSiteGeo
3604
3426
  };
3605
- if (isNumber2(mergedGeo.latitude)) mergedGeo.latitude = Math.round(mergedGeo.latitude * 1e3) / 1e3;
3606
- if (isNumber2(mergedGeo.longitude)) mergedGeo.longitude = Math.round(mergedGeo.longitude * 1e3) / 1e3;
3607
- if (!mergedGeo.sphere && isNumber2(mergedGeo.latitude)) {
3608
- mergedGeo.sphere = mergedGeo.latitude > 1e-3 ? "north" : mergedGeo.latitude < -1e-3 ? "south" : "equator";
3609
- }
3427
+ const lat = mergedGeo.latitude;
3428
+ const lng = mergedGeo.longitude;
3429
+ if (isNumber(lat)) mergedGeo.latitude = Math.round(lat * 1e3) / 1e3;
3430
+ if (isNumber(lng)) mergedGeo.longitude = Math.round(lng * 1e3) / 1e3;
3431
+ if (!mergedGeo.sphere && isNumber(lat))
3432
+ mergedGeo.sphere = lat > 1e-3 ? "north" : lat < -1e-3 ? "south" : "equator";
3610
3433
  let instance = this;
3611
3434
  const targetTz = mergedGeo.timezone;
3612
- if (setTimezone && isString2(targetTz) && !isEmpty2(targetTz))
3435
+ if (setTimezone && isString(targetTz) && !isEmpty(targetTz))
3613
3436
  instance = this.set({ timeZone: targetTz });
3614
- const targetLocale = mergedGeo.country || isString2(setLocale) ? resolveCulturalLocale(this.locale ?? this.config.locale, mergedGeo.country, setLocale) : void 0;
3437
+ const targetLocale = mergedGeo.country || isString(setLocale) ? resolveCulturalLocale(this.locale ?? this.config.locale, mergedGeo.country, setLocale) : void 0;
3615
3438
  return new TempoClass(instance, {
3616
3439
  ...instance.config,
3617
3440
  ...targetLocale ? { locale: targetLocale } : {},
@@ -3624,12 +3447,6 @@ var GeoPlugin = definePlugin({
3624
3447
  TempoClass.prototype.geoLookup = async function(opts) {
3625
3448
  return resolveGeoCoordinates(this, getEffectiveOptions(opts, this));
3626
3449
  };
3627
- TempoClass.prototype.geoDistance = function(other, unit) {
3628
- return haversineDistance(this, other, unit);
3629
- };
3630
- TempoClass.prototype.geoSolarOffset = function(options2) {
3631
- return solarOffset(this, options2);
3632
- };
3633
3450
  }
3634
3451
  });
3635
3452
  var geoPlugin = GeoPlugin;
@@ -3637,9 +3454,7 @@ var index_default = GeoPlugin;
3637
3454
  export {
3638
3455
  GEO_PROPERTIES,
3639
3456
  GeoPlugin,
3640
- calculateBearing,
3641
- calculateMidpoint,
3642
- calculateVelocity,
3457
+ NON_GEO_CONTROL_KEYS,
3643
3458
  clearStashedGeo,
3644
3459
  coerceGeo,
3645
3460
  index_default as default,
@@ -3649,10 +3464,6 @@ export {
3649
3464
  geoPlugin,
3650
3465
  getGeoProvider,
3651
3466
  getStashedGeo,
3652
- haversineDistance,
3653
- inBoundingBox,
3654
- isImpossibleTravel,
3655
- isWithin,
3656
3467
  resolveCulturalLocale,
3657
3468
  resolveGeoCoordinates,
3658
3469
  reverseGeocode,
@@ -3660,6 +3471,5 @@ export {
3660
3471
  serverGeoLocation,
3661
3472
  serverMapHemisphere,
3662
3473
  setGeoProvider,
3663
- solarOffset,
3664
3474
  stashGeo
3665
3475
  };