Skip to content

Commit edb5343

Browse files
mournergithub-actions[bot]
authored andcommitted
Add setSdkInfo for SDK wrappers to self-identify
GitOrigin-RevId: 5f990bd3a106064efbdf2e73fa3dad5d5b426552
1 parent e356c9c commit edb5343

4 files changed

Lines changed: 63 additions & 2 deletions

File tree

src/index.esm.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ export {default as MercatorCoordinate} from './geo/mercator_coordinate';
164164
export {Evented} from './util/evented';
165165
export {FreeCameraOptions} from './ui/free_camera';
166166
export {setRTLTextPlugin, getRTLTextPluginStatus} from './source/rtl_text_plugin';
167+
export {setSdkInfo} from './util/mapbox';
167168
export {addTileProvider} from './source/tile_provider';
168169
export {prewarm, clearPrewarmedResources} from './util/worker_pool_factory';
169170
export {setWorkerUrl} from './util/worker_class';

src/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import MercatorCoordinate from './geo/mercator_coordinate';
1717
import {Evented} from './util/evented';
1818
import config, {setAccessToken, setBaseApiUrl, setMaxParallelImageRequests, getDracoUrl, setDracoUrl, getMeshoptUrl, setMeshoptUrl, getBuildingGenUrl, setBuildingGenUrl} from './util/config';
1919
import {setRTLTextPlugin, getRTLTextPluginStatus} from './source/rtl_text_plugin';
20+
import {setSdkInfo} from './util/mapbox';
2021
import {addTileProvider} from './source/tile_provider';
2122
import {getWorkerCount, setWorkerCount} from './util/worker_pool';
2223
import WorkerClass from './util/worker_class';
@@ -84,6 +85,7 @@ const exported = {
8485
supported,
8586
setRTLTextPlugin,
8687
getRTLTextPluginStatus,
88+
setSdkInfo,
8789
addTileProvider,
8890
Map,
8991
NavigationControl,

src/util/mapbox.ts

Lines changed: 30 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,28 @@ function isTelemetryEnabled(customAccessToken?: string | null): boolean {
321321
return true;
322322
}
323323

324+
let sdkInfo: string | undefined;
325+
326+
const SDK_INFO_RE = /^[\w.+-]+(\/[\w.+-]+)?$/;
327+
328+
const EVENT_SCHEMA_VERSION = '2.2';
329+
330+
/**
331+
* Internal API used by Mapbox wrapper SDKs (e.g. the Flutter or React Native bridges) to
332+
* self-identify in telemetry. Not part of the public API and subject to change. Pass a
333+
* `Name/version` string (e.g. `'FlutterPlugin/3.0.0'`); call once at startup before any maps
334+
* are created, as events from earlier maps won't carry it.
335+
*
336+
* @private
337+
*/
338+
export function setSdkInfo(info: string) {
339+
if (typeof info !== 'string' || info.length > 64 || !SDK_INFO_RE.test(info)) {
340+
warnOnce(`Invalid SDK info "${info}"; expected a "Name/version" string. Ignoring.`);
341+
return;
342+
}
343+
sdkInfo = info;
344+
}
345+
324346
type TelemetryEventType = 'appUserTurnstile' | 'map.load' | 'map.auth' | 'gljs.performance' | 'style.load' | 'metrics';
325347

326348
export class TelemetryEvent {
@@ -550,14 +572,17 @@ export class MapLoadEvent extends TelemetryEvent {
550572
this.refreshUUID();
551573
}
552574

553-
const additionalPayload = {
575+
const additionalPayload: Record<string, unknown> = {
576+
version: EVENT_SCHEMA_VERSION,
554577
sdkIdentifier: 'mapbox-gl-js',
555578
sdkVersion,
556579
skuId: SKU_ID,
557580
skuToken: this.skuToken,
558581
userId: this.anonId
559582
};
560583

584+
if (sdkInfo) additionalPayload.sdkInfo = sdkInfo;
585+
561586
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
562587
this.postEvent(timestamp, additionalPayload, (err) => {
563588
if (err) {
@@ -847,14 +872,17 @@ export class TurnstileEvent extends TelemetryEvent {
847872
return;
848873
}
849874

850-
const additionalPayload = {
875+
const additionalPayload: Record<string, unknown> = {
876+
version: EVENT_SCHEMA_VERSION,
851877
sdkIdentifier: 'mapbox-gl-js',
852878
sdkVersion,
853879
skuId: SKU_ID,
854880
"enabled.telemetry": false,
855881
userId: this.anonId
856882
};
857883

884+
if (sdkInfo) additionalPayload.sdkInfo = sdkInfo;
885+
858886
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
859887
this.postEvent(nextUpdate, additionalPayload, (err) => {
860888
if (!err) {

test/unit/util/mapbox.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -778,6 +778,8 @@ describe("mapbox", () => {
778778
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
779779
expect(mapLoadEvent["enabled.telemetry"]).toEqual(false);
780780
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
781+
expect(mapLoadEvent.version).toEqual('2.2');
782+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
781783
expect(!!mapLoadEvent.userId).toBeTruthy();
782784
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
783785
expect(!!mapLoadEvent.created).toBeTruthy();
@@ -1206,6 +1208,34 @@ describe("mapbox", () => {
12061208
expect(!!mapLoadEvent.userId).toBeTruthy();
12071209
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
12081210
expect(!!mapLoadEvent.created).toBeTruthy();
1211+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1212+
expect(mapLoadEvent.version).toEqual('2.2');
1213+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1214+
expect(mapLoadEvent.sdkInfo).toBeUndefined();
1215+
});
1216+
1217+
test('setSdkInfo ignores invalid values', async () => {
1218+
mapbox.setSdkInfo('not a valid value!');
1219+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1220+
event.postMapLoadEvent(1, skuToken);
1221+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
1222+
const reqBody = await window.server.requests[0].requestBody;
1223+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1224+
const mapLoadEvent = JSON.parse(reqBody.slice(1, reqBody.length - 1));
1225+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1226+
expect(mapLoadEvent.sdkInfo).toBeUndefined();
1227+
});
1228+
1229+
test('includes sdkInfo when set via setSdkInfo', async () => {
1230+
mapbox.setSdkInfo('FlutterPlugin/3.0.0-beta.1');
1231+
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1232+
event.postMapLoadEvent(1, skuToken);
1233+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
1234+
const reqBody = await window.server.requests[0].requestBody;
1235+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-argument, @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-member-access
1236+
const mapLoadEvent = JSON.parse(reqBody.slice(1, reqBody.length - 1));
1237+
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
1238+
expect(mapLoadEvent.sdkInfo).toEqual('FlutterPlugin/3.0.0-beta.1');
12091239
});
12101240

12111241
test('does not POST when mapboxgl.ACCESS_TOKEN is not set', () => {

0 commit comments

Comments
 (0)