Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add startTrackingVerified(), getVerifiedLocationToken(), and onTokenUpdated() #178

Merged
merged 12 commits into from
Aug 14, 2024
Merged
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ Radar.initialize('prj_test_pk_...', { /* options */ });

Add the following script in your `html` file
```html
<script src="https://js.radar.com/v4.3.5-beta.0/radar.min.js"></script>
<script src="https://js.radar.com/v4.3.5/radar.min.js"></script>
```

Then initialize the Radar SDK
Expand All @@ -73,8 +73,8 @@ To create a map, first initialize the Radar SDK with your publishable key. Then
```html
<html>
<head>
<link href="https://js.radar.com/v4.3.5-beta.0/radar.css" rel="stylesheet">
<script src="https://js.radar.com/v4.3.5-beta.0/radar.min.js"></script>
<link href="https://js.radar.com/v4.3.5/radar.css" rel="stylesheet">
<script src="https://js.radar.com/v4.3.5/radar.min.js"></script>
</head>

<body>
Expand All @@ -98,8 +98,8 @@ To create an autocomplete input, first initialize the Radar SDK with your publis
```html
<html>
<head>
<link href="https://js.radar.com/v4.3.5-beta.0/radar.css" rel="stylesheet">
<script src="https://js.radar.com/v4.3.5-beta.0/radar.min.js"></script>
<link href="https://js.radar.com/v4.3.5/radar.css" rel="stylesheet">
<script src="https://js.radar.com/v4.3.5/radar.min.js"></script>
</head>

