@amplytools/react-native-amply-sdk 0.11.0 → 0.12.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/AmplyReactNative.podspec +1 -1
- package/README.md +10 -1
- package/android/build.gradle +1 -1
- package/android/src/main/java/tools/amply/sdk/reactnative/AmplyModule.kt +12 -3
- package/android/src/main/java/tools/amply/sdk/reactnative/core/DefaultAmplyClient.kt +23 -5
- package/dist/src/__tests__/gateRegistrationLifecycle.test.js +4 -4
- package/dist/src/__tests__/index.test.js +25 -1
- package/dist/src/index.d.ts +16 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +25 -0
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/docs/FEATURE_DEBUG.md +3 -1
- package/ios/Sources/AmplyReactNative/AmplyModule.mm +34 -7
- package/package.json +4 -3
- package/scripts/check-sample-parity.sh +263 -0
- package/src/__tests__/gateRegistrationLifecycle.test.ts +4 -4
- package/src/__tests__/index.test.ts +28 -1
- package/src/index.ts +40 -2
package/AmplyReactNative.podspec
CHANGED
package/README.md
CHANGED
|
@@ -42,10 +42,12 @@ If you upgraded from v0.2.11 or earlier and have `"@amplytools/react-native-ampl
|
|
|
42
42
|
```typescript
|
|
43
43
|
import Amply from '@amplytools/react-native-amply-sdk';
|
|
44
44
|
|
|
45
|
-
// Initialize
|
|
45
|
+
// Initialize — all three keys are required (your application's page in Amply).
|
|
46
|
+
// Use the iOS application's keys on iOS and the Android application's on Android.
|
|
46
47
|
await Amply.initialize({
|
|
47
48
|
appId: 'YOUR_APP_ID',
|
|
48
49
|
apiKeyPublic: 'YOUR_PUBLIC_API_KEY',
|
|
50
|
+
apiKeySecret: 'YOUR_SECRET_API_KEY',
|
|
49
51
|
debug: true, // optional: enable debug logging
|
|
50
52
|
});
|
|
51
53
|
|
|
@@ -67,6 +69,13 @@ const unsubscribe = await Amply.addDeepLinkListener((event) => {
|
|
|
67
69
|
});
|
|
68
70
|
```
|
|
69
71
|
|
|
72
|
+
### About the keys
|
|
73
|
+
|
|
74
|
+
`apiKeySecret` ships inside your app: the SDK signs every request with it on the device. Keep it
|
|
75
|
+
out of source control and inject it at build time, like the public key. If any of the three keys
|
|
76
|
+
is missing or blank, `initialize` rejects with `AMP_INVALID_CONFIG`, logs which key is missing,
|
|
77
|
+
and Amply stays off — every later call is a no-op. It never crashes your app.
|
|
78
|
+
|
|
70
79
|
## Documentation
|
|
71
80
|
|
|
72
81
|
Full integration guides, API reference, and examples:
|
package/android/build.gradle
CHANGED
|
@@ -15,7 +15,7 @@ buildscript {
|
|
|
15
15
|
apply plugin: 'com.android.library'
|
|
16
16
|
apply plugin: 'org.jetbrains.kotlin.android'
|
|
17
17
|
|
|
18
|
-
def amplySdkVersion = project.findProperty('amplySdkVersion') ?: System.getenv('AMPLY_SDK_VERSION') ?: '0.
|
|
18
|
+
def amplySdkVersion = project.findProperty('amplySdkVersion') ?: System.getenv('AMPLY_SDK_VERSION') ?: '0.12.0'
|
|
19
19
|
group = 'tools.amply'
|
|
20
20
|
version = amplySdkVersion
|
|
21
21
|
|
|
@@ -334,11 +334,20 @@ class AmplyModule(reactContext: ReactApplicationContext) :
|
|
|
334
334
|
|
|
335
335
|
// ---- твои helper-методы без изменений ----
|
|
336
336
|
|
|
337
|
+
private fun ReadableMap.requiredString(key: String): String {
|
|
338
|
+
val value = if (hasKey(key)) getString(key) else null
|
|
339
|
+
if (value.isNullOrBlank()) throw IllegalArgumentException("'$key' is required")
|
|
340
|
+
return value
|
|
341
|
+
}
|
|
342
|
+
|
|
337
343
|
private fun ReadableMap.toInitializationOptions(): AmplyInitializationOptions {
|
|
338
|
-
|
|
339
|
-
|
|
344
|
+
// All three keys are required, blank included: a blank secret used to pass straight through
|
|
345
|
+
// and sign every request with an empty key, which the backend refuses — a silent failure
|
|
346
|
+
// instead of this rejection.
|
|
347
|
+
val appId = requiredString("appId")
|
|
348
|
+
val apiKeyPublic = requiredString("apiKeyPublic")
|
|
349
|
+
val apiKeySecret = requiredString("apiKeySecret")
|
|
340
350
|
|
|
341
|
-
val apiKeySecret = if (hasKey("apiKeySecret")) getString("apiKeySecret") else null
|
|
342
351
|
val configBaseUrl = if (hasKey("configBaseUrl")) getString("configBaseUrl") else null
|
|
343
352
|
val backendBaseUrl = if (hasKey("backendBaseUrl")) getString("backendBaseUrl") else null
|
|
344
353
|
val endpoint = if (hasKey("endpoint")) getString("endpoint") else null
|
|
@@ -144,9 +144,16 @@ class DefaultAmplyClient(
|
|
|
144
144
|
synchronized(propertyLock) {
|
|
145
145
|
amplyInstance = instance
|
|
146
146
|
if (pendingPropertyOps.isNotEmpty()) {
|
|
147
|
-
|
|
148
|
-
|
|
147
|
+
// Taken out of the list before running, and each op guarded: one throwing op used to
|
|
148
|
+
// abort the drain after amplyInstance was already set, so the rest were never
|
|
149
|
+
// replayed and initialize rejected while isInitialized() reported true.
|
|
150
|
+
val ops = pendingPropertyOps.toList()
|
|
149
151
|
pendingPropertyOps.clear()
|
|
152
|
+
android.util.Log.i("AmplyReactNative", "Draining ${ops.size} buffered property operations")
|
|
153
|
+
ops.forEach { op ->
|
|
154
|
+
runCatching { op(instance) }
|
|
155
|
+
.onFailure { android.util.Log.w("AmplyReactNative", "Buffered property operation failed", it) }
|
|
156
|
+
}
|
|
150
157
|
}
|
|
151
158
|
}
|
|
152
159
|
|
|
@@ -362,9 +369,20 @@ class DefaultAmplyClient(
|
|
|
362
369
|
}
|
|
363
370
|
|
|
364
371
|
override fun setUserId(userId: String?) {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
372
|
+
// Buffered like the property calls below. It used to requireInstance(), and this runs from a
|
|
373
|
+
// void TurboModule method, so the IllegalStateException never reached JS: calling setUserId
|
|
374
|
+
// before a successful initialize (for example after initialize rejected over a missing key)
|
|
375
|
+
// crashed the host app.
|
|
376
|
+
synchronized(propertyLock) {
|
|
377
|
+
val instance = amplyInstance
|
|
378
|
+
if (instance != null) {
|
|
379
|
+
instance.setUserId(userId)
|
|
380
|
+
android.util.Log.i("AmplyReactNative", "User ID set to: ${userId ?: "<null>"}")
|
|
381
|
+
} else {
|
|
382
|
+
android.util.Log.i("AmplyReactNative", "Buffering setUserId until init")
|
|
383
|
+
pendingPropertyOps.add { it.setUserId(userId) }
|
|
384
|
+
}
|
|
385
|
+
}
|
|
368
386
|
}
|
|
369
387
|
|
|
370
388
|
override fun setCustomProperty(key: String, value: Any) {
|
|
@@ -170,7 +170,7 @@ describe('gate registration lifecycle', () => {
|
|
|
170
170
|
// Native refuses while uninitialised; JS must not record that as done.
|
|
171
171
|
expect(mockNativeModule.registerGate).not.toHaveBeenCalled();
|
|
172
172
|
mockNativeModule.isInitialized.mockReturnValue(true);
|
|
173
|
-
await Amply.initialize({
|
|
173
|
+
await Amply.initialize({ appId: 'a', apiKeyPublic: 'k', apiKeySecret: 's' });
|
|
174
174
|
expect(mockNativeModule.registerGate).toHaveBeenCalledWith('stillframe://ad', 'cancel', 0);
|
|
175
175
|
emitPresentation();
|
|
176
176
|
await flushMicrotasks();
|
|
@@ -181,7 +181,7 @@ describe('gate registration lifecycle', () => {
|
|
|
181
181
|
await Amply.addDeepLinkListener(jest.fn());
|
|
182
182
|
expect(mockNativeModule.registerDeepLinkListener).not.toHaveBeenCalled();
|
|
183
183
|
mockNativeModule.isInitialized.mockReturnValue(true);
|
|
184
|
-
await Amply.initialize({
|
|
184
|
+
await Amply.initialize({ appId: 'a', apiKeyPublic: 'k', apiKeySecret: 's' });
|
|
185
185
|
expect(mockNativeModule.registerDeepLinkListener).toHaveBeenCalledTimes(1);
|
|
186
186
|
});
|
|
187
187
|
/**
|
|
@@ -197,7 +197,7 @@ describe('gate registration lifecycle', () => {
|
|
|
197
197
|
await Amply.registerGate('stillframe://ad', first);
|
|
198
198
|
await Amply.registerGate('stillframe://ad', second);
|
|
199
199
|
mockNativeModule.isInitialized.mockReturnValue(true);
|
|
200
|
-
await Amply.initialize({
|
|
200
|
+
await Amply.initialize({ appId: 'a', apiKeyPublic: 'k', apiKeySecret: 's' });
|
|
201
201
|
emitPresentation();
|
|
202
202
|
await flushMicrotasks();
|
|
203
203
|
expect(second).toHaveBeenCalledTimes(1);
|
|
@@ -208,7 +208,7 @@ describe('gate registration lifecycle', () => {
|
|
|
208
208
|
const unsubscribe = await Amply.registerGate('stillframe://ad', jest.fn());
|
|
209
209
|
unsubscribe();
|
|
210
210
|
mockNativeModule.isInitialized.mockReturnValue(true);
|
|
211
|
-
await Amply.initialize({
|
|
211
|
+
await Amply.initialize({ appId: 'a', apiKeyPublic: 'k', apiKeySecret: 's' });
|
|
212
212
|
expect(mockNativeModule.registerGate).not.toHaveBeenCalled();
|
|
213
213
|
});
|
|
214
214
|
});
|
|
@@ -25,13 +25,36 @@ describe('Amply JS API', () => {
|
|
|
25
25
|
__setNativeModule(mockNativeModule);
|
|
26
26
|
});
|
|
27
27
|
it('initializes the native module', async () => {
|
|
28
|
-
await Amply.initialize({ appId: 'id', apiKeyPublic: 'public' });
|
|
28
|
+
await Amply.initialize({ appId: 'id', apiKeyPublic: 'public', apiKeySecret: 'secret' });
|
|
29
29
|
expect(mockNativeModule.initialize).toHaveBeenCalledWith(expect.objectContaining({ appId: 'id', apiKeyPublic: 'public' }));
|
|
30
30
|
});
|
|
31
|
+
// A missing key used to reach the native SDK, whose config builder threw an exception that
|
|
32
|
+
// crossed into Objective-C uncaught and aborted the host app — no JS try/catch could stop it.
|
|
33
|
+
// Bad keys must cost the app its Amply, never its process.
|
|
34
|
+
describe.each([
|
|
35
|
+
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public' }],
|
|
36
|
+
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public', apiKeySecret: '' }],
|
|
37
|
+
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public', apiKeySecret: ' ' }],
|
|
38
|
+
['apiKeySecret', { appId: 'id', apiKeyPublic: 'public', apiKeySecret: null }],
|
|
39
|
+
['apiKeyPublic', { appId: 'id', apiKeyPublic: '', apiKeySecret: 'secret' }],
|
|
40
|
+
['appId', { appId: '', apiKeyPublic: 'public', apiKeySecret: 'secret' }],
|
|
41
|
+
])('when %s is missing (%j)', (field, config) => {
|
|
42
|
+
it('rejects with AMP_INVALID_CONFIG, names the field and never calls the native module', async () => {
|
|
43
|
+
const error = jest.spyOn(console, 'error').mockImplementation(() => { });
|
|
44
|
+
await expect(Amply.initialize(config)).rejects.toMatchObject({
|
|
45
|
+
code: 'AMP_INVALID_CONFIG',
|
|
46
|
+
message: expect.stringContaining(field),
|
|
47
|
+
});
|
|
48
|
+
expect(mockNativeModule.initialize).not.toHaveBeenCalled();
|
|
49
|
+
expect(error).toHaveBeenCalledWith(expect.stringContaining(field));
|
|
50
|
+
error.mockRestore();
|
|
51
|
+
});
|
|
52
|
+
});
|
|
31
53
|
it('passes the base-URL overrides through to the native layer', async () => {
|
|
32
54
|
await Amply.initialize({
|
|
33
55
|
appId: 'id',
|
|
34
56
|
apiKeyPublic: 'public',
|
|
57
|
+
apiKeySecret: 'secret',
|
|
35
58
|
configBaseUrl: 'https://config-staging.example.com',
|
|
36
59
|
backendBaseUrl: 'https://api-staging.example.com',
|
|
37
60
|
});
|
|
@@ -47,6 +70,7 @@ describe('Amply JS API', () => {
|
|
|
47
70
|
await Amply.initialize({
|
|
48
71
|
appId: 'id',
|
|
49
72
|
apiKeyPublic: 'public',
|
|
73
|
+
apiKeySecret: 'secret',
|
|
50
74
|
endpoint: 'https://api-staging.example.com',
|
|
51
75
|
});
|
|
52
76
|
expect(mockNativeModule.initialize).toHaveBeenCalledWith(expect.objectContaining({ endpoint: 'https://api-staging.example.com' }));
|
package/dist/src/index.d.ts
CHANGED
|
@@ -1,7 +1,21 @@
|
|
|
1
1
|
export { useAmplySystemEvents } from './hooks/useAmplySystemEvents';
|
|
2
2
|
export { formatSystemEventLabel } from './systemEventUtils';
|
|
3
3
|
export type { FormatOptions } from './systemEventUtils';
|
|
4
|
-
import type { CampaignResult, GateDecision, AmplyInitializationConfig, DataSetSnapshot, DataSetType, DeepLinkEvent, EventRecord, LogLevel, CampaignPresentEvent, TrackEventPayload } from './nativeSpecs/NativeAmplyModule';
|
|
4
|
+
import type { CampaignResult, GateDecision, AmplyInitializationConfig as NativeInitializationConfig, DataSetSnapshot, DataSetType, DeepLinkEvent, EventRecord, LogLevel, CampaignPresentEvent, TrackEventPayload } from './nativeSpecs/NativeAmplyModule';
|
|
5
|
+
/**
|
|
6
|
+
* The keys from your application's page in Amply. All three are required: the SDK signs every
|
|
7
|
+
* request with `apiKeySecret` on the device, so the secret ships inside the app next to the
|
|
8
|
+
* public key. The codegen spec keeps the field optional only so the generated native structs
|
|
9
|
+
* stay unchanged; this is the contract callers see.
|
|
10
|
+
*/
|
|
11
|
+
export type AmplyInitializationConfig = Omit<NativeInitializationConfig, 'apiKeySecret'> & {
|
|
12
|
+
apiKeySecret: string;
|
|
13
|
+
};
|
|
14
|
+
/** Rejection raised by {@link initialize} for a config the SDK cannot start with. */
|
|
15
|
+
export declare class AmplyConfigError extends Error {
|
|
16
|
+
readonly code = "AMP_INVALID_CONFIG";
|
|
17
|
+
constructor(message: string);
|
|
18
|
+
}
|
|
5
19
|
export declare function initialize(config: AmplyInitializationConfig): Promise<void>;
|
|
6
20
|
/**
|
|
7
21
|
* Set the user ID for analytics. Pass null to clear.
|
|
@@ -151,7 +165,7 @@ export declare function removeCustomProperty(key: string): void;
|
|
|
151
165
|
*/
|
|
152
166
|
export declare function clearCustomProperties(): void;
|
|
153
167
|
export declare function removeAllListeners(): void;
|
|
154
|
-
export type {
|
|
168
|
+
export type { DataSetSnapshot, DataSetType, DeepLinkEvent, EventRecord, LogLevel, CampaignPresentEvent, TrackEventPayload, };
|
|
155
169
|
export declare function addSystemEventsListener(listener: (event: EventRecord) => void): Promise<() => void>;
|
|
156
170
|
export declare const systemEvents: {
|
|
157
171
|
addListener: typeof addSystemEventsListener;
|
package/dist/src/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,oBAAoB,EAAC,MAAM,8BAA8B,CAAC;AAClE,OAAO,EAAC,sBAAsB,EAAC,MAAM,oBAAoB,CAAC;AAC1D,YAAY,EAAC,aAAa,EAAC,MAAM,oBAAoB,CAAC;AACtD,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,yBAAyB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/src/index.js
CHANGED
|
@@ -2,6 +2,22 @@ import getNativeModule from './nativeModule';
|
|
|
2
2
|
import { addSystemEventListenerRaw, addSystemEventListener as addSystemEventListenerInternal } from './systemEvents';
|
|
3
3
|
export { useAmplySystemEvents } from './hooks/useAmplySystemEvents';
|
|
4
4
|
export { formatSystemEventLabel } from './systemEventUtils';
|
|
5
|
+
const REQUIRED_KEYS = ['appId', 'apiKeyPublic', 'apiKeySecret'];
|
|
6
|
+
/** Rejection raised by {@link initialize} for a config the SDK cannot start with. */
|
|
7
|
+
export class AmplyConfigError extends Error {
|
|
8
|
+
constructor(message) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.code = 'AMP_INVALID_CONFIG';
|
|
11
|
+
this.name = 'AmplyConfigError';
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
/** The first required key that is missing or blank, if any. */
|
|
15
|
+
function missingKey(config) {
|
|
16
|
+
return REQUIRED_KEYS.find((key) => {
|
|
17
|
+
const value = config === null || config === void 0 ? void 0 : config[key];
|
|
18
|
+
return typeof value !== 'string' || value.trim().length === 0;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
5
21
|
let deepLinkRegistered = false;
|
|
6
22
|
let debugLogListenerRegistered = false;
|
|
7
23
|
const deepLinkSubscriptions = new Set();
|
|
@@ -157,6 +173,15 @@ function trackDeepLinkSubscription(subscription) {
|
|
|
157
173
|
return unsubscribe;
|
|
158
174
|
}
|
|
159
175
|
export async function initialize(config) {
|
|
176
|
+
// Checked here, before the native module sees anything: a missing key used to reach the
|
|
177
|
+
// native config builder, which threw across the Objective-C boundary and aborted the host
|
|
178
|
+
// app. Bad keys cost the app its Amply — never its process. The SDK stays uninitialized.
|
|
179
|
+
const missing = missingKey(config);
|
|
180
|
+
if (missing) {
|
|
181
|
+
const message = `[Amply] '${missing}' is required — Amply is not initialized. Copy it from your application's page in Amply.`;
|
|
182
|
+
console.error(message);
|
|
183
|
+
throw new AmplyConfigError(message);
|
|
184
|
+
}
|
|
160
185
|
// Set up debug log listener if debug mode is enabled
|
|
161
186
|
if (config.debug || config.logLevel) {
|
|
162
187
|
ensureDebugLogListener();
|