react-native-nitro-amplitude 0.1.0 → 0.5.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/README.md +547 -55
- package/cpp/bindings/HybridAmplitudeWorker.cpp +27 -7
- package/lib/commonjs/analytics/config.js +31 -10
- package/lib/commonjs/analytics/config.js.map +1 -1
- package/lib/commonjs/analytics/index.js +8 -2
- package/lib/commonjs/analytics/index.js.map +1 -1
- package/lib/commonjs/analytics/network-guarded-fetch-transport.js +16 -0
- package/lib/commonjs/analytics/network-guarded-fetch-transport.js.map +1 -0
- package/lib/commonjs/analytics/nitro-transport.js +2 -0
- package/lib/commonjs/analytics/nitro-transport.js.map +1 -1
- package/lib/commonjs/analytics/plugins/context.js +7 -1
- package/lib/commonjs/analytics/plugins/context.js.map +1 -1
- package/lib/commonjs/analytics/react-native-client.js +155 -9
- package/lib/commonjs/analytics/react-native-client.js.map +1 -1
- package/lib/commonjs/diagnostics.js +92 -0
- package/lib/commonjs/diagnostics.js.map +1 -0
- package/lib/commonjs/errors.js +48 -0
- package/lib/commonjs/errors.js.map +1 -0
- package/lib/commonjs/experiment/experimentClient.js +84 -2
- package/lib/commonjs/experiment/experimentClient.js.map +1 -1
- package/lib/commonjs/experiment/index.js +12 -0
- package/lib/commonjs/experiment/index.js.map +1 -1
- package/lib/commonjs/experiment/stubClient.js +25 -0
- package/lib/commonjs/experiment/stubClient.js.map +1 -1
- package/lib/commonjs/experiment/transport/http.js +8 -2
- package/lib/commonjs/experiment/transport/http.js.map +1 -1
- package/lib/commonjs/experiment/typed-variants.js +52 -0
- package/lib/commonjs/experiment/typed-variants.js.map +1 -0
- package/lib/commonjs/experiment/types/config.js +32 -4
- package/lib/commonjs/experiment/types/config.js.map +1 -1
- package/lib/commonjs/index.js +105 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/commonjs/index.web.js +387 -13
- package/lib/commonjs/index.web.js.map +1 -1
- package/lib/commonjs/native/context.web.js +26 -0
- package/lib/commonjs/native/context.web.js.map +1 -0
- package/lib/commonjs/native/http.js +23 -8
- package/lib/commonjs/native/http.js.map +1 -1
- package/lib/commonjs/native/http.web.js +17 -0
- package/lib/commonjs/native/http.web.js.map +1 -0
- package/lib/commonjs/native/hybrid.web.js +23 -0
- package/lib/commonjs/native/hybrid.web.js.map +1 -0
- package/lib/commonjs/native/storage.js +27 -15
- package/lib/commonjs/native/storage.js.map +1 -1
- package/lib/commonjs/native/storage.web.js +135 -0
- package/lib/commonjs/native/storage.web.js.map +1 -0
- package/lib/commonjs/network.js +154 -0
- package/lib/commonjs/network.js.map +1 -0
- package/lib/commonjs/presets.js +118 -0
- package/lib/commonjs/presets.js.map +1 -0
- package/lib/commonjs/testing.js +166 -0
- package/lib/commonjs/testing.js.map +1 -0
- package/lib/module/analytics/config.js +32 -11
- package/lib/module/analytics/config.js.map +1 -1
- package/lib/module/analytics/index.js +4 -1
- package/lib/module/analytics/index.js.map +1 -1
- package/lib/module/analytics/network-guarded-fetch-transport.js +11 -0
- package/lib/module/analytics/network-guarded-fetch-transport.js.map +1 -0
- package/lib/module/analytics/nitro-transport.js +2 -0
- package/lib/module/analytics/nitro-transport.js.map +1 -1
- package/lib/module/analytics/plugins/context.js +7 -1
- package/lib/module/analytics/plugins/context.js.map +1 -1
- package/lib/module/analytics/react-native-client.js +154 -9
- package/lib/module/analytics/react-native-client.js.map +1 -1
- package/lib/module/diagnostics.js +85 -0
- package/lib/module/diagnostics.js.map +1 -0
- package/lib/module/errors.js +41 -0
- package/lib/module/errors.js.map +1 -0
- package/lib/module/experiment/experimentClient.js +84 -2
- package/lib/module/experiment/experimentClient.js.map +1 -1
- package/lib/module/experiment/index.js +1 -0
- package/lib/module/experiment/index.js.map +1 -1
- package/lib/module/experiment/stubClient.js +25 -0
- package/lib/module/experiment/stubClient.js.map +1 -1
- package/lib/module/experiment/transport/http.js +8 -2
- package/lib/module/experiment/transport/http.js.map +1 -1
- package/lib/module/experiment/typed-variants.js +43 -0
- package/lib/module/experiment/typed-variants.js.map +1 -0
- package/lib/module/experiment/types/config.js +31 -4
- package/lib/module/experiment/types/config.js.map +1 -1
- package/lib/module/index.js +15 -3
- package/lib/module/index.js.map +1 -1
- package/lib/module/index.web.js +60 -11
- package/lib/module/index.web.js.map +1 -1
- package/lib/module/native/context.web.js +18 -0
- package/lib/module/native/context.web.js.map +1 -0
- package/lib/module/native/http.js +23 -8
- package/lib/module/native/http.js.map +1 -1
- package/lib/module/native/http.web.js +12 -0
- package/lib/module/native/http.web.js.map +1 -0
- package/lib/module/native/hybrid.web.js +16 -0
- package/lib/module/native/hybrid.web.js.map +1 -0
- package/lib/module/native/storage.js +27 -15
- package/lib/module/native/storage.js.map +1 -1
- package/lib/module/native/storage.web.js +128 -0
- package/lib/module/native/storage.web.js.map +1 -0
- package/lib/module/network.js +138 -0
- package/lib/module/network.js.map +1 -0
- package/lib/module/presets.js +110 -0
- package/lib/module/presets.js.map +1 -0
- package/lib/module/testing.js +160 -0
- package/lib/module/testing.js.map +1 -0
- package/lib/typescript/analytics/config.d.ts +19 -6
- package/lib/typescript/analytics/config.d.ts.map +1 -1
- package/lib/typescript/analytics/index.d.ts +1 -1
- package/lib/typescript/analytics/index.d.ts.map +1 -1
- package/lib/typescript/analytics/network-guarded-fetch-transport.d.ts +6 -0
- package/lib/typescript/analytics/network-guarded-fetch-transport.d.ts.map +1 -0
- package/lib/typescript/analytics/nitro-transport.d.ts.map +1 -1
- package/lib/typescript/analytics/plugins/context.d.ts +2 -0
- package/lib/typescript/analytics/plugins/context.d.ts.map +1 -1
- package/lib/typescript/analytics/react-native-client.d.ts +46 -6
- package/lib/typescript/analytics/react-native-client.d.ts.map +1 -1
- package/lib/typescript/diagnostics.d.ts +21 -0
- package/lib/typescript/diagnostics.d.ts.map +1 -0
- package/lib/typescript/errors.d.ts +9 -0
- package/lib/typescript/errors.d.ts.map +1 -0
- package/lib/typescript/experiment/experimentClient.d.ts +9 -1
- package/lib/typescript/experiment/experimentClient.d.ts.map +1 -1
- package/lib/typescript/experiment/index.d.ts +1 -0
- package/lib/typescript/experiment/index.d.ts.map +1 -1
- package/lib/typescript/experiment/stubClient.d.ts +6 -1
- package/lib/typescript/experiment/stubClient.d.ts.map +1 -1
- package/lib/typescript/experiment/transport/http.d.ts.map +1 -1
- package/lib/typescript/experiment/typed-variants.d.ts +9 -0
- package/lib/typescript/experiment/typed-variants.d.ts.map +1 -0
- package/lib/typescript/experiment/types/client.d.ts +21 -0
- package/lib/typescript/experiment/types/client.d.ts.map +1 -1
- package/lib/typescript/experiment/types/config.d.ts.map +1 -1
- package/lib/typescript/index.d.ts +12 -3
- package/lib/typescript/index.d.ts.map +1 -1
- package/lib/typescript/index.web.d.ts +37 -8
- package/lib/typescript/index.web.d.ts.map +1 -1
- package/lib/typescript/native/context.web.d.ts +8 -0
- package/lib/typescript/native/context.web.d.ts.map +1 -0
- package/lib/typescript/native/http.d.ts.map +1 -1
- package/lib/typescript/native/http.web.d.ts +6 -0
- package/lib/typescript/native/http.web.d.ts.map +1 -0
- package/lib/typescript/native/hybrid.web.d.ts +8 -0
- package/lib/typescript/native/hybrid.web.d.ts.map +1 -0
- package/lib/typescript/native/storage.d.ts.map +1 -1
- package/lib/typescript/native/storage.web.d.ts +30 -0
- package/lib/typescript/native/storage.web.d.ts.map +1 -0
- package/lib/typescript/network.d.ts +50 -0
- package/lib/typescript/network.d.ts.map +1 -0
- package/lib/typescript/presets.d.ts +50 -0
- package/lib/typescript/presets.d.ts.map +1 -0
- package/lib/typescript/testing.d.ts +11 -0
- package/lib/typescript/testing.d.ts.map +1 -0
- package/package.json +4 -2
- package/src/analytics/config.ts +33 -8
- package/src/analytics/index.ts +3 -0
- package/src/analytics/network-guarded-fetch-transport.ts +10 -0
- package/src/analytics/nitro-transport.ts +2 -0
- package/src/analytics/plugins/context.ts +10 -1
- package/src/analytics/react-native-client.ts +238 -9
- package/src/diagnostics.ts +119 -0
- package/src/errors.ts +60 -0
- package/src/experiment/experimentClient.ts +116 -3
- package/src/experiment/index.ts +1 -0
- package/src/experiment/stubClient.ts +42 -1
- package/src/experiment/transport/http.ts +10 -2
- package/src/experiment/typed-variants.ts +68 -0
- package/src/experiment/types/client.ts +29 -0
- package/src/experiment/types/config.ts +29 -5
- package/src/index.ts +28 -2
- package/src/index.web.ts +89 -14
- package/src/native/context.web.ts +38 -0
- package/src/native/http.ts +38 -8
- package/src/native/http.web.ts +24 -0
- package/src/native/hybrid.web.ts +21 -0
- package/src/native/storage.ts +27 -25
- package/src/native/storage.web.ts +152 -0
- package/src/network.ts +258 -0
- package/src/presets.ts +208 -0
- package/src/testing.ts +177 -0
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
Client,
|
|
3
|
+
ExperimentFetchResult,
|
|
4
|
+
ExperimentVariantResult,
|
|
5
|
+
FetchOptions,
|
|
6
|
+
} from "./types/client";
|
|
2
7
|
import { Defaults } from "./types/config";
|
|
3
8
|
import { ExperimentUser, ExperimentUserProvider } from "./types/user";
|
|
4
9
|
import { Variant, Variants } from "./types/variant";
|
|
@@ -33,6 +38,20 @@ export class StubExperimentClient implements Client {
|
|
|
33
38
|
return this;
|
|
34
39
|
}
|
|
35
40
|
|
|
41
|
+
public async fetchWithMetadata(
|
|
42
|
+
_user?: ExperimentUser,
|
|
43
|
+
_options?: FetchOptions,
|
|
44
|
+
): Promise<ExperimentFetchResult> {
|
|
45
|
+
return {
|
|
46
|
+
fetched: false,
|
|
47
|
+
flagKeys: [],
|
|
48
|
+
cacheHit: false,
|
|
49
|
+
durationMillis: 0,
|
|
50
|
+
source: "cache",
|
|
51
|
+
failureReason: "stub_client",
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
36
55
|
public getUserProvider(): ExperimentUserProvider {
|
|
37
56
|
return {
|
|
38
57
|
async getUser(): Promise<ExperimentUser> {
|
|
@@ -51,11 +70,33 @@ export class StubExperimentClient implements Client {
|
|
|
51
70
|
return Defaults.fallbackVariant ?? {};
|
|
52
71
|
}
|
|
53
72
|
|
|
73
|
+
public variantWithMetadata(
|
|
74
|
+
_key: string,
|
|
75
|
+
_fallback?: string | Variant,
|
|
76
|
+
): ExperimentVariantResult {
|
|
77
|
+
return {
|
|
78
|
+
variant: Defaults.fallbackVariant ?? {},
|
|
79
|
+
fallback: true,
|
|
80
|
+
stale: false,
|
|
81
|
+
reason: "fallback",
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
54
85
|
public all(): Variants {
|
|
55
86
|
return {};
|
|
56
87
|
}
|
|
57
88
|
|
|
58
89
|
public clear(): void {}
|
|
59
90
|
|
|
91
|
+
public clearVariants(): void {}
|
|
92
|
+
|
|
93
|
+
public hasCachedVariant(_key: string): boolean {
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
public getLastFetchTime(): number | undefined {
|
|
98
|
+
return undefined;
|
|
99
|
+
}
|
|
100
|
+
|
|
60
101
|
public exposure(_key: string): void {}
|
|
61
102
|
}
|
|
@@ -66,11 +66,19 @@ const _request = (
|
|
|
66
66
|
): Promise<SimpleResponse> => {
|
|
67
67
|
const abortController = getAbortController();
|
|
68
68
|
const call = async () => {
|
|
69
|
-
const
|
|
69
|
+
const upperMethod = method.toUpperCase();
|
|
70
|
+
const init: RequestInit = {
|
|
70
71
|
method: method,
|
|
71
72
|
headers: headers,
|
|
72
|
-
body: data,
|
|
73
73
|
signal: abortController?.signal,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
if (upperMethod !== "GET" && upperMethod !== "HEAD") {
|
|
77
|
+
init.body = data;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const response = await getFetch()(requestUrl, {
|
|
81
|
+
...init,
|
|
74
82
|
});
|
|
75
83
|
const simpleResponse: SimpleResponse = {
|
|
76
84
|
status: response.status,
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { Client } from "./types/client";
|
|
2
|
+
import type { Variant } from "./types/variant";
|
|
3
|
+
|
|
4
|
+
export function variantString(
|
|
5
|
+
client: Pick<Client, "variant">,
|
|
6
|
+
key: string,
|
|
7
|
+
fallback: string,
|
|
8
|
+
): string {
|
|
9
|
+
const value = client.variant(key, fallback).value;
|
|
10
|
+
return value ?? fallback;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function variantBoolean(
|
|
14
|
+
client: Pick<Client, "variant">,
|
|
15
|
+
key: string,
|
|
16
|
+
fallback: boolean,
|
|
17
|
+
): boolean {
|
|
18
|
+
const value = client.variant(key, String(fallback)).value;
|
|
19
|
+
if (value === "true") {
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
if (value === "false") {
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
return fallback;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function variantNumber(
|
|
29
|
+
client: Pick<Client, "variant">,
|
|
30
|
+
key: string,
|
|
31
|
+
fallback: number,
|
|
32
|
+
): number {
|
|
33
|
+
const value = client.variant(key, String(fallback)).value;
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
return fallback;
|
|
36
|
+
}
|
|
37
|
+
const parsed = Number(value);
|
|
38
|
+
return Number.isFinite(parsed) ? parsed : fallback;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function variantPayload<T>(
|
|
42
|
+
client: Pick<Client, "variant">,
|
|
43
|
+
key: string,
|
|
44
|
+
fallback: T,
|
|
45
|
+
): T {
|
|
46
|
+
const payload = client.variant(key).payload;
|
|
47
|
+
return payload === undefined ? fallback : (payload as T);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export function variantJson<T>(
|
|
51
|
+
client: Pick<Client, "variant">,
|
|
52
|
+
key: string,
|
|
53
|
+
fallback: T,
|
|
54
|
+
): T {
|
|
55
|
+
const variant = client.variant(key);
|
|
56
|
+
return parseVariantJson(variant, fallback);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export function parseVariantJson<T>(variant: Variant, fallback: T): T {
|
|
60
|
+
if (typeof variant.value !== "string") {
|
|
61
|
+
return fallback;
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
return JSON.parse(variant.value) as T;
|
|
65
|
+
} catch {
|
|
66
|
+
return fallback;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ExperimentUser, ExperimentUserProvider } from "./user";
|
|
2
2
|
import { Variant, Variants } from "./variant";
|
|
3
|
+
import { VariantSource } from "./source";
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Interface for the main client.
|
|
@@ -9,10 +10,21 @@ export interface Client {
|
|
|
9
10
|
start(user?: ExperimentUser): Promise<void>;
|
|
10
11
|
stop(): void;
|
|
11
12
|
fetch(user?: ExperimentUser, options?: FetchOptions): Promise<Client>;
|
|
13
|
+
fetchWithMetadata(
|
|
14
|
+
user?: ExperimentUser,
|
|
15
|
+
options?: FetchOptions,
|
|
16
|
+
): Promise<ExperimentFetchResult>;
|
|
12
17
|
fetchOrThrow(user?: ExperimentUser, options?: FetchOptions): Promise<Client>;
|
|
13
18
|
variant(key: string, fallback?: string | Variant): Variant;
|
|
19
|
+
variantWithMetadata(
|
|
20
|
+
key: string,
|
|
21
|
+
fallback?: string | Variant,
|
|
22
|
+
): ExperimentVariantResult;
|
|
14
23
|
all(): Variants;
|
|
15
24
|
clear(): void;
|
|
25
|
+
clearVariants(): void;
|
|
26
|
+
hasCachedVariant(key: string): boolean;
|
|
27
|
+
getLastFetchTime(): number | undefined;
|
|
16
28
|
exposure(key: string): void;
|
|
17
29
|
getUser(): ExperimentUser;
|
|
18
30
|
setUser(user: ExperimentUser): void;
|
|
@@ -36,3 +48,20 @@ export type FetchOptions = {
|
|
|
36
48
|
*/
|
|
37
49
|
flagKeys?: string[];
|
|
38
50
|
};
|
|
51
|
+
|
|
52
|
+
export type ExperimentFetchResult = {
|
|
53
|
+
fetched: boolean;
|
|
54
|
+
flagKeys: string[];
|
|
55
|
+
cacheHit: boolean;
|
|
56
|
+
durationMillis: number;
|
|
57
|
+
source: "network" | "cache";
|
|
58
|
+
failureReason?: string;
|
|
59
|
+
};
|
|
60
|
+
|
|
61
|
+
export type ExperimentVariantResult = {
|
|
62
|
+
variant: Variant;
|
|
63
|
+
source?: VariantSource;
|
|
64
|
+
fallback: boolean;
|
|
65
|
+
stale: boolean;
|
|
66
|
+
reason?: "missing_flag" | "fetch_failure" | "no_assignment" | "fallback";
|
|
67
|
+
};
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { NitroMemoryStorage } from "../../native/storage";
|
|
3
|
-
|
|
1
|
+
import { isNative } from "../util/platform";
|
|
4
2
|
import { ExposureTrackingProvider } from "./exposure";
|
|
5
3
|
import { Logger, LogLevel } from "./logger";
|
|
6
4
|
import { Source } from "./source";
|
|
@@ -9,6 +7,28 @@ import { HttpClient } from "./transport";
|
|
|
9
7
|
import { ExperimentUserProvider } from "./user";
|
|
10
8
|
import { Variant, Variants } from "./variant";
|
|
11
9
|
|
|
10
|
+
function createDefaultHttpClient(): HttpClient {
|
|
11
|
+
if (isNative()) {
|
|
12
|
+
const { nitroHttpClient } =
|
|
13
|
+
require("../../native/http") as typeof import("../../native/http");
|
|
14
|
+
return nitroHttpClient;
|
|
15
|
+
}
|
|
16
|
+
const { nitroHttpClient } =
|
|
17
|
+
require("../../native/http.web") as typeof import("../../native/http");
|
|
18
|
+
return nitroHttpClient;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createDefaultStorage(): Storage {
|
|
22
|
+
if (isNative()) {
|
|
23
|
+
const { NitroMemoryStorage } =
|
|
24
|
+
require("../../native/storage") as typeof import("../../native/storage");
|
|
25
|
+
return new NitroMemoryStorage("experiment");
|
|
26
|
+
}
|
|
27
|
+
const { NitroMemoryStorage } =
|
|
28
|
+
require("../../native/storage.web") as typeof import("../../native/storage");
|
|
29
|
+
return new NitroMemoryStorage("experiment");
|
|
30
|
+
}
|
|
31
|
+
|
|
12
32
|
/**
|
|
13
33
|
* @category Configuration
|
|
14
34
|
*/
|
|
@@ -205,6 +225,10 @@ export const Defaults: ExperimentConfig = {
|
|
|
205
225
|
automaticFetchOnAmplitudeIdentityChange: false,
|
|
206
226
|
userProvider: null,
|
|
207
227
|
exposureTrackingProvider: null,
|
|
208
|
-
httpClient
|
|
209
|
-
|
|
228
|
+
get httpClient() {
|
|
229
|
+
return createDefaultHttpClient();
|
|
230
|
+
},
|
|
231
|
+
get storage() {
|
|
232
|
+
return createDefaultStorage();
|
|
233
|
+
},
|
|
210
234
|
};
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import analyticsClient, {
|
|
2
2
|
createInstance,
|
|
3
3
|
} from "./analytics/react-native-client";
|
|
4
|
+
import type { AmplitudeDiagnostics } from "./diagnostics";
|
|
5
|
+
import { getAmplitudeDiagnostics } from "./diagnostics";
|
|
4
6
|
import { prefetchNativeContext } from "./native/context";
|
|
5
7
|
|
|
6
8
|
import * as AnalyticsTypes from "./analytics/types";
|
|
@@ -27,19 +29,42 @@ export const {
|
|
|
27
29
|
shutdown,
|
|
28
30
|
track,
|
|
29
31
|
extendSession,
|
|
32
|
+
flushWithResult,
|
|
33
|
+
healthCheck,
|
|
30
34
|
} = analyticsClient;
|
|
31
35
|
|
|
36
|
+
export function getDiagnostics(): AmplitudeDiagnostics {
|
|
37
|
+
return getAmplitudeDiagnostics(analyticsClient);
|
|
38
|
+
}
|
|
39
|
+
|
|
32
40
|
export { Revenue, Identify } from "@amplitude/analytics-core";
|
|
33
41
|
export {
|
|
34
42
|
InMemoryStorage,
|
|
35
43
|
LocalStorage,
|
|
36
44
|
MemoryStorage,
|
|
37
45
|
} from "./analytics/storage/local-storage";
|
|
38
|
-
export {
|
|
46
|
+
export {
|
|
47
|
+
NitroAnalyticsStorage,
|
|
48
|
+
NitroExperimentStorage,
|
|
49
|
+
NitroMemoryStorage,
|
|
50
|
+
} from "./native/storage";
|
|
39
51
|
export { nitroHttpClient } from "./native/http";
|
|
40
52
|
export { nitroTransport } from "./analytics/nitro-transport";
|
|
41
53
|
export { prefetchNativeContext };
|
|
42
54
|
export { AnalyticsTypes as Types };
|
|
55
|
+
export {
|
|
56
|
+
getAmplitudeDiagnostics,
|
|
57
|
+
getLastNativeError,
|
|
58
|
+
getNativeStartupDiagnostics,
|
|
59
|
+
} from "./diagnostics";
|
|
60
|
+
export type {
|
|
61
|
+
AmplitudeDiagnostics,
|
|
62
|
+
NativeStartupDiagnostics,
|
|
63
|
+
} from "./diagnostics";
|
|
64
|
+
export * from "./errors";
|
|
65
|
+
export * from "./network";
|
|
66
|
+
export * from "./presets";
|
|
67
|
+
export * from "./testing";
|
|
43
68
|
|
|
44
69
|
export * from "./experiment/types/config";
|
|
45
70
|
export { Experiment } from "./experiment/factory";
|
|
@@ -58,9 +83,10 @@ export {
|
|
|
58
83
|
LocalStorage as ExperimentLocalStorage,
|
|
59
84
|
MemoryStorage as ExperimentMemoryStorage,
|
|
60
85
|
} from "./experiment/storage/local-storage";
|
|
86
|
+
export * from "./experiment/typed-variants";
|
|
61
87
|
|
|
62
88
|
export type { AmplitudeContext } from "./AmplitudeContext.nitro";
|
|
63
89
|
export type { AmplitudeStorage } from "./AmplitudeStorage.nitro";
|
|
64
90
|
export type { AmplitudeWorker } from "./AmplitudeWorker.nitro";
|
|
65
91
|
|
|
66
|
-
export const VERSION = "0.
|
|
92
|
+
export const VERSION = "0.5.0";
|
package/src/index.web.ts
CHANGED
|
@@ -1,19 +1,94 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
};
|
|
1
|
+
import analyticsClient, {
|
|
2
|
+
createInstance,
|
|
3
|
+
} from "./analytics/react-native-client";
|
|
4
|
+
import type { Transport } from "@amplitude/analytics-core";
|
|
5
|
+
import { NetworkGuardedFetchTransport } from "./analytics/network-guarded-fetch-transport";
|
|
6
|
+
import type { AmplitudeDiagnostics } from "./diagnostics";
|
|
7
|
+
import { getAmplitudeDiagnostics } from "./diagnostics";
|
|
8
|
+
import { prefetchNativeContext } from "./native/context.web";
|
|
6
9
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
export
|
|
10
|
-
export const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
10
|
+
import * as AnalyticsTypes from "./analytics/types";
|
|
11
|
+
|
|
12
|
+
export { createInstance };
|
|
13
|
+
export const {
|
|
14
|
+
add,
|
|
15
|
+
flush,
|
|
16
|
+
getDeviceId,
|
|
17
|
+
getSessionId,
|
|
18
|
+
getUserId,
|
|
19
|
+
groupIdentify,
|
|
20
|
+
identify,
|
|
21
|
+
init,
|
|
22
|
+
logEvent,
|
|
23
|
+
remove,
|
|
24
|
+
reset,
|
|
25
|
+
revenue,
|
|
26
|
+
setDeviceId,
|
|
27
|
+
setGroup,
|
|
28
|
+
setOptOut,
|
|
29
|
+
setSessionId,
|
|
30
|
+
setUserId,
|
|
31
|
+
shutdown,
|
|
32
|
+
track,
|
|
33
|
+
extendSession,
|
|
34
|
+
flushWithResult,
|
|
35
|
+
healthCheck,
|
|
36
|
+
} = analyticsClient;
|
|
37
|
+
|
|
38
|
+
export function getDiagnostics(): AmplitudeDiagnostics {
|
|
39
|
+
return getAmplitudeDiagnostics(analyticsClient);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export { Revenue, Identify } from "@amplitude/analytics-core";
|
|
43
|
+
export {
|
|
44
|
+
InMemoryStorage,
|
|
45
|
+
LocalStorage,
|
|
46
|
+
MemoryStorage,
|
|
47
|
+
} from "./analytics/storage/local-storage";
|
|
48
|
+
export {
|
|
49
|
+
NitroAnalyticsStorage,
|
|
50
|
+
NitroExperimentStorage,
|
|
51
|
+
NitroMemoryStorage,
|
|
52
|
+
} from "./native/storage.web";
|
|
53
|
+
export { nitroHttpClient } from "./native/http.web";
|
|
54
|
+
export const nitroTransport: Transport = new NetworkGuardedFetchTransport();
|
|
55
|
+
export { prefetchNativeContext };
|
|
56
|
+
export { AnalyticsTypes as Types };
|
|
57
|
+
export {
|
|
58
|
+
getAmplitudeDiagnostics,
|
|
59
|
+
getLastNativeError,
|
|
60
|
+
getNativeStartupDiagnostics,
|
|
61
|
+
} from "./diagnostics";
|
|
62
|
+
export type {
|
|
63
|
+
AmplitudeDiagnostics,
|
|
64
|
+
NativeStartupDiagnostics,
|
|
65
|
+
} from "./diagnostics";
|
|
66
|
+
export * from "./errors";
|
|
67
|
+
export * from "./network";
|
|
68
|
+
export * from "./presets";
|
|
69
|
+
export * from "./testing";
|
|
70
|
+
|
|
71
|
+
export * from "./experiment/types/config";
|
|
72
|
+
export { Experiment } from "./experiment/factory";
|
|
73
|
+
export { StubExperimentClient } from "./experiment/stubClient";
|
|
74
|
+
export { ExperimentClient } from "./experiment/experimentClient";
|
|
75
|
+
export * from "./experiment/types/client";
|
|
76
|
+
export { Source } from "./experiment/types/source";
|
|
77
|
+
export * from "./experiment/types/user";
|
|
78
|
+
export * from "./experiment/types/variant";
|
|
79
|
+
export * from "./experiment/types/exposure";
|
|
80
|
+
export * from "./experiment/types/storage";
|
|
81
|
+
export { LogLevel } from "./experiment/types/logger";
|
|
82
|
+
export type { Logger } from "./experiment/types/logger";
|
|
83
|
+
export { ConsoleLogger } from "./experiment/logger/consoleLogger";
|
|
84
|
+
export {
|
|
85
|
+
LocalStorage as ExperimentLocalStorage,
|
|
86
|
+
MemoryStorage as ExperimentMemoryStorage,
|
|
87
|
+
} from "./experiment/storage/local-storage";
|
|
88
|
+
export * from "./experiment/typed-variants";
|
|
16
89
|
|
|
17
90
|
export type { AmplitudeContext } from "./AmplitudeContext.nitro";
|
|
18
91
|
export type { AmplitudeStorage } from "./AmplitudeStorage.nitro";
|
|
19
92
|
export type { AmplitudeWorker } from "./AmplitudeWorker.nitro";
|
|
93
|
+
|
|
94
|
+
export const VERSION = "0.5.0";
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ReactNativeTrackingOptions } from "@amplitude/analytics-core";
|
|
2
|
+
import type { LegacySessionData, NativeApplicationContext } from "./context";
|
|
3
|
+
|
|
4
|
+
type NavigatorWithLanguage = Navigator & {
|
|
5
|
+
userLanguage?: string;
|
|
6
|
+
};
|
|
7
|
+
|
|
8
|
+
export function prefetchNativeContext(): void {}
|
|
9
|
+
|
|
10
|
+
export function getNativeApplicationContext(
|
|
11
|
+
_options: ReactNativeTrackingOptions,
|
|
12
|
+
): NativeApplicationContext {
|
|
13
|
+
const browserNavigator =
|
|
14
|
+
typeof navigator === "undefined"
|
|
15
|
+
? undefined
|
|
16
|
+
: (navigator as NavigatorWithLanguage);
|
|
17
|
+
return {
|
|
18
|
+
platform: "Web",
|
|
19
|
+
language: browserNavigator?.language ?? browserNavigator?.userLanguage,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function getLegacySessionData(_instanceName: string): LegacySessionData {
|
|
24
|
+
return {};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getLegacyEvents(
|
|
28
|
+
_instanceName: string,
|
|
29
|
+
_eventKind: string,
|
|
30
|
+
): string[] {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function removeLegacyEvent(
|
|
35
|
+
_instanceName: string,
|
|
36
|
+
_eventKind: string,
|
|
37
|
+
_eventId: number,
|
|
38
|
+
): void {}
|
package/src/native/http.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import type { HttpClient, SimpleResponse } from "../experiment/types/transport";
|
|
2
|
+
import { createAmplitudeError, getAmplitudeErrorCode } from "../errors";
|
|
3
|
+
import { assertNetworkEnabled } from "../network";
|
|
2
4
|
import { getAmplitudeWorker } from "./hybrid";
|
|
5
|
+
import type { AmplitudeWorker } from "../AmplitudeWorker.nitro";
|
|
3
6
|
|
|
4
7
|
type PendingRequest = {
|
|
5
8
|
resolve: (response: SimpleResponse) => void;
|
|
@@ -9,13 +12,18 @@ type PendingRequest = {
|
|
|
9
12
|
|
|
10
13
|
const pendingRequests = new Map<string, PendingRequest>();
|
|
11
14
|
let listenerInstalled = false;
|
|
15
|
+
let listenerWorker: AmplitudeWorker | undefined;
|
|
16
|
+
const DEFAULT_TIMEOUT_MILLIS = 10000;
|
|
17
|
+
const MAX_TIMEOUT_MILLIS = 300000;
|
|
12
18
|
|
|
13
19
|
function ensureListener(): void {
|
|
14
|
-
|
|
20
|
+
const worker = getAmplitudeWorker();
|
|
21
|
+
if (listenerInstalled && listenerWorker === worker) {
|
|
15
22
|
return;
|
|
16
23
|
}
|
|
17
24
|
listenerInstalled = true;
|
|
18
|
-
|
|
25
|
+
listenerWorker = worker;
|
|
26
|
+
worker.addOnComplete((requestId, statusCode, body, error) => {
|
|
19
27
|
const pending = pendingRequests.get(requestId);
|
|
20
28
|
if (!pending) {
|
|
21
29
|
return;
|
|
@@ -23,7 +31,9 @@ function ensureListener(): void {
|
|
|
23
31
|
pendingRequests.delete(requestId);
|
|
24
32
|
clearTimeout(pending.timeoutId);
|
|
25
33
|
if (error) {
|
|
26
|
-
pending.reject(
|
|
34
|
+
pending.reject(
|
|
35
|
+
createAmplitudeError(getAmplitudeErrorCode(new Error(error)), error),
|
|
36
|
+
);
|
|
27
37
|
return;
|
|
28
38
|
}
|
|
29
39
|
pending.resolve({
|
|
@@ -37,22 +47,36 @@ function createRequestId(): string {
|
|
|
37
47
|
return `req_${Date.now()}_${Math.random().toString(36).slice(2, 10)}`;
|
|
38
48
|
}
|
|
39
49
|
|
|
50
|
+
function normalizeTimeoutMillis(timeoutMillis: number): number {
|
|
51
|
+
if (!Number.isFinite(timeoutMillis) || timeoutMillis <= 0) {
|
|
52
|
+
return DEFAULT_TIMEOUT_MILLIS;
|
|
53
|
+
}
|
|
54
|
+
return Math.min(Math.ceil(timeoutMillis), MAX_TIMEOUT_MILLIS);
|
|
55
|
+
}
|
|
56
|
+
|
|
40
57
|
export class NitroHttpClient implements HttpClient {
|
|
41
58
|
async request(
|
|
42
59
|
requestUrl: string,
|
|
43
60
|
method: string,
|
|
44
61
|
headers: Record<string, string>,
|
|
45
62
|
data: string | null,
|
|
46
|
-
timeoutMillis =
|
|
63
|
+
timeoutMillis = DEFAULT_TIMEOUT_MILLIS,
|
|
47
64
|
): Promise<SimpleResponse> {
|
|
65
|
+
assertNetworkEnabled();
|
|
48
66
|
ensureListener();
|
|
49
67
|
const requestId = createRequestId();
|
|
68
|
+
const normalizedTimeoutMillis = normalizeTimeoutMillis(timeoutMillis);
|
|
50
69
|
return new Promise<SimpleResponse>((resolve, reject) => {
|
|
51
70
|
const timeoutId = setTimeout(() => {
|
|
52
71
|
pendingRequests.delete(requestId);
|
|
53
72
|
getAmplitudeWorker().cancel(requestId);
|
|
54
|
-
reject(
|
|
55
|
-
|
|
73
|
+
reject(
|
|
74
|
+
createAmplitudeError(
|
|
75
|
+
"timeout",
|
|
76
|
+
`Request timed out after ${normalizedTimeoutMillis}ms`,
|
|
77
|
+
),
|
|
78
|
+
);
|
|
79
|
+
}, normalizedTimeoutMillis + 250);
|
|
56
80
|
|
|
57
81
|
pendingRequests.set(requestId, { resolve, reject, timeoutId });
|
|
58
82
|
|
|
@@ -63,12 +87,18 @@ export class NitroHttpClient implements HttpClient {
|
|
|
63
87
|
method,
|
|
64
88
|
JSON.stringify(headers),
|
|
65
89
|
data ?? "",
|
|
66
|
-
|
|
90
|
+
normalizedTimeoutMillis,
|
|
67
91
|
);
|
|
68
92
|
} catch (error) {
|
|
69
93
|
pendingRequests.delete(requestId);
|
|
70
94
|
clearTimeout(timeoutId);
|
|
71
|
-
reject(
|
|
95
|
+
reject(
|
|
96
|
+
createAmplitudeError(
|
|
97
|
+
getAmplitudeErrorCode(error),
|
|
98
|
+
error instanceof Error ? error.message : String(error),
|
|
99
|
+
error,
|
|
100
|
+
),
|
|
101
|
+
);
|
|
72
102
|
}
|
|
73
103
|
});
|
|
74
104
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { FetchHttpClient } from "../experiment/transport/http";
|
|
2
|
+
import type { HttpClient, SimpleResponse } from "../experiment/types/transport";
|
|
3
|
+
import { assertNetworkEnabled } from "../network";
|
|
4
|
+
|
|
5
|
+
export class NitroHttpClient implements HttpClient {
|
|
6
|
+
request(
|
|
7
|
+
requestUrl: string,
|
|
8
|
+
method: string,
|
|
9
|
+
headers: Record<string, string>,
|
|
10
|
+
data: string | null,
|
|
11
|
+
timeoutMillis = 10000,
|
|
12
|
+
): Promise<SimpleResponse> {
|
|
13
|
+
assertNetworkEnabled();
|
|
14
|
+
return FetchHttpClient.request(
|
|
15
|
+
requestUrl,
|
|
16
|
+
method,
|
|
17
|
+
headers,
|
|
18
|
+
data ?? "",
|
|
19
|
+
timeoutMillis,
|
|
20
|
+
);
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export const nitroHttpClient = new NitroHttpClient();
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AmplitudeContext } from "../AmplitudeContext.nitro";
|
|
2
|
+
import type { AmplitudeStorage } from "../AmplitudeStorage.nitro";
|
|
3
|
+
import type { AmplitudeWorker } from "../AmplitudeWorker.nitro";
|
|
4
|
+
|
|
5
|
+
function unavailable(): never {
|
|
6
|
+
throw new Error("Nitro Amplitude native bindings are not available on web");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function getAmplitudeContext(): AmplitudeContext {
|
|
10
|
+
return unavailable();
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export function getAmplitudeStorage(): AmplitudeStorage {
|
|
14
|
+
return unavailable();
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getAmplitudeWorker(): AmplitudeWorker {
|
|
18
|
+
return unavailable();
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function resetHybridInstancesForTests(): void {}
|