@clix-so/react-native-sdk 0.0.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/LICENSE +27 -0
- package/README.md +345 -0
- package/lib/module/core/Clix.js +217 -0
- package/lib/module/core/Clix.js.map +1 -0
- package/lib/module/core/ClixConfig.js +4 -0
- package/lib/module/core/ClixConfig.js.map +1 -0
- package/lib/module/core/ClixInitCoordinator.js +58 -0
- package/lib/module/core/ClixInitCoordinator.js.map +1 -0
- package/lib/module/core/ClixVersion.js +17 -0
- package/lib/module/core/ClixVersion.js.map +1 -0
- package/lib/module/index.js +7 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/models/ClixDevice.js +51 -0
- package/lib/module/models/ClixDevice.js.map +1 -0
- package/lib/module/models/ClixPushNotificationPayload.js +21 -0
- package/lib/module/models/ClixPushNotificationPayload.js.map +1 -0
- package/lib/module/models/ClixUserProperty.js +44 -0
- package/lib/module/models/ClixUserProperty.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/services/ClixAPIClient.js +172 -0
- package/lib/module/services/ClixAPIClient.js.map +1 -0
- package/lib/module/services/DeviceAPIService.js +112 -0
- package/lib/module/services/DeviceAPIService.js.map +1 -0
- package/lib/module/services/DeviceService.js +157 -0
- package/lib/module/services/DeviceService.js.map +1 -0
- package/lib/module/services/EventAPIService.js +36 -0
- package/lib/module/services/EventAPIService.js.map +1 -0
- package/lib/module/services/EventService.js +29 -0
- package/lib/module/services/EventService.js.map +1 -0
- package/lib/module/services/NotificationService.js +549 -0
- package/lib/module/services/NotificationService.js.map +1 -0
- package/lib/module/services/StorageService.js +76 -0
- package/lib/module/services/StorageService.js.map +1 -0
- package/lib/module/services/TokenService.js +71 -0
- package/lib/module/services/TokenService.js.map +1 -0
- package/lib/module/utils/ClixError.js +63 -0
- package/lib/module/utils/ClixError.js.map +1 -0
- package/lib/module/utils/UUID.js +28 -0
- package/lib/module/utils/UUID.js.map +1 -0
- package/lib/module/utils/logging/ClixLogger.js +55 -0
- package/lib/module/utils/logging/ClixLogger.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/core/Clix.d.ts +67 -0
- package/lib/typescript/src/core/Clix.d.ts.map +1 -0
- package/lib/typescript/src/core/ClixConfig.d.ts +9 -0
- package/lib/typescript/src/core/ClixConfig.d.ts.map +1 -0
- package/lib/typescript/src/core/ClixInitCoordinator.d.ts +16 -0
- package/lib/typescript/src/core/ClixInitCoordinator.d.ts.map +1 -0
- package/lib/typescript/src/core/ClixVersion.d.ts +6 -0
- package/lib/typescript/src/core/ClixVersion.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +5 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/models/ClixDevice.d.ts +42 -0
- package/lib/typescript/src/models/ClixDevice.d.ts.map +1 -0
- package/lib/typescript/src/models/ClixPushNotificationPayload.d.ts +23 -0
- package/lib/typescript/src/models/ClixPushNotificationPayload.d.ts.map +1 -0
- package/lib/typescript/src/models/ClixUserProperty.d.ts +19 -0
- package/lib/typescript/src/models/ClixUserProperty.d.ts.map +1 -0
- package/lib/typescript/src/services/ClixAPIClient.d.ts +35 -0
- package/lib/typescript/src/services/ClixAPIClient.d.ts.map +1 -0
- package/lib/typescript/src/services/DeviceAPIService.d.ts +13 -0
- package/lib/typescript/src/services/DeviceAPIService.d.ts.map +1 -0
- package/lib/typescript/src/services/DeviceService.d.ts +20 -0
- package/lib/typescript/src/services/DeviceService.d.ts.map +1 -0
- package/lib/typescript/src/services/EventAPIService.d.ts +7 -0
- package/lib/typescript/src/services/EventAPIService.d.ts.map +1 -0
- package/lib/typescript/src/services/EventService.d.ts +9 -0
- package/lib/typescript/src/services/EventService.d.ts.map +1 -0
- package/lib/typescript/src/services/NotificationService.d.ts +56 -0
- package/lib/typescript/src/services/NotificationService.d.ts.map +1 -0
- package/lib/typescript/src/services/StorageService.d.ts +10 -0
- package/lib/typescript/src/services/StorageService.d.ts.map +1 -0
- package/lib/typescript/src/services/TokenService.d.ts +15 -0
- package/lib/typescript/src/services/TokenService.d.ts.map +1 -0
- package/lib/typescript/src/utils/ClixError.d.ts +41 -0
- package/lib/typescript/src/utils/ClixError.d.ts.map +1 -0
- package/lib/typescript/src/utils/UUID.d.ts +14 -0
- package/lib/typescript/src/utils/UUID.d.ts.map +1 -0
- package/lib/typescript/src/utils/logging/ClixLogger.d.ts +18 -0
- package/lib/typescript/src/utils/logging/ClixLogger.d.ts.map +1 -0
- package/package.json +151 -0
- package/src/core/Clix.ts +256 -0
- package/src/core/ClixConfig.ts +9 -0
- package/src/core/ClixInitCoordinator.ts +65 -0
- package/src/core/ClixVersion.ts +17 -0
- package/src/index.ts +5 -0
- package/src/models/ClixDevice.ts +88 -0
- package/src/models/ClixPushNotificationPayload.ts +38 -0
- package/src/models/ClixUserProperty.ts +58 -0
- package/src/services/ClixAPIClient.ts +248 -0
- package/src/services/DeviceAPIService.ts +187 -0
- package/src/services/DeviceService.ts +204 -0
- package/src/services/EventAPIService.ts +48 -0
- package/src/services/EventService.ts +45 -0
- package/src/services/NotificationService.ts +730 -0
- package/src/services/StorageService.ts +84 -0
- package/src/services/TokenService.ts +84 -0
- package/src/utils/ClixError.ts +78 -0
- package/src/utils/UUID.ts +29 -0
- package/src/utils/logging/ClixLogger.ts +61 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { ClixLogger } from '../utils/logging/ClixLogger';
|
|
2
|
+
|
|
3
|
+
export class ClixInitCoordinator {
|
|
4
|
+
private promise: Promise<void>;
|
|
5
|
+
private resolve: (() => void) | null = null;
|
|
6
|
+
private reject: ((error: Error) => void) | null = null;
|
|
7
|
+
private isCompleted = false;
|
|
8
|
+
private isFailed = false;
|
|
9
|
+
|
|
10
|
+
constructor() {
|
|
11
|
+
this.promise = new Promise<void>((resolve, reject) => {
|
|
12
|
+
this.resolve = resolve;
|
|
13
|
+
this.reject = reject;
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async waitForInitialization(): Promise<void> {
|
|
18
|
+
if (this.isCompleted) {
|
|
19
|
+
return Promise.resolve();
|
|
20
|
+
}
|
|
21
|
+
return this.promise;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
isInitializationFailed(): boolean {
|
|
25
|
+
return this.isFailed;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
isInitializationCompleted(): boolean {
|
|
29
|
+
return this.isCompleted;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
completeInitialization(): void {
|
|
33
|
+
if (this.isAlreadyFinalized()) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
this.isCompleted = true;
|
|
37
|
+
this.resolve?.();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
failInitialization(error: Error): void {
|
|
41
|
+
if (this.isAlreadyFinalized()) {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
this.isFailed = true;
|
|
45
|
+
ClixLogger.warn('Clix initialization failed:', error);
|
|
46
|
+
this.reject?.(error);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
reset(): void {
|
|
50
|
+
this.isCompleted = false;
|
|
51
|
+
this.isFailed = false;
|
|
52
|
+
this.promise = new Promise<void>((resolve, reject) => {
|
|
53
|
+
this.resolve = resolve;
|
|
54
|
+
this.reject = reject;
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private isAlreadyFinalized(): boolean {
|
|
59
|
+
if (this.isCompleted || this.isFailed) {
|
|
60
|
+
ClixLogger.warn('Initialization already completed or failed');
|
|
61
|
+
return true;
|
|
62
|
+
}
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export class ClixVersion {
|
|
2
|
+
private static cachedVersion?: string;
|
|
3
|
+
private static fallBackVersion: string = '0.0.0';
|
|
4
|
+
|
|
5
|
+
static async getVersion(): Promise<string> {
|
|
6
|
+
if (this.cachedVersion) {
|
|
7
|
+
return this.cachedVersion;
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
this.cachedVersion =
|
|
11
|
+
require('../../../package.json').version || this.fallBackVersion;
|
|
12
|
+
return this.cachedVersion!;
|
|
13
|
+
} catch (error) {
|
|
14
|
+
return '0.0.0';
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export class ClixDevice {
|
|
2
|
+
public readonly id: string;
|
|
3
|
+
public readonly platform: string;
|
|
4
|
+
public readonly model: string;
|
|
5
|
+
public readonly manufacturer: string;
|
|
6
|
+
public readonly osName: string;
|
|
7
|
+
public readonly osVersion: string;
|
|
8
|
+
public readonly localeRegion: string;
|
|
9
|
+
public readonly localeLanguage: string;
|
|
10
|
+
public readonly timezone: string;
|
|
11
|
+
public readonly appName: string;
|
|
12
|
+
public readonly appVersion: string;
|
|
13
|
+
public readonly sdkType: string;
|
|
14
|
+
public readonly sdkVersion: string;
|
|
15
|
+
public readonly adId?: string;
|
|
16
|
+
public readonly isPushPermissionGranted: boolean;
|
|
17
|
+
public readonly pushToken?: string;
|
|
18
|
+
public readonly pushTokenType?: string;
|
|
19
|
+
|
|
20
|
+
constructor(device: {
|
|
21
|
+
id: string;
|
|
22
|
+
platform: string;
|
|
23
|
+
model: string;
|
|
24
|
+
manufacturer: string;
|
|
25
|
+
osName: string;
|
|
26
|
+
osVersion: string;
|
|
27
|
+
localeRegion: string;
|
|
28
|
+
localeLanguage: string;
|
|
29
|
+
timezone: string;
|
|
30
|
+
appName: string;
|
|
31
|
+
appVersion: string;
|
|
32
|
+
sdkType: string;
|
|
33
|
+
sdkVersion: string;
|
|
34
|
+
adId?: string;
|
|
35
|
+
isPushPermissionGranted: boolean;
|
|
36
|
+
pushToken?: string;
|
|
37
|
+
pushTokenType?: string;
|
|
38
|
+
}) {
|
|
39
|
+
this.id = device.id;
|
|
40
|
+
this.platform = device.platform;
|
|
41
|
+
this.model = device.model;
|
|
42
|
+
this.manufacturer = device.manufacturer;
|
|
43
|
+
this.osName = device.osName;
|
|
44
|
+
this.osVersion = device.osVersion;
|
|
45
|
+
this.localeRegion = device.localeRegion;
|
|
46
|
+
this.localeLanguage = device.localeLanguage;
|
|
47
|
+
this.timezone = device.timezone;
|
|
48
|
+
this.appName = device.appName;
|
|
49
|
+
this.appVersion = device.appVersion;
|
|
50
|
+
this.sdkType = device.sdkType;
|
|
51
|
+
this.sdkVersion = device.sdkVersion;
|
|
52
|
+
this.adId = device.adId;
|
|
53
|
+
this.isPushPermissionGranted = device.isPushPermissionGranted;
|
|
54
|
+
this.pushToken = device.pushToken;
|
|
55
|
+
this.pushTokenType = device.pushTokenType;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
copyWith(updates: Partial<ClixDevice>): ClixDevice {
|
|
59
|
+
return new ClixDevice({
|
|
60
|
+
id: updates.id ?? this.id,
|
|
61
|
+
platform: updates.platform ?? this.platform,
|
|
62
|
+
model: updates.model ?? this.model,
|
|
63
|
+
manufacturer: updates.manufacturer ?? this.manufacturer,
|
|
64
|
+
osName: updates.osName ?? this.osName,
|
|
65
|
+
osVersion: updates.osVersion ?? this.osVersion,
|
|
66
|
+
localeRegion: updates.localeRegion ?? this.localeRegion,
|
|
67
|
+
localeLanguage: updates.localeLanguage ?? this.localeLanguage,
|
|
68
|
+
timezone: updates.timezone ?? this.timezone,
|
|
69
|
+
appName: updates.appName ?? this.appName,
|
|
70
|
+
appVersion: updates.appVersion ?? this.appVersion,
|
|
71
|
+
sdkType: updates.sdkType ?? this.sdkType,
|
|
72
|
+
sdkVersion: updates.sdkVersion ?? this.sdkVersion,
|
|
73
|
+
adId: updates.adId ?? this.adId,
|
|
74
|
+
isPushPermissionGranted:
|
|
75
|
+
updates.isPushPermissionGranted ?? this.isPushPermissionGranted,
|
|
76
|
+
pushToken: updates.pushToken ?? this.pushToken,
|
|
77
|
+
pushTokenType: updates.pushTokenType ?? this.pushTokenType,
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
equals(other: ClixDevice): boolean {
|
|
82
|
+
return this.id === other.id;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
toString(): string {
|
|
86
|
+
return `ClixDevice(id: ${this.id}, platform: ${this.platform}, model: ${this.model})`;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export class ClixPushNotificationPayload {
|
|
2
|
+
public readonly messageId: string;
|
|
3
|
+
public readonly campaignId?: string;
|
|
4
|
+
public readonly userId?: string;
|
|
5
|
+
public readonly deviceId?: string;
|
|
6
|
+
public readonly trackingId?: string;
|
|
7
|
+
public readonly landingUrl?: string;
|
|
8
|
+
public readonly imageUrl?: string;
|
|
9
|
+
public readonly customProperties?: Record<string, any>;
|
|
10
|
+
|
|
11
|
+
constructor(payload: {
|
|
12
|
+
messageId: string;
|
|
13
|
+
campaignId?: string;
|
|
14
|
+
userId?: string;
|
|
15
|
+
deviceId?: string;
|
|
16
|
+
trackingId?: string;
|
|
17
|
+
landingUrl?: string;
|
|
18
|
+
imageUrl?: string;
|
|
19
|
+
customProperties?: Record<string, any>;
|
|
20
|
+
}) {
|
|
21
|
+
this.messageId = payload.messageId;
|
|
22
|
+
this.campaignId = payload.campaignId;
|
|
23
|
+
this.userId = payload.userId;
|
|
24
|
+
this.deviceId = payload.deviceId;
|
|
25
|
+
this.trackingId = payload.trackingId;
|
|
26
|
+
this.landingUrl = payload.landingUrl;
|
|
27
|
+
this.imageUrl = payload.imageUrl;
|
|
28
|
+
this.customProperties = payload.customProperties;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
equals(other: ClixPushNotificationPayload): boolean {
|
|
32
|
+
return this.messageId === other.messageId;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
toString(): string {
|
|
36
|
+
return `ClixPushNotificationPayload(messageId: ${this.messageId}, campaignId: ${this.campaignId})`;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export enum PropertyType {
|
|
2
|
+
String = 'USER_PROPERTY_TYPE_STRING',
|
|
3
|
+
Number = 'USER_PROPERTY_TYPE_NUMBER',
|
|
4
|
+
Boolean = 'USER_PROPERTY_TYPE_BOOLEAN',
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
export class ClixUserProperty {
|
|
8
|
+
public readonly name: string;
|
|
9
|
+
public readonly valueString: any;
|
|
10
|
+
public readonly type: PropertyType;
|
|
11
|
+
|
|
12
|
+
constructor(property: {
|
|
13
|
+
name: string;
|
|
14
|
+
valueString: any;
|
|
15
|
+
type: PropertyType;
|
|
16
|
+
}) {
|
|
17
|
+
this.name = property.name;
|
|
18
|
+
this.valueString = property.valueString;
|
|
19
|
+
this.type = property.type;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
static of(name: string, value: any): ClixUserProperty {
|
|
23
|
+
let type: PropertyType;
|
|
24
|
+
let codableValue: any;
|
|
25
|
+
|
|
26
|
+
if (typeof value === 'boolean') {
|
|
27
|
+
type = PropertyType.Boolean;
|
|
28
|
+
codableValue = value;
|
|
29
|
+
} else if (typeof value === 'number') {
|
|
30
|
+
type = PropertyType.Number;
|
|
31
|
+
codableValue = value;
|
|
32
|
+
} else if (typeof value === 'string') {
|
|
33
|
+
type = PropertyType.String;
|
|
34
|
+
codableValue = value;
|
|
35
|
+
} else {
|
|
36
|
+
type = PropertyType.String;
|
|
37
|
+
codableValue = value.toString();
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return new ClixUserProperty({
|
|
41
|
+
name,
|
|
42
|
+
valueString: codableValue,
|
|
43
|
+
type,
|
|
44
|
+
});
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
equals(other: ClixUserProperty): boolean {
|
|
48
|
+
return (
|
|
49
|
+
this.name === other.name &&
|
|
50
|
+
this.valueString === other.valueString &&
|
|
51
|
+
this.type === other.type
|
|
52
|
+
);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
toString(): string {
|
|
56
|
+
return `ClixUserProperty(name: ${this.name}, value: ${this.valueString}, type: ${this.type})`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import type { ClixConfig } from '../core/ClixConfig';
|
|
2
|
+
import { ClixVersion } from '../core/ClixVersion';
|
|
3
|
+
import { ClixLogger } from '../utils/logging/ClixLogger';
|
|
4
|
+
|
|
5
|
+
export interface APIResponse {
|
|
6
|
+
status: number;
|
|
7
|
+
data: any;
|
|
8
|
+
headers: Record<string, string>;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export class ClixAPIClient {
|
|
12
|
+
private static readonly API_BASE_PATH = '/api/v1';
|
|
13
|
+
|
|
14
|
+
constructor(private readonly config: ClixConfig) {}
|
|
15
|
+
|
|
16
|
+
private async getCommonHeaders(): Promise<Record<string, string>> {
|
|
17
|
+
const version = await ClixVersion.getVersion();
|
|
18
|
+
const headers: Record<string, string> = {
|
|
19
|
+
'Content-Type': 'application/json',
|
|
20
|
+
'X-Clix-Project-ID': this.config.projectId,
|
|
21
|
+
'X-Clix-API-Key': this.config.apiKey,
|
|
22
|
+
'User-Agent': `clix-react-native-sdk/${version}`,
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
if (this.config.extraHeaders) {
|
|
26
|
+
Object.assign(headers, this.config.extraHeaders);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return headers;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
private buildUrl(path: string): string {
|
|
33
|
+
const endpoint = this.config.endpoint || 'https://api.clix.so';
|
|
34
|
+
const baseUrl = endpoint.endsWith('/') ? endpoint.slice(0, -1) : endpoint;
|
|
35
|
+
|
|
36
|
+
const fullPath = path.startsWith('/') ? path : `/${path}`;
|
|
37
|
+
return `${baseUrl}${ClixAPIClient.API_BASE_PATH}${fullPath}`;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private buildUrlWithQuery(
|
|
41
|
+
path: string,
|
|
42
|
+
queryParameters?: Record<string, any>
|
|
43
|
+
): string {
|
|
44
|
+
const url = this.buildUrl(path);
|
|
45
|
+
|
|
46
|
+
if (queryParameters && Object.keys(queryParameters).length > 0) {
|
|
47
|
+
const searchParams = new URLSearchParams();
|
|
48
|
+
Object.entries(queryParameters).forEach(([key, value]) => {
|
|
49
|
+
if (value !== null && value !== undefined) {
|
|
50
|
+
searchParams.append(key, String(value));
|
|
51
|
+
}
|
|
52
|
+
});
|
|
53
|
+
return `${url}?${searchParams.toString()}`;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
return url;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async get(
|
|
60
|
+
path: string,
|
|
61
|
+
options?: {
|
|
62
|
+
headers?: Record<string, string>;
|
|
63
|
+
queryParameters?: Record<string, any>;
|
|
64
|
+
}
|
|
65
|
+
): Promise<APIResponse> {
|
|
66
|
+
const url = this.buildUrlWithQuery(path, options?.queryParameters);
|
|
67
|
+
const commonHeaders = await this.getCommonHeaders();
|
|
68
|
+
const requestHeaders = {
|
|
69
|
+
...commonHeaders,
|
|
70
|
+
...options?.headers,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
ClixLogger.debug(`API GET ${path}`);
|
|
74
|
+
ClixLogger.debug(`Making request to: ${url}`);
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const response = await fetch(url, {
|
|
78
|
+
method: 'GET',
|
|
79
|
+
headers: requestHeaders,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const data = await this.parseResponse(response);
|
|
83
|
+
|
|
84
|
+
ClixLogger.debug(`Response Status: ${response.status}`);
|
|
85
|
+
ClixLogger.debug(`Response Body: ${JSON.stringify(data)}`);
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
status: response.status,
|
|
89
|
+
data,
|
|
90
|
+
headers: this.headersToRecord(response.headers),
|
|
91
|
+
};
|
|
92
|
+
} catch (error) {
|
|
93
|
+
ClixLogger.error(`GET ${path} failed`, error);
|
|
94
|
+
throw error;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
async post(
|
|
99
|
+
path: string,
|
|
100
|
+
options?: {
|
|
101
|
+
headers?: Record<string, string>;
|
|
102
|
+
queryParameters?: Record<string, any>;
|
|
103
|
+
body?: any;
|
|
104
|
+
}
|
|
105
|
+
): Promise<APIResponse> {
|
|
106
|
+
const url = this.buildUrlWithQuery(path, options?.queryParameters);
|
|
107
|
+
const commonHeaders = await this.getCommonHeaders();
|
|
108
|
+
const requestHeaders = {
|
|
109
|
+
...commonHeaders,
|
|
110
|
+
...options?.headers,
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
ClixLogger.debug(`API POST ${path}`);
|
|
114
|
+
if (options?.body) {
|
|
115
|
+
ClixLogger.debug(`Request Body: ${JSON.stringify(options.body)}`);
|
|
116
|
+
}
|
|
117
|
+
if (
|
|
118
|
+
options?.queryParameters &&
|
|
119
|
+
Object.keys(options.queryParameters).length > 0
|
|
120
|
+
) {
|
|
121
|
+
ClixLogger.debug(
|
|
122
|
+
`Query Parameters: ${JSON.stringify(options.queryParameters)}`
|
|
123
|
+
);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
const body = options?.body ? JSON.stringify(options.body) : undefined;
|
|
127
|
+
|
|
128
|
+
try {
|
|
129
|
+
const response = await fetch(url, {
|
|
130
|
+
method: 'POST',
|
|
131
|
+
headers: requestHeaders,
|
|
132
|
+
body,
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
const data = await this.parseResponse(response);
|
|
136
|
+
|
|
137
|
+
ClixLogger.debug(`Response Status: ${response.status}`);
|
|
138
|
+
ClixLogger.debug(`Response Body: ${JSON.stringify(data)}`);
|
|
139
|
+
|
|
140
|
+
return {
|
|
141
|
+
status: response.status,
|
|
142
|
+
data,
|
|
143
|
+
headers: this.headersToRecord(response.headers),
|
|
144
|
+
};
|
|
145
|
+
} catch (error) {
|
|
146
|
+
ClixLogger.error(`POST ${path} failed`, error);
|
|
147
|
+
throw error;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async put(
|
|
152
|
+
path: string,
|
|
153
|
+
options?: {
|
|
154
|
+
headers?: Record<string, string>;
|
|
155
|
+
queryParameters?: Record<string, any>;
|
|
156
|
+
body?: any;
|
|
157
|
+
}
|
|
158
|
+
): Promise<APIResponse> {
|
|
159
|
+
const url = this.buildUrlWithQuery(path, options?.queryParameters);
|
|
160
|
+
const commonHeaders = await this.getCommonHeaders();
|
|
161
|
+
const requestHeaders = {
|
|
162
|
+
...commonHeaders,
|
|
163
|
+
...options?.headers,
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
ClixLogger.debug(`API PUT ${path}`);
|
|
167
|
+
|
|
168
|
+
const body = options?.body ? JSON.stringify(options.body) : undefined;
|
|
169
|
+
|
|
170
|
+
try {
|
|
171
|
+
const response = await fetch(url, {
|
|
172
|
+
method: 'PUT',
|
|
173
|
+
headers: requestHeaders,
|
|
174
|
+
body,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
const data = await this.parseResponse(response);
|
|
178
|
+
|
|
179
|
+
ClixLogger.debug(`Response Status: ${response.status}`);
|
|
180
|
+
ClixLogger.debug(`Response Body: ${JSON.stringify(data)}`);
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
status: response.status,
|
|
184
|
+
data,
|
|
185
|
+
headers: this.headersToRecord(response.headers),
|
|
186
|
+
};
|
|
187
|
+
} catch (error) {
|
|
188
|
+
ClixLogger.error(`PUT ${path} failed`, error);
|
|
189
|
+
throw error;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async delete(
|
|
194
|
+
path: string,
|
|
195
|
+
options?: {
|
|
196
|
+
headers?: Record<string, string>;
|
|
197
|
+
queryParameters?: Record<string, any>;
|
|
198
|
+
}
|
|
199
|
+
): Promise<APIResponse> {
|
|
200
|
+
const url = this.buildUrlWithQuery(path, options?.queryParameters);
|
|
201
|
+
const commonHeaders = await this.getCommonHeaders();
|
|
202
|
+
const requestHeaders = {
|
|
203
|
+
...commonHeaders,
|
|
204
|
+
...options?.headers,
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
ClixLogger.debug(`API DELETE ${path}`);
|
|
208
|
+
|
|
209
|
+
try {
|
|
210
|
+
const response = await fetch(url, {
|
|
211
|
+
method: 'DELETE',
|
|
212
|
+
headers: requestHeaders,
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
const data = await this.parseResponse(response);
|
|
216
|
+
|
|
217
|
+
ClixLogger.debug(`Response Status: ${response.status}`);
|
|
218
|
+
ClixLogger.debug(`Response Body: ${JSON.stringify(data)}`);
|
|
219
|
+
|
|
220
|
+
return {
|
|
221
|
+
status: response.status,
|
|
222
|
+
data,
|
|
223
|
+
headers: this.headersToRecord(response.headers),
|
|
224
|
+
};
|
|
225
|
+
} catch (error) {
|
|
226
|
+
ClixLogger.error(`DELETE ${path} failed`, error);
|
|
227
|
+
throw error;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private async parseResponse(response: Response): Promise<any> {
|
|
232
|
+
const contentType = response.headers.get('content-type');
|
|
233
|
+
|
|
234
|
+
if (contentType && contentType.includes('application/json')) {
|
|
235
|
+
return await response.json();
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return await response.text();
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
private headersToRecord(headers: Headers): Record<string, string> {
|
|
242
|
+
const record: Record<string, string> = {};
|
|
243
|
+
headers.forEach((value: any, key: string) => {
|
|
244
|
+
record[key] = value;
|
|
245
|
+
});
|
|
246
|
+
return record;
|
|
247
|
+
}
|
|
248
|
+
}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { ClixDevice } from '../models/ClixDevice';
|
|
2
|
+
import { ClixUserProperty } from '../models/ClixUserProperty';
|
|
3
|
+
import { ClixLogger } from '../utils/logging/ClixLogger';
|
|
4
|
+
import { ClixAPIClient } from './ClixAPIClient';
|
|
5
|
+
|
|
6
|
+
export class DeviceAPIService {
|
|
7
|
+
constructor(private readonly apiClient: ClixAPIClient) {}
|
|
8
|
+
|
|
9
|
+
async registerDevice(device: ClixDevice): Promise<void> {
|
|
10
|
+
try {
|
|
11
|
+
ClixLogger.debug(`Upserting device: ${device.id}`);
|
|
12
|
+
|
|
13
|
+
const response = await this.apiClient.post('/devices', {
|
|
14
|
+
body: {
|
|
15
|
+
devices: [
|
|
16
|
+
{
|
|
17
|
+
id: device.id,
|
|
18
|
+
platform: device.platform,
|
|
19
|
+
model: device.model,
|
|
20
|
+
manufacturer: device.manufacturer,
|
|
21
|
+
os_name: device.osName,
|
|
22
|
+
os_version: device.osVersion,
|
|
23
|
+
locale_region: device.localeRegion,
|
|
24
|
+
locale_language: device.localeLanguage,
|
|
25
|
+
timezone: device.timezone,
|
|
26
|
+
app_name: device.appName,
|
|
27
|
+
app_version: device.appVersion,
|
|
28
|
+
sdk_type: device.sdkType,
|
|
29
|
+
sdk_version: device.sdkVersion,
|
|
30
|
+
ad_id: device.adId,
|
|
31
|
+
is_push_permission_granted: device.isPushPermissionGranted,
|
|
32
|
+
push_token: device.pushToken,
|
|
33
|
+
push_token_type: device.pushTokenType,
|
|
34
|
+
},
|
|
35
|
+
],
|
|
36
|
+
},
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
if (response.status < 200 || response.status >= 300) {
|
|
40
|
+
throw new Error(
|
|
41
|
+
`HTTP ${response.status}: ${JSON.stringify(response.data)}`
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
ClixLogger.debug(`Device upserted successfully: ${device.id}`);
|
|
46
|
+
} catch (error) {
|
|
47
|
+
ClixLogger.error(`Failed to upsert device: ${device.id}`, error);
|
|
48
|
+
throw error;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async setProjectUserId(
|
|
53
|
+
deviceId: string,
|
|
54
|
+
projectUserId: string
|
|
55
|
+
): Promise<void> {
|
|
56
|
+
try {
|
|
57
|
+
ClixLogger.debug(`Setting project user ID for device: ${deviceId}`);
|
|
58
|
+
|
|
59
|
+
const response = await this.apiClient.post(
|
|
60
|
+
`/devices/${deviceId}/user/project-user-id`,
|
|
61
|
+
{
|
|
62
|
+
body: {
|
|
63
|
+
project_user_id: projectUserId,
|
|
64
|
+
},
|
|
65
|
+
}
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (response.status < 200 || response.status >= 300) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
`HTTP ${response.status}: ${JSON.stringify(response.data)}`
|
|
71
|
+
);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
ClixLogger.debug(
|
|
75
|
+
`Project user ID set successfully for device: ${deviceId}`
|
|
76
|
+
);
|
|
77
|
+
} catch (error) {
|
|
78
|
+
ClixLogger.error(
|
|
79
|
+
`Failed to set project user ID for device: ${deviceId}`,
|
|
80
|
+
error
|
|
81
|
+
);
|
|
82
|
+
throw error;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async removeProjectUserId(deviceId: string): Promise<void> {
|
|
87
|
+
try {
|
|
88
|
+
ClixLogger.debug(`Removing project user ID for device: ${deviceId}`);
|
|
89
|
+
|
|
90
|
+
const response = await this.apiClient.delete(
|
|
91
|
+
`/devices/${deviceId}/user/project-user-id`
|
|
92
|
+
);
|
|
93
|
+
|
|
94
|
+
if (response.status < 200 || response.status >= 300) {
|
|
95
|
+
throw new Error(
|
|
96
|
+
`HTTP ${response.status}: ${JSON.stringify(response.data)}`
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
ClixLogger.debug(
|
|
101
|
+
`Project user ID removed successfully for device: ${deviceId}`
|
|
102
|
+
);
|
|
103
|
+
} catch (error) {
|
|
104
|
+
ClixLogger.error(
|
|
105
|
+
`Failed to remove project user ID for device: ${deviceId}`,
|
|
106
|
+
error
|
|
107
|
+
);
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async upsertUserProperties(
|
|
113
|
+
deviceId: string,
|
|
114
|
+
properties: ClixUserProperty[]
|
|
115
|
+
): Promise<void> {
|
|
116
|
+
try {
|
|
117
|
+
ClixLogger.debug(
|
|
118
|
+
`Upserting ${properties.length} user properties for device: ${deviceId}`
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
const response = await this.apiClient.post(
|
|
122
|
+
`/devices/${deviceId}/user/properties`,
|
|
123
|
+
{
|
|
124
|
+
body: {
|
|
125
|
+
properties: properties.map((p) => ({
|
|
126
|
+
name: p.name,
|
|
127
|
+
value_string: p.valueString,
|
|
128
|
+
type: p.type,
|
|
129
|
+
})),
|
|
130
|
+
},
|
|
131
|
+
}
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
if (response.status < 200 || response.status >= 300) {
|
|
135
|
+
throw new Error(
|
|
136
|
+
`HTTP ${response.status}: ${JSON.stringify(response.data)}`
|
|
137
|
+
);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
ClixLogger.debug(
|
|
141
|
+
`User properties upserted successfully for device: ${deviceId}`
|
|
142
|
+
);
|
|
143
|
+
} catch (error) {
|
|
144
|
+
ClixLogger.error(
|
|
145
|
+
`Failed to upsert user properties for device: ${deviceId}`,
|
|
146
|
+
error
|
|
147
|
+
);
|
|
148
|
+
throw error;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
async removeUserProperties(
|
|
153
|
+
deviceId: string,
|
|
154
|
+
propertyNames: string[]
|
|
155
|
+
): Promise<void> {
|
|
156
|
+
try {
|
|
157
|
+
ClixLogger.debug(
|
|
158
|
+
`Removing ${propertyNames.length} user properties for device: ${deviceId}`
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
const response = await this.apiClient.delete(
|
|
162
|
+
`/devices/${deviceId}/user/properties`,
|
|
163
|
+
{
|
|
164
|
+
queryParameters: {
|
|
165
|
+
property_names: propertyNames.join(','),
|
|
166
|
+
},
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (response.status < 200 || response.status >= 300) {
|
|
171
|
+
throw new Error(
|
|
172
|
+
`HTTP ${response.status}: ${JSON.stringify(response.data)}`
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
ClixLogger.debug(
|
|
177
|
+
`User properties removed successfully for device: ${deviceId}`
|
|
178
|
+
);
|
|
179
|
+
} catch (error) {
|
|
180
|
+
ClixLogger.error(
|
|
181
|
+
`Failed to remove user properties for device: ${deviceId}`,
|
|
182
|
+
error
|
|
183
|
+
);
|
|
184
|
+
throw error;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|