<body>
Expand Down Expand Up @@ -130,8 +130,8 @@ To power [geofencing](https://radar.com/documentation/geofencing/overview) exper
```html
<html>
<head>
<link href="https://js.radar.com/v4.3.5-beta.0/radar.css" rel="stylesheet">
<script src="https://js.radar.com/v4.3.5-beta.0/radar.min.js"></script>
<link href="https://js.radar.com/v4.3.5/radar.css" rel="stylesheet">
<script src="https://js.radar.com/v4.3.5/radar.min.js"></script>
</head>

<body>
Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "radar-sdk-js",
"version": "4.3.5-beta.0",
"version": "4.3.5",
"description": "Web Javascript SDK for Radar, location infrastructure for mobile and web apps.",
"homepage": "https://radar.com",
"type": "module",
Expand Down
8 changes: 3 additions & 5 deletions src/api/track.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,14 +162,10 @@ class TrackAPI {
};
}

let { user, events, token, expiresAt } = response;
let { user, events, token, expiresAt, expiresIn, passed, failureReasons, _id } = response;
const location = { latitude, longitude, accuracy };
let passed;
let expiresIn;
if (expiresAt) {
expiresAt = new Date(expiresAt);
passed = user?.fraud?.passed && user?.country?.passed && user?.state?.passed;
expiresIn = (expiresAt.getTime() - Date.now()) / 1000;
}

const trackRes = {
Expand All @@ -180,6 +176,8 @@ class TrackAPI {
expiresAt,
expiresIn,
passed,
failureReasons,
_id,
} as RadarTrackVerifiedResponse;

if (options.debug) {
Expand Down
89 changes: 83 additions & 6 deletions src/api/verify.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import Logger from '../logger';
import Session from '../session';
import Storage from '../storage';

import type { RadarTrackParams, RadarTrackVerifiedResponse } from '../types';
import type { RadarStartTrackingVerifiedParams, RadarTrackParams, RadarTrackVerifiedResponse } from '../types';

let tokenTimeoutId: any | null = null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we namespace these as verified instead of token?

Copy link
Collaborator

@kochis kochis Aug 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, it's probably preferable to mark things as optional instead of null

let tokenTimeoutId?: any;
let tokenCallback?: (token: RadarTrackVerifiedResponse) => void;

Otherwise it needs to be explicitly set to null

let tokenCallback: ((token: RadarTrackVerifiedResponse) => void) | null = null;
let lastToken: RadarTrackVerifiedResponse | null = null;
let lastTokenNow: number = 0;
let expectedCountryCode: string | null = null;
let expectedStateCode: string | null = null;
Comment on lines +12 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably fine to define the scoped variables like this, but there are a couple issues:

  1. These wont persist across a page reload
  2. Can run into issues if there are multiple callers (though I think for track we expect a singleton pattern)

If we need to track the last call time across the page-load, probably need to put it in localstorage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't need this to work across page load like userId, so should be good. I could move it inside the class if that's important

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these aren't sensitive it's probably fine. Maybe the user-provided ones should be static variables (callback and expected codes)


class VerifyAPI {
static async trackVerified(params: RadarTrackParams, encrypted: Boolean = false) {
Expand Down Expand Up @@ -41,6 +48,8 @@ class VerifyAPI {
stopped: true,
userId,
encrypted,
expectedCountryCode,
expectedStateCode,
};

let userAgent = navigator.userAgent;
Expand All @@ -53,7 +62,7 @@ class VerifyAPI {
host: apple ? 'https://radar-verify.com:52516' : 'http://localhost:52516',
});

let { user, events, token, expiresAt } = response;
let { user, events, token, expiresAt, expiresIn, passed, failureReasons, _id } = response;
let location;
if (user && user.location && user.location.coordinates && user.locationAccuracy) {
location = {
Expand All @@ -62,12 +71,8 @@ class VerifyAPI {
accuracy: user.locationAccuracy,
};
}
let passed;
let expiresIn;
if (expiresAt) {
expiresAt = new Date(expiresAt);
passed = user?.fraud?.passed && user?.country?.passed && user?.state?.passed;
expiresIn = (expiresAt.getTime() - Date.now()) / 1000;
}

const trackRes = {
Expand All @@ -78,14 +83,86 @@ class VerifyAPI {
expiresAt,
expiresIn,
passed,
failureReasons,
_id,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What _id is this?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

location._id

} as RadarTrackVerifiedResponse;

if (options.debug) {
trackRes.response = response;
}

lastToken = trackRes;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

token is the entire response?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. Deserialized to RadarVerifiedLocationToken in mobile SDKs

lastTokenNow = performance.now();
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should use Date.now() unless there's a need for nano-second measurement (this is really only intended for perf measurement)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem with Date.now() is that you can manipulate it by changing your system clock time, whereas performance.now() is based off of time since page load and harder to tamper with

Copy link
Contributor Author

@nickpatrick nickpatrick Aug 12, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do something similar on the mobile SDKs (SystemClock.elapsedRealTimeNanos on Android) for the same reason


if (tokenCallback) {
tokenCallback(trackRes);
}

return trackRes;
}

static async startTrackingVerified(params: RadarStartTrackingVerifiedParams) {
const doTrackVerified = async () => {
const trackRes = await this.trackVerified({});

const { interval } = params;

let expiresIn = 0;
let minInterval = interval;

if (trackRes) {
expiresIn = (trackRes.expiresIn || expiresIn);

// if expiresIn is shorter than interval, override interval
minInterval = Math.min(expiresIn, interval);
}

// re-request early to maximize the likelihood that a cached token is available
if (minInterval > 20) {
minInterval = minInterval - 10;
}

// min interval is 10 seconds
if (minInterval < 10) {
minInterval = 10;
Comment on lines +120 to +127
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so if I give the interval param as 21 then it is effectively 11 but if I give 15 it is effectively 15?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah. I think that's an edge case, but if it bothers us, I can update

}

if (tokenTimeoutId) {
clearTimeout(tokenTimeoutId);
}

tokenTimeoutId = setTimeout(doTrackVerified, minInterval * 1000);
};

doTrackVerified();
}

static stopTrackingVerified() {
if (tokenTimeoutId) {
clearTimeout(tokenTimeoutId);
}
}

static async getVerifiedLocationToken() {
const lastTokenElapsed = (performance.now() - lastTokenNow) / 1000;

if (lastToken) {
if (lastTokenElapsed < (lastToken.expiresIn || 0)) {
return lastToken;
}
}

return this.trackVerified({});
}

static setExpectedJurisdiction(countryCode?: string, stateCode?: string) {
expectedCountryCode = countryCode || null;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If these are marked as optional in the definition, we wont need the || null here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was getting errors because expectedCountryCode is defined as | null instead of | undefined. https://app.circleci.com/pipelines/github/radarlabs/radar-sdk-js/1241/workflows/a23a44d8-bbed-4f3d-a059-163a7b4407c0/jobs/1016

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was getting errors because expectedCountryCode is defined as | null instead of | undefined. https://app.circleci.com/pipelines/github/radarlabs/radar-sdk-js/1241/workflows/a23a44d8-bbed-4f3d-a059-163a7b4407c0/jobs/1016

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I think you can just define them as:

let expectedCountryCode?: string;

expectedStateCode = stateCode || null;
}

static onTokenUpdated(callback: (token: RadarTrackVerifiedResponse) => void) {
tokenCallback = callback;
}
}

export default VerifyAPI;
32 changes: 28 additions & 4 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import type {
RadarReverseGeocodeParams,
RadarSearchGeofencesParams,
RadarSearchPlacesParams,
RadarStartTrackingVerifiedParams,
RadarTrackParams,
RadarTrackVerifiedResponse,
RadarTripOptions,
RadarValidateAddressParams,
} from './types';
Expand Down Expand Up @@ -105,7 +107,7 @@ class Radar {
}

///////////////////////
// geofencing platform
// Geofencing Platform
///////////////////////

public static setUserId(userId?: string) {
Expand Down Expand Up @@ -148,6 +150,22 @@ class Radar {
return VerifyAPI.trackVerified(params);
}

public static startTrackingVerified(params: RadarStartTrackingVerifiedParams) {
return VerifyAPI.startTrackingVerified(params);
}

public static stopTrackingVerified() {
return VerifyAPI.stopTrackingVerified();
}

public static getVerifiedLocationToken() {
return VerifyAPI.getVerifiedLocationToken();
}

public static setExpectedJurisdiction(countryCode?: string, stateCode?: string) {
VerifyAPI.setExpectedJurisdiction(countryCode, stateCode);
}

public static getContext(params: Location) {
return ContextAPI.getContext(params);
}
Expand Down Expand Up @@ -184,10 +202,16 @@ class Radar {
return ConversionsAPI.logConversion(params);
}

///////////////////////
// listeners
///////////////////////
public static onTokenUpdated(callback: (token: RadarTrackVerifiedResponse) => void) {
VerifyAPI.onTokenUpdated(callback);
}

/////////////////
// maps platform
/////////////////
///////////////////////
// Maps Platform
///////////////////////

public static forwardGeocode(params: RadarForwardGeocodeParams) {
return GeocodingAPI.forwardGeocode(params);
Expand Down
8 changes: 7 additions & 1 deletion src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@ export interface RadarTrackParams {
fraud?: boolean;
}

export interface RadarStartTrackingVerifiedParams {
interval: number;
}

export enum RadarEventConfidence {
none = 0,
low = 1,
Expand Down Expand Up @@ -218,9 +222,11 @@ export interface RadarTrackVerifiedResponse extends RadarTrackResponse {
expiresAt?: Date;
expiresIn?: number;
passed?: boolean;
failureReasons?: string[];
_id?: string;
}

export interface RadarContextResponse extends RadarResponse {
export interface RadarContextResponse extends RadarResponse {
location?: Location;
geofences?: RadarGeofence[];
place?: RadarPlace;
Expand Down
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export default '4.3.5-beta.0';
export default '4.3.5';
Loading