Skip to content

Commit 22b89a9

Browse files
committed
WIP
1 parent bba88a1 commit 22b89a9

File tree

16 files changed

+135
-214
lines changed

16 files changed

+135
-214
lines changed

packages/sdk/browser/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
],
2828
"scripts": {
2929
"clean": "rimraf dist",
30-
"build": "rollup -c rollup.config.js",
30+
"build": "tsc --noEmit && rollup -c rollup.config.js",
3131
"lint": "eslint . --ext .ts,.tsx",
3232
"prettier": "prettier --write '**/*.@(js|ts|tsx|json|css)' --ignore-path ../../../.prettierignore",
3333
"test": "NODE_OPTIONS=--experimental-vm-modules npx jest --runInBand",

packages/sdk/browser/src/BrowserClient.ts

Lines changed: 5 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,13 @@ import {
1313
LDHeaders,
1414
Platform,
1515
} from '@launchdarkly/js-client-sdk-common';
16+
import { LDIdentifyOptions } from '@launchdarkly/js-client-sdk-common/dist/api/LDIdentifyOptions';
1617

1718
import BrowserDataManager from './BrowserDataManager';
1819
import GoalManager from './goals/GoalManager';
1920
import { Goal, isClick } from './goals/Goals';
2021
import validateOptions, { BrowserOptions, filterToBaseOptions } from './options';
2122
import BrowserPlatform from './platform/BrowserPlatform';
22-
import { LDIdentifyOptions } from '@launchdarkly/js-client-sdk-common/dist/api/LDIdentifyOptions';
2323

2424
/**
2525
* We are not supporting dynamically setting the connection mode on the LDClient.
@@ -53,7 +53,6 @@ export class BrowserClient extends LDClientImpl {
5353
const baseUrl = options.baseUri ?? 'https://clientsdk.launchdarkly.com';
5454

5555
const platform = overridePlatform ?? new BrowserPlatform(logger);
56-
<<<<<<< HEAD
5756
const validatedBrowserOptions = validateOptions(options, logger);
5857
const { eventUrlTransformer } = validatedBrowserOptions;
5958
super(
@@ -111,26 +110,8 @@ export class BrowserClient extends LDClientImpl {
111110
),
112111
},
113112
);
114-
=======
115-
const ValidatedBrowserOptions = validateOptions(options, logger);
116-
const { eventUrlTransformer } = ValidatedBrowserOptions;
117-
super(clientSideId, autoEnvAttributes, platform, filterToBaseOptions(options), {
118-
analyticsEventPath: `/events/bulk/${clientSideId}`,
119-
diagnosticEventPath: `/events/diagnostic/${clientSideId}`,
120-
includeAuthorizationHeader: false,
121-
highTimeoutThreshold: 5,
122-
userAgentHeaderName: 'x-launchdarkly-user-agent',
123-
trackEventModifier: (event: internal.InputCustomEvent) =>
124-
new internal.InputCustomEvent(
125-
event.context,
126-
event.key,
127-
event.data,
128-
event.metricValue,
129-
event.samplingRatio,
130-
eventUrlTransformer(window.location.href),
131-
),
132-
});
133-
>>>>>>> origin/rlamb/fix-browser-contract-test-build
113+
114+
this.setEventSendingEnabled(true, false);
134115

135116
if (validatedBrowserOptions.fetchGoals) {
136117
this.goalManager = new GoalManager(
@@ -178,8 +159,8 @@ export class BrowserClient extends LDClientImpl {
178159
}
179160
}
180161

181-
override async identify(context: LDContext): Promise<void> {
182-
await super.identify(context);
162+
override async identify(context: LDContext, identifyOptions: LDIdentifyOptions): Promise<void> {
163+
await super.identify(context, identifyOptions);
183164
this.goalManager?.startTracking();
184165
}
185166

@@ -192,24 +173,5 @@ export class BrowserClient extends LDClientImpl {
192173
}
193174
}
194175

195-
<<<<<<< HEAD
196176
// TODO: Setup event listeners.
197-
=======
198-
override getPollingPaths(): DataSourcePaths {
199-
const parentThis = this;
200-
return {
201-
pathGet(encoding: Encoding, _plainContextString: string): string {
202-
return `/sdk/evalx/${parentThis.clientSideId}/contexts/${base64UrlEncode(_plainContextString, encoding)}`;
203-
},
204-
pathReport(_encoding: Encoding, _plainContextString: string): string {
205-
return `/sdk/evalx/${parentThis.clientSideId}/context`;
206-
},
207-
};
208-
}
209-
210-
override async identify(context: LDContext, identifyOptions?: LDIdentifyOptions): Promise<void> {
211-
await super.identify(context, identifyOptions);
212-
this.goalManager?.startTracking();
213-
}
214-
>>>>>>> origin/rlamb/fix-browser-contract-test-build
215177
}

packages/sdk/browser/src/BrowserDataManager.ts

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,14 +74,24 @@ export default class BrowserDataManager extends DefaultDataManager {
7474
}
7575

7676
startDataSource() {
77-
// Should always be streaming for browser SDKs for now.
78-
if (this.connectionMode !== 'streaming') {
79-
this.setConnectionMode('streaming');
80-
} else if (this.context && !this.updateProcessor) {
77+
if (this.context && !this.updateProcessor) {
8178
this.setupConnection(this.context);
8279
}
8380
}
8481

82+
private setupConnection(
83+
context: Context,
84+
identifyResolve?: () => void,
85+
identifyReject?: (err: Error) => void,
86+
) {
87+
const rawContext = Context.toLDContext(context)!;
88+
89+
this.updateProcessor?.close();
90+
this.createStreamingProcessor(rawContext, context, identifyResolve, identifyReject);
91+
92+
this.updateProcessor!.start();
93+
}
94+
8595
private getRequestor(plainContextString: string): Requestor {
8696
const paths = this.getPollingPaths();
8797
const path = this.config.useReport

packages/sdk/react-native/src/MobileDataManager.ts

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
1-
import { Context, DefaultDataManager, LDIdentifyOptions } from '@launchdarkly/js-client-sdk-common';
1+
import {
2+
ConnectionMode,
3+
Context,
4+
DefaultDataManager,
5+
LDIdentifyOptions,
6+
} from '@launchdarkly/js-client-sdk-common';
27

38
export default class MobileDataManager extends DefaultDataManager {
9+
// Not implemented yet.
10+
protected networkAvailable: boolean = true;
11+
protected connectionMode: ConnectionMode = 'streaming';
12+
413
override async identify(
514
identifyResolve: () => void,
615
identifyReject: (err: Error) => void,
@@ -37,4 +46,62 @@ export default class MobileDataManager extends DefaultDataManager {
3746
this.setupConnection(context, identifyResolve, identifyReject);
3847
}
3948
}
49+
50+
private setupConnection(
51+
context: Context,
52+
identifyResolve?: () => void,
53+
identifyReject?: (err: Error) => void,
54+
) {
55+
const rawContext = Context.toLDContext(context)!;
56+
57+
this.updateProcessor?.close();
58+
switch (this.connectionMode) {
59+
case 'streaming':
60+
this.createStreamingProcessor(rawContext, context, identifyResolve, identifyReject);
61+
break;
62+
case 'polling':
63+
this.createPollingProcessor(rawContext, context, identifyResolve, identifyReject);
64+
break;
65+
default:
66+
break;
67+
}
68+
this.updateProcessor!.start();
69+
}
70+
71+
setNetworkAvailability(available: boolean): void {
72+
this.networkAvailable = available;
73+
}
74+
75+
async setConnectionMode(mode: ConnectionMode): Promise<void> {
76+
if (this.connectionMode === mode) {
77+
this.logger.debug(`setConnectionMode ignored. Mode is already '${mode}'.`);
78+
return;
79+
}
80+
81+
this.connectionMode = mode;
82+
this.logger.debug(`setConnectionMode ${mode}.`);
83+
84+
switch (mode) {
85+
case 'offline':
86+
this.updateProcessor?.close();
87+
break;
88+
case 'polling':
89+
case 'streaming':
90+
if (this.context) {
91+
// identify will start the update processor
92+
this.setupConnection(this.context);
93+
}
94+
95+
break;
96+
default:
97+
this.logger.warn(
98+
`Unknown ConnectionMode: ${mode}. Only 'offline', 'streaming', and 'polling' are supported.`,
99+
);
100+
break;
101+
}
102+
}
103+
104+
getConnectionMode(): ConnectionMode {
105+
return this.connectionMode;
106+
}
40107
}

packages/sdk/react-native/src/RNOptions.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { LDOptions } from '@launchdarkly/js-client-sdk-common';
1+
import { ConnectionMode, LDOptions } from '@launchdarkly/js-client-sdk-common';
22

33
/**
44
* Interface for providing custom storage implementations for react Native.
@@ -95,6 +95,16 @@ export interface RNSpecificOptions {
9595
* Defaults to @react-native-async-storage/async-storage.
9696
*/
9797
readonly storage?: RNStorage;
98+
99+
/**
100+
* Sets the mode to use for connections when the SDK is initialized.
101+
*
102+
* @remarks
103+
* Possible values are offline or streaming. See {@link ConnectionMode} for more information.
104+
*
105+
* @defaultValue streaming.
106+
*/
107+
initialConnectionMode?: ConnectionMode;
98108
}
99109

100110
export default interface RNOptions extends LDOptions, RNSpecificOptions {}

packages/sdk/react-native/src/ReactNativeLDClient.ts

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,17 +104,18 @@ export default class ReactNativeLDClient extends LDClientImpl {
104104
internalOptions,
105105
);
106106

107+
const dataManager = this.dataManager as MobileDataManager;
107108
const destination: ConnectionDestination = {
108109
setNetworkAvailability: (available: boolean) => {
109-
this.setNetworkAvailability(available);
110+
dataManager.setNetworkAvailability(available);
110111
},
111112
setEventSendingEnabled: (enabled: boolean, flush: boolean) => {
112113
this.setEventSendingEnabled(enabled, flush);
113114
},
114115
setConnectionMode: async (mode: ConnectionMode) => {
115116
// Pass the connection mode to the base implementation.
116117
// The RN implementation will pass the connection mode through the connection manager.
117-
this.baseSetConnectionMode(mode);
118+
dataManager.setConnectionMode(mode);
118119
},
119120
};
120121

@@ -132,16 +133,24 @@ export default class ReactNativeLDClient extends LDClientImpl {
132133
);
133134
}
134135

135-
private baseSetConnectionMode(mode: ConnectionMode) {
136-
// Jest had problems with calls to super from nested arrow functions, so this method proxies the call.
137-
super.setConnectionMode(mode);
138-
}
139-
140-
override async setConnectionMode(mode: ConnectionMode): Promise<void> {
136+
async setConnectionMode(mode: ConnectionMode): Promise<void> {
141137
// Set the connection mode before setting offline, in case there is any mode transition work
142138
// such as flushing on entering the background.
143139
this.connectionManager.setConnectionMode(mode);
144140
// For now the data source connection and the event processing state are connected.
145141
this.connectionManager.setOffline(mode === 'offline');
146142
}
143+
144+
/**
145+
* Gets the SDK connection mode.
146+
*/
147+
getConnectionMode(): ConnectionMode {
148+
const dataManager = this.dataManager as MobileDataManager;
149+
return dataManager.getConnectionMode();
150+
}
151+
152+
isOffline() {
153+
const dataManager = this.dataManager as MobileDataManager;
154+
return dataManager.getConnectionMode() === 'offline';
155+
}
147156
}

packages/sdk/react-native/src/options.ts

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
ConnectionMode,
23
LDLogger,
34
LDOptions,
45
OptionMessages,
@@ -8,25 +9,37 @@ import {
89

910
import RNOptions, { RNStorage } from './RNOptions';
1011

12+
class ConnectionModeValidator implements TypeValidator {
13+
is(u: unknown): u is ConnectionMode {
14+
return u === 'offline' || u === 'streaming' || u === 'polling';
15+
}
16+
getType(): string {
17+
return 'ConnectionMode (offline | streaming | polling)';
18+
}
19+
}
20+
1121
export interface ValidatedOptions {
1222
runInBackground: boolean;
1323
automaticNetworkHandling: boolean;
1424
automaticBackgroundHandling: boolean;
1525
storage?: RNStorage;
26+
initialConnectionMode: ConnectionMode;
1627
}
1728

18-
const optDefaults = {
29+
const optDefaults: ValidatedOptions = {
1930
runInBackground: false,
2031
automaticNetworkHandling: true,
2132
automaticBackgroundHandling: true,
2233
storage: undefined,
34+
initialConnectionMode: 'streaming',
2335
};
2436

2537
const validators: { [Property in keyof RNOptions]: TypeValidator | undefined } = {
2638
runInBackground: TypeValidators.Boolean,
2739
automaticNetworkHandling: TypeValidators.Boolean,
2840
automaticBackgroundHandling: TypeValidators.Boolean,
2941
storage: TypeValidators.Object,
42+
initialConnectionMode: new ConnectionModeValidator(),
3043
};
3144

3245
export function filterToBaseOptions(opts: RNOptions): LDOptions {
@@ -48,6 +61,7 @@ export default function validateOptions(opts: RNOptions, logger: LDLogger): Vali
4861
const value = opts[key];
4962
if (value !== undefined) {
5063
if (validator.is(value)) {
64+
// @ts-ignore The type inference has some problems here.
5165
output[key as keyof ValidatedOptions] = value as any;
5266
} else {
5367
logger.warn(OptionMessages.wrongOptionType(key, validator.getType(), typeof value));

packages/shared/common/src/internal/events/EventProcessor.ts

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -130,7 +130,6 @@ export default class EventProcessor implements LDEventProcessor {
130130
baseHeaders: LDHeaders,
131131
private readonly contextDeduplicator?: LDContextDeduplicator,
132132
private readonly diagnosticsManager?: DiagnosticsManager,
133-
start: boolean = true,
134133
) {
135134
this.capacity = config.eventsCapacity;
136135
this.logger = clientContext.basicConfiguration.logger;
@@ -140,10 +139,6 @@ export default class EventProcessor implements LDEventProcessor {
140139
config.allAttributesPrivate,
141140
config.privateAttributes.map((ref) => new AttributeReference(ref)),
142141
);
143-
144-
if (start) {
145-
this.start();
146-
}
147142
}
148143

149144
start() {

0 commit comments

Comments
 (0)