@magmacomputing/tempo-plugin-geo 1.2.0 → 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/CHANGELOG.md +24 -0
- package/README.md +10 -0
- package/dist/index.d.ts +25 -4
- package/dist/index.global.min.js +1 -1
- package/dist/index.js +466 -60
- package/dist/install.global.min.js +1 -1
- package/dist/install.js +466 -60
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -2774,8 +2774,8 @@ __export(sdk_exports, {
|
|
|
2774
2774
|
__reExport(sdk_exports, sdk_star);
|
|
2775
2775
|
import * as sdk_star from "@magmacomputing/tempo/plugin/sdk";
|
|
2776
2776
|
import { definePlugin as originalPlugin, defineTerm as originalTerm } from "@magmacomputing/tempo/plugin/sdk";
|
|
2777
|
-
var definePlugin = (config) => originalPlugin({ ...config, version: "1.
|
|
2778
|
-
var defineTerm = (config) => originalTerm({ ...config, version: "1.
|
|
2777
|
+
var definePlugin = (config) => originalPlugin({ ...config, version: "1.3.0" });
|
|
2778
|
+
var defineTerm = (config) => originalTerm({ ...config, version: "1.3.0" });
|
|
2779
2779
|
|
|
2780
2780
|
// ../../library/dist/common/runtime/mapper.library.js
|
|
2781
2781
|
init_utility_library();
|
|
@@ -2794,6 +2794,7 @@ function evaluate(...values) {
|
|
|
2794
2794
|
}
|
|
2795
2795
|
|
|
2796
2796
|
// ../../library/dist/common/runtime/mapper.library.js
|
|
2797
|
+
init_international_library();
|
|
2797
2798
|
var MAP_KEY2 = "_magma_geo_";
|
|
2798
2799
|
var DEFAULT_GEO_TTL = 24 * 60 * 60 * 1e3;
|
|
2799
2800
|
var GEO_PROPERTIES = [
|
|
@@ -2895,16 +2896,25 @@ var resolveCacheKey = (keyOrOpts) => {
|
|
|
2895
2896
|
return trimmed.startsWith(MAP_KEY2) ? trimmed : `${MAP_KEY2}:${trimmed}`;
|
|
2896
2897
|
}
|
|
2897
2898
|
if (keyOrOpts && isObject(keyOrOpts)) {
|
|
2899
|
+
const provider = keyOrOpts.provider ?? activeGeoProvider;
|
|
2900
|
+
const providerPrefix = provider && isString(provider.name) && !isEmpty(provider.name) ? `provider:${provider.name}` : void 0;
|
|
2898
2901
|
const k = keyOrOpts.key ?? keyOrOpts.ip ?? keyOrOpts.query;
|
|
2899
|
-
if (isString(k) && !isEmpty(k))
|
|
2900
|
-
|
|
2902
|
+
if (isString(k) && !isEmpty(k)) {
|
|
2903
|
+
const trimmedKey = k.trim();
|
|
2904
|
+
return providerPrefix ? `${MAP_KEY2}:${providerPrefix}:${trimmedKey}` : `${MAP_KEY2}:${trimmedKey}`;
|
|
2905
|
+
}
|
|
2906
|
+
if (providerPrefix) {
|
|
2907
|
+
return `${MAP_KEY2}:${providerPrefix}`;
|
|
2908
|
+
}
|
|
2909
|
+
} else if (activeGeoProvider && isString(activeGeoProvider.name) && !isEmpty(activeGeoProvider.name)) {
|
|
2910
|
+
return `${MAP_KEY2}:provider:${activeGeoProvider.name}`;
|
|
2901
2911
|
}
|
|
2902
2912
|
return MAP_KEY2;
|
|
2903
2913
|
};
|
|
2904
2914
|
var getStashedGeo = (keyOrOpts) => {
|
|
2905
2915
|
const cacheKey = resolveCacheKey(keyOrOpts);
|
|
2906
2916
|
try {
|
|
2907
|
-
const raw = getStorage(cacheKey) ?? (
|
|
2917
|
+
const raw = getStorage(cacheKey) ?? (isCallable(globalThis.localStorage?.getItem) ? globalThis.localStorage.getItem(cacheKey) : void 0);
|
|
2908
2918
|
if (!raw)
|
|
2909
2919
|
return void 0;
|
|
2910
2920
|
const parsed = isString(raw) && (raw.startsWith("{") || raw.startsWith("[")) ? JSON.parse(raw) : raw;
|
|
@@ -2958,7 +2968,15 @@ var clearStashedGeo = (keyOrOpts) => {
|
|
|
2958
2968
|
const cacheKey = resolveCacheKey(keyOrOpts);
|
|
2959
2969
|
setStorage(cacheKey, void 0);
|
|
2960
2970
|
};
|
|
2971
|
+
var activeGeoProvider;
|
|
2972
|
+
function setGeoProvider(provider) {
|
|
2973
|
+
activeGeoProvider = provider;
|
|
2974
|
+
}
|
|
2975
|
+
function getGeoProvider() {
|
|
2976
|
+
return activeGeoProvider;
|
|
2977
|
+
}
|
|
2961
2978
|
var geoLookup = async (opts = {}) => {
|
|
2979
|
+
const provider = opts.provider ?? activeGeoProvider;
|
|
2962
2980
|
const useCache = opts.refresh !== true;
|
|
2963
2981
|
if (useCache) {
|
|
2964
2982
|
const stashed = getStashedGeo(opts);
|
|
@@ -2974,26 +2992,45 @@ var geoLookup = async (opts = {}) => {
|
|
|
2974
2992
|
};
|
|
2975
2993
|
}
|
|
2976
2994
|
}
|
|
2977
|
-
const { type } = getContext();
|
|
2978
2995
|
let res;
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
const
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2996
|
+
if (provider && isFunction(provider.lookup)) {
|
|
2997
|
+
try {
|
|
2998
|
+
const providerRes = await provider.lookup(opts);
|
|
2999
|
+
if (providerRes) {
|
|
3000
|
+
res = providerRes;
|
|
3001
|
+
if (providerRes.error && opts.fallback === false)
|
|
3002
|
+
return providerRes;
|
|
3003
|
+
} else if (opts.fallback === false) {
|
|
3004
|
+
return { error: "Provider returned null and fallback is disabled" };
|
|
3005
|
+
}
|
|
3006
|
+
} catch (err) {
|
|
3007
|
+
if (opts.fallback === false)
|
|
3008
|
+
return { error: err?.message ?? "Provider lookup failed" };
|
|
2989
3009
|
}
|
|
2990
|
-
|
|
2991
|
-
|
|
2992
|
-
|
|
2993
|
-
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
3010
|
+
}
|
|
3011
|
+
if (!res || res.error) {
|
|
3012
|
+
if (opts.fallback === false && (provider || res?.error))
|
|
3013
|
+
return res && res.error ? res : { error: "Geolocation resolution failed and fallback is disabled" };
|
|
3014
|
+
const { type } = getContext();
|
|
3015
|
+
switch (type) {
|
|
3016
|
+
case CONTEXT.Browser: {
|
|
3017
|
+
const { geoLocation: geoLocation2 } = await Promise.resolve().then(() => (init_mapper_library(), mapper_library_exports));
|
|
3018
|
+
const browserRes = await geoLocation2(opts);
|
|
3019
|
+
if (browserRes.error)
|
|
3020
|
+
return { error: browserRes.error };
|
|
3021
|
+
const lat = browserRes.coords?.latitude;
|
|
3022
|
+
const lng = browserRes.coords?.longitude;
|
|
3023
|
+
res = { ...browserRes, lat, lng, latitude: lat, longitude: lng };
|
|
3024
|
+
break;
|
|
3025
|
+
}
|
|
3026
|
+
case CONTEXT.WebWorker:
|
|
3027
|
+
case CONTEXT.NodeJS:
|
|
3028
|
+
case CONTEXT.Deno:
|
|
3029
|
+
default: {
|
|
3030
|
+
const { serverGeoLocation: serverGeoLocation2 } = await Promise.resolve().then(() => (init_mapper_library2(), mapper_library_exports2));
|
|
3031
|
+
res = await serverGeoLocation2(opts);
|
|
3032
|
+
break;
|
|
3033
|
+
}
|
|
2997
3034
|
}
|
|
2998
3035
|
}
|
|
2999
3036
|
const rawLat = res.latitude ?? res.lat;
|
|
@@ -3023,6 +3060,21 @@ var geoLookup = async (opts = {}) => {
|
|
|
3023
3060
|
}
|
|
3024
3061
|
return res;
|
|
3025
3062
|
};
|
|
3063
|
+
async function reverseGeocode(coords, opts) {
|
|
3064
|
+
const provider = opts?.provider ?? activeGeoProvider;
|
|
3065
|
+
if (provider && isFunction(provider.reverseGeocode)) {
|
|
3066
|
+
return provider.reverseGeocode(coords, opts);
|
|
3067
|
+
}
|
|
3068
|
+
const resolved = coerceGeo(coords);
|
|
3069
|
+
return resolved ?? null;
|
|
3070
|
+
}
|
|
3071
|
+
async function forwardGeocode(query, opts) {
|
|
3072
|
+
const provider = opts?.provider ?? activeGeoProvider;
|
|
3073
|
+
if (provider && isFunction(provider.forwardGeocode)) {
|
|
3074
|
+
return provider.forwardGeocode(query, opts);
|
|
3075
|
+
}
|
|
3076
|
+
return null;
|
|
3077
|
+
}
|
|
3026
3078
|
var resolveGeoCoordinates = async (input, opts = {}) => {
|
|
3027
3079
|
const coerced = coerceGeo(input);
|
|
3028
3080
|
if (coerced && isNumber(coerced.latitude) && isNumber(coerced.longitude))
|
|
@@ -3053,35 +3105,80 @@ var resolveGeoCoordinates = async (input, opts = {}) => {
|
|
|
3053
3105
|
}
|
|
3054
3106
|
return null;
|
|
3055
3107
|
};
|
|
3056
|
-
|
|
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) => {
|
|
3057
3150
|
const c1 = coerceGeo(from);
|
|
3058
3151
|
const c2 = coerceGeo(to);
|
|
3059
|
-
if (!c1 || !c2 || !isNumber(c1.latitude) || !isNumber(c1.longitude) || !isNumber(c2.latitude) || !isNumber(c2.longitude))
|
|
3060
|
-
return
|
|
3061
|
-
}
|
|
3152
|
+
if (!c1 || !c2 || !isNumber(c1.latitude) || !isNumber(c1.longitude) || !isNumber(c2.latitude) || !isNumber(c2.longitude))
|
|
3153
|
+
return void 0;
|
|
3062
3154
|
const toRad = Math.PI / 180;
|
|
3063
3155
|
const lat1 = c1.latitude * toRad;
|
|
3064
3156
|
const lng1 = c1.longitude * toRad;
|
|
3065
3157
|
const lat2 = c2.latitude * toRad;
|
|
3066
3158
|
const lng2 = c2.longitude * toRad;
|
|
3067
|
-
|
|
3068
|
-
|
|
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;
|
|
3069
3173
|
const a = Math.sin(dLat / 2) ** 2 + Math.cos(lat1) * Math.cos(lat2) * Math.sin(dLng / 2) ** 2;
|
|
3070
3174
|
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
3071
|
-
|
|
3072
|
-
if (unit === "miles") {
|
|
3073
|
-
radius = 3958.7613;
|
|
3074
|
-
} else if (unit === "m") {
|
|
3075
|
-
radius = 63710088e-1;
|
|
3076
|
-
} else {
|
|
3077
|
-
radius = 6371.0088;
|
|
3078
|
-
}
|
|
3175
|
+
const radius = unit === "miles" ? 3958.7613 : unit === "m" ? 63710088e-1 : 6371.0088;
|
|
3079
3176
|
const dist = radius * c;
|
|
3080
3177
|
return unit === "m" ? Math.round(dist) : Math.round(dist * 1e3) / 1e3;
|
|
3081
3178
|
}
|
|
3082
3179
|
var resolveCivilTimezoneOffset = (tz, epochMs) => {
|
|
3083
3180
|
try {
|
|
3084
|
-
if (
|
|
3181
|
+
if (isDefined(globalThis.Temporal) && isFunction(globalThis.Temporal.Instant?.fromEpochMilliseconds)) {
|
|
3085
3182
|
const zdt = Temporal.Instant.fromEpochMilliseconds(epochMs).toZonedDateTimeISO(tz);
|
|
3086
3183
|
return zdt.offsetNanoseconds / 6e10;
|
|
3087
3184
|
}
|
|
@@ -3106,14 +3203,14 @@ var resolveCivilTimezoneOffset = (tz, epochMs) => {
|
|
|
3106
3203
|
};
|
|
3107
3204
|
function solarOffset(coords, options) {
|
|
3108
3205
|
const geo = coerceGeo(coords);
|
|
3109
|
-
if (!geo || !isNumber(geo.latitude) || !isNumber(geo.longitude)
|
|
3206
|
+
if (!geo || !isNumber(geo.latitude) || !isNumber(geo.longitude)) {
|
|
3110
3207
|
return NaN;
|
|
3111
3208
|
}
|
|
3112
3209
|
const lng = geo.longitude;
|
|
3113
3210
|
const tz = options?.timeZone ?? (isReference(coords) ? coords.timezone ?? coords.tz : void 0) ?? geo.timezone;
|
|
3114
|
-
const dateVal = options?.date ?? (isReference(coords)
|
|
3115
|
-
const epochMs =
|
|
3116
|
-
if (!
|
|
3211
|
+
const dateVal = options?.date ?? (isReference(coords) ? extractEpochMs(coords) : void 0);
|
|
3212
|
+
const epochMs = isDefined(dateVal) ? extractEpochMs(dateVal) : Date.now();
|
|
3213
|
+
if (!isNumber(epochMs))
|
|
3117
3214
|
return NaN;
|
|
3118
3215
|
const offsetMinutes = isText(tz) ? resolveCivilTimezoneOffset(tz, epochMs) : void 0;
|
|
3119
3216
|
const refMeridian = offsetMinutes !== void 0 ? offsetMinutes / 60 * 15 : Math.round(lng / 15) * 15;
|
|
@@ -3127,11 +3224,11 @@ function solarOffset(coords, options) {
|
|
|
3127
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));
|
|
3128
3225
|
offsetMin += eqTime;
|
|
3129
3226
|
}
|
|
3130
|
-
const unit = options?.unit ?? "
|
|
3227
|
+
const unit = options?.unit ?? "mi";
|
|
3131
3228
|
let res;
|
|
3132
|
-
if (unit === "seconds") {
|
|
3229
|
+
if (unit === "ss" || unit === "seconds") {
|
|
3133
3230
|
res = offsetMin * 60;
|
|
3134
|
-
} else if (unit === "hours") {
|
|
3231
|
+
} else if (unit === "hh" || unit === "hours") {
|
|
3135
3232
|
res = offsetMin / 60;
|
|
3136
3233
|
} else {
|
|
3137
3234
|
res = offsetMin;
|
|
@@ -3140,23 +3237,308 @@ function solarOffset(coords, options) {
|
|
|
3140
3237
|
const factor = Math.pow(10, precision);
|
|
3141
3238
|
return Math.round(res * factor) / factor;
|
|
3142
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 {
|
|
3260
|
+
}
|
|
3261
|
+
}
|
|
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;
|
|
3272
|
+
}
|
|
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"
|
|
3476
|
+
};
|
|
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
|
+
}
|
|
3143
3523
|
|
|
3144
3524
|
// src/index.ts
|
|
3145
3525
|
init_mapper_library2();
|
|
3146
3526
|
init_mapper_library();
|
|
3147
|
-
|
|
3527
|
+
import { isString as isString2, isNumber as isNumber2, isObject as isObject2, isEmpty as isEmpty2, isSafeKey as isSafeKey2 } from "@magmacomputing/tempo/library";
|
|
3148
3528
|
var GeoPlugin = definePlugin({
|
|
3149
3529
|
name: "geo",
|
|
3150
3530
|
install(TempoClass, options) {
|
|
3151
3531
|
const installedClass = TempoClass || this;
|
|
3532
|
+
if (options?.provider)
|
|
3533
|
+
setGeoProvider(options.provider);
|
|
3152
3534
|
const getEffectiveOptions = (callSiteOpts, instance) => {
|
|
3153
3535
|
const classOpts = installedClass.config?.pluginOptions?.geo;
|
|
3154
3536
|
const instanceOpts = instance?.config?.pluginOptions?.geo;
|
|
3155
3537
|
return {
|
|
3156
|
-
...
|
|
3157
|
-
...
|
|
3158
|
-
...
|
|
3159
|
-
...
|
|
3538
|
+
...isObject2(options) ? options : {},
|
|
3539
|
+
...isObject2(classOpts) ? classOpts : {},
|
|
3540
|
+
...isObject2(instanceOpts) ? instanceOpts : {},
|
|
3541
|
+
...isObject2(callSiteOpts) ? callSiteOpts : {}
|
|
3160
3542
|
};
|
|
3161
3543
|
};
|
|
3162
3544
|
if (!Object.hasOwn(installedClass, "geo")) {
|
|
@@ -3165,10 +3547,20 @@ var GeoPlugin = definePlugin({
|
|
|
3165
3547
|
resolve: (target, opts) => resolveGeoCoordinates(target, getEffectiveOptions(opts, target)),
|
|
3166
3548
|
coerce: coerceGeo,
|
|
3167
3549
|
distance: haversineDistance,
|
|
3550
|
+
bearing: calculateBearing,
|
|
3551
|
+
midpoint: calculateMidpoint,
|
|
3552
|
+
velocity: calculateVelocity,
|
|
3553
|
+
isImpossibleTravel,
|
|
3554
|
+
isWithin,
|
|
3555
|
+
inBoundingBox,
|
|
3168
3556
|
solarOffset,
|
|
3169
3557
|
stash: stashGeo,
|
|
3170
3558
|
clear: clearStashedGeo,
|
|
3171
3559
|
get: getStashedGeo,
|
|
3560
|
+
setProvider: setGeoProvider,
|
|
3561
|
+
getProvider: getGeoProvider,
|
|
3562
|
+
reverse: (coords, opts) => reverseGeocode(coords, getEffectiveOptions(opts)),
|
|
3563
|
+
forward: (query, opts) => forwardGeocode(query, getEffectiveOptions(opts)),
|
|
3172
3564
|
server: serverGeoLocation,
|
|
3173
3565
|
browser: geoLocation,
|
|
3174
3566
|
get current() {
|
|
@@ -3185,41 +3577,44 @@ var GeoPlugin = definePlugin({
|
|
|
3185
3577
|
TempoClass.prototype.geoLocate = async function(opts) {
|
|
3186
3578
|
const effectiveOpts = getEffectiveOptions(opts, this);
|
|
3187
3579
|
const setTimezone = effectiveOpts?.setTimezone !== false;
|
|
3580
|
+
const setLocale = effectiveOpts?.setLocale ?? true;
|
|
3188
3581
|
const coords = await resolveGeoCoordinates(this, effectiveOpts);
|
|
3189
3582
|
if (coords) {
|
|
3190
|
-
const existingGeo =
|
|
3583
|
+
const existingGeo = isObject2(this.config.geo) ? this.config.geo : {};
|
|
3191
3584
|
const customKeys = {};
|
|
3192
3585
|
for (const key of Object.keys(existingGeo)) {
|
|
3193
|
-
if (
|
|
3586
|
+
if (isSafeKey2(key) && !GEO_PROPERTIES.includes(key))
|
|
3194
3587
|
customKeys[key] = existingGeo[key];
|
|
3195
3588
|
}
|
|
3196
3589
|
const callSiteGeo = coerceGeo(opts) ?? {};
|
|
3197
|
-
if (
|
|
3590
|
+
if (isObject2(opts)) {
|
|
3198
3591
|
for (const key of Object.keys(opts)) {
|
|
3199
|
-
if (
|
|
3592
|
+
if (isSafeKey2(key) && !["setTimezone", "setLocale", "refresh", "ttl", "endpoint", "timeout", "catch", "debug", "geo", "provider", "fallback"].includes(key)) {
|
|
3200
3593
|
if (!GEO_PROPERTIES.includes(key))
|
|
3201
3594
|
customKeys[key] = opts[key];
|
|
3202
3595
|
}
|
|
3203
3596
|
}
|
|
3204
3597
|
}
|
|
3205
|
-
const preservedElevation =
|
|
3598
|
+
const preservedElevation = isNumber2(coords?.elevation) ? coords.elevation : isNumber2(existingGeo.elevation) ? existingGeo.elevation : void 0;
|
|
3206
3599
|
const mergedGeo = {
|
|
3207
3600
|
...customKeys,
|
|
3208
3601
|
...coords,
|
|
3209
|
-
...
|
|
3602
|
+
...isNumber2(preservedElevation) ? { elevation: preservedElevation } : {},
|
|
3210
3603
|
...callSiteGeo
|
|
3211
3604
|
};
|
|
3212
|
-
if (
|
|
3213
|
-
if (
|
|
3214
|
-
if (!mergedGeo.sphere &&
|
|
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)) {
|
|
3215
3608
|
mergedGeo.sphere = mergedGeo.latitude > 1e-3 ? "north" : mergedGeo.latitude < -1e-3 ? "south" : "equator";
|
|
3216
3609
|
}
|
|
3217
3610
|
let instance = this;
|
|
3218
3611
|
const targetTz = mergedGeo.timezone;
|
|
3219
|
-
if (setTimezone &&
|
|
3612
|
+
if (setTimezone && isString2(targetTz) && !isEmpty2(targetTz))
|
|
3220
3613
|
instance = this.set({ timeZone: targetTz });
|
|
3614
|
+
const targetLocale = mergedGeo.country || isString2(setLocale) ? resolveCulturalLocale(this.locale ?? this.config.locale, mergedGeo.country, setLocale) : void 0;
|
|
3221
3615
|
return new TempoClass(instance, {
|
|
3222
3616
|
...instance.config,
|
|
3617
|
+
...targetLocale ? { locale: targetLocale } : {},
|
|
3223
3618
|
geo: (0, sdk_exports.deepFreeze)(mergedGeo),
|
|
3224
3619
|
...mergedGeo.sphere ? { sphere: mergedGeo.sphere } : {}
|
|
3225
3620
|
});
|
|
@@ -3242,18 +3637,29 @@ var index_default = GeoPlugin;
|
|
|
3242
3637
|
export {
|
|
3243
3638
|
GEO_PROPERTIES,
|
|
3244
3639
|
GeoPlugin,
|
|
3640
|
+
calculateBearing,
|
|
3641
|
+
calculateMidpoint,
|
|
3642
|
+
calculateVelocity,
|
|
3245
3643
|
clearStashedGeo,
|
|
3246
3644
|
coerceGeo,
|
|
3247
3645
|
index_default as default,
|
|
3646
|
+
forwardGeocode,
|
|
3248
3647
|
geoLocation,
|
|
3249
3648
|
geoLookup,
|
|
3250
3649
|
geoPlugin,
|
|
3650
|
+
getGeoProvider,
|
|
3251
3651
|
getStashedGeo,
|
|
3252
3652
|
haversineDistance,
|
|
3653
|
+
inBoundingBox,
|
|
3654
|
+
isImpossibleTravel,
|
|
3655
|
+
isWithin,
|
|
3656
|
+
resolveCulturalLocale,
|
|
3253
3657
|
resolveGeoCoordinates,
|
|
3658
|
+
reverseGeocode,
|
|
3254
3659
|
serverGeoCoords,
|
|
3255
3660
|
serverGeoLocation,
|
|
3256
3661
|
serverMapHemisphere,
|
|
3662
|
+
setGeoProvider,
|
|
3257
3663
|
solarOffset,
|
|
3258
3664
|
stashGeo
|
|
3259
3665
|
};
|