Skip to content

Commit 3253a32

Browse files
committed
refactor remoteconfig into an integration
1 parent f5f600d commit 3253a32

File tree

9 files changed

+243
-186
lines changed

9 files changed

+243
-186
lines changed

packages/browser/src/client.ts

Lines changed: 0 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import type {
99
EventHint,
1010
Options,
1111
ParameterizedString,
12-
RemoteConfigStorage,
1312
SeverityLevel,
1413
UserFeedback,
1514
} from '@sentry/types';
@@ -120,38 +119,6 @@ export class BrowserClient extends BaseClient<BrowserClientOptions> {
120119
return super._prepareEvent(event, hint, scope);
121120
}
122121

123-
/**
124-
* @inheritdoc
125-
*/
126-
protected _createRemoteStorage(): RemoteConfigStorage {
127-
function getKey(key: string): string {
128-
return `_sentryRC:${key}`;
129-
}
130-
131-
return {
132-
get(key: string): unknown {
133-
const value = WINDOW.localStorage.getItem(getKey(key));
134-
135-
if (value === null) {
136-
return value;
137-
}
138-
139-
try {
140-
return JSON.parse(value);
141-
} catch {
142-
return null;
143-
}
144-
},
145-
set(key: string, value: any): void {
146-
try {
147-
WINDOW.localStorage.setItem(getKey(key), JSON.stringify(value));
148-
} catch {
149-
DEBUG_BUILD && logger.error('Unable to serialize configuration and save to localStorage');
150-
}
151-
},
152-
};
153-
}
154-
155122
/**
156123
* Sends client reports as an envelope.
157124
*/

packages/browser/src/index.ts

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
export * from './exports';
22

3-
export { reportingObserverIntegration } from './integrations/reportingobserver';
4-
export { httpClientIntegration } from './integrations/httpclient';
53
export { contextLinesIntegration } from './integrations/contextlines';
4+
export { httpClientIntegration } from './integrations/httpclient';
5+
export { remoteConfigIntegration } from './integrations/remoteconfig';
6+
export { reportingObserverIntegration } from './integrations/reportingobserver';
67

78
export {
89
captureConsoleIntegration,
@@ -13,10 +14,7 @@ export {
1314
captureFeedback,
1415
} from '@sentry/core';
1516

16-
export {
17-
replayIntegration,
18-
getReplay,
19-
} from '@sentry-internal/replay';
17+
export { replayIntegration, getReplay } from '@sentry-internal/replay';
2018
export type {
2119
ReplayEventType,
2220
ReplayEventWithTime,
@@ -34,15 +32,9 @@ export { replayCanvasIntegration } from '@sentry-internal/replay-canvas';
3432
import { feedbackAsyncIntegration } from './feedbackAsync';
3533
import { feedbackSyncIntegration } from './feedbackSync';
3634
export { feedbackAsyncIntegration, feedbackSyncIntegration, feedbackSyncIntegration as feedbackIntegration };
37-
export {
38-
getFeedback,
39-
sendFeedback,
40-
} from '@sentry-internal/feedback';
35+
export { getFeedback, sendFeedback } from '@sentry-internal/feedback';
4136

42-
export {
43-
defaultRequestInstrumentationOptions,
44-
instrumentOutgoingRequests,
45-
} from './tracing/request';
37+
export { defaultRequestInstrumentationOptions, instrumentOutgoingRequests } from './tracing/request';
4638
export {
4739
browserTracingIntegration,
4840
startBrowserTracingNavigationSpan,
Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
import { defineIntegration, getClient, remoteConfig } from '@sentry/core';
2+
import type { IntegrationFn, RemoteConfigStorage, RemoteOverrideableConfig } from '@sentry/types';
3+
import { logger } from '@sentry/utils';
4+
import { DEBUG_BUILD } from '../debug-build';
5+
import { WINDOW } from '../helpers';
6+
7+
const INTEGRATION_NAME = 'RemoteConfig';
8+
9+
/**
10+
* Remote Configuration fetches configuration from a remote server.
11+
*/
12+
const _remoteConfigIntegration = (() => {
13+
let _inst: ReturnType<typeof remoteConfig> | undefined;
14+
return {
15+
name: INTEGRATION_NAME,
16+
setupOnce() {
17+
const client = getClient();
18+
if (!client) {
19+
// when can this happen?
20+
return;
21+
}
22+
_inst = remoteConfig({ client, storage: browserStorage() });
23+
},
24+
get api() {
25+
return _inst;
26+
},
27+
applyUpdate() {
28+
if (!_inst) {
29+
return;
30+
}
31+
32+
return _inst.applyUpdate();
33+
},
34+
fetch() {
35+
if (!_inst) {
36+
return;
37+
}
38+
39+
return _inst.fetch();
40+
},
41+
fetchAndApply() {
42+
if (!_inst) {
43+
return;
44+
}
45+
46+
return _inst.fetchAndApply();
47+
},
48+
get<T>(defaultConfig: T): T {
49+
if (!_inst) {
50+
return defaultConfig;
51+
}
52+
53+
return _inst.get(defaultConfig);
54+
},
55+
getInternal(config: RemoteOverrideableConfig): RemoteOverrideableConfig {
56+
if (!_inst) {
57+
return config;
58+
}
59+
60+
return _inst.getInternal(config);
61+
},
62+
getSource() {
63+
if (!_inst) {
64+
return 'DEFAULT';
65+
}
66+
67+
return _inst.getSource();
68+
},
69+
};
70+
}) satisfies IntegrationFn;
71+
72+
export const remoteConfigIntegration = defineIntegration(_remoteConfigIntegration);
73+
74+
function _getStorageKey(key: string): string {
75+
return `_sentryRC:${key}`;
76+
}
77+
78+
function browserStorage(): RemoteConfigStorage {
79+
return {
80+
get(key: string): unknown {
81+
const value = WINDOW.localStorage.getItem(_getStorageKey(key));
82+
83+
if (value === null) {
84+
return value;
85+
}
86+
87+
try {
88+
return JSON.parse(value);
89+
} catch {
90+
return null;
91+
}
92+
},
93+
set(key: string, value: any): void {
94+
try {
95+
WINDOW.localStorage.setItem(_getStorageKey(key), JSON.stringify(value));
96+
} catch {
97+
DEBUG_BUILD && logger.error('Unable to serialize configuration and save to localStorage');
98+
}
99+
},
100+
};
101+
}

packages/browser/src/transports/fetch.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ export function makeFetchTransport(
2121
pendingBodySize += requestSize;
2222
pendingCount++;
2323

24+
const method = options.method || 'POST';
2425
const requestOptions: RequestInit = {
25-
body: request.body,
26-
method: 'POST',
26+
method,
2727
referrerPolicy: 'origin',
2828
headers: options.headers,
2929
// Outgoing requests are usually cancelled when navigating to a different page, causing a "TypeError: Failed to
@@ -41,6 +41,10 @@ export function makeFetchTransport(
4141
...options.fetchOptions,
4242
};
4343

44+
if (method === 'POST') {
45+
requestOptions.body = request.body;
46+
}
47+
4448
if (!nativeFetch) {
4549
clearCachedFetchImplementation();
4650
return rejectedSyncPromise('No fetch implementation available');

packages/core/src/baseclient.ts

Lines changed: 1 addition & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,6 @@ import type {
1717
Integration,
1818
Outcome,
1919
ParameterizedString,
20-
RemoteConfigInterface,
21-
RemoteConfigStorage,
2220
SdkMetadata,
2321
Session,
2422
SessionAggregates,
@@ -50,14 +48,13 @@ import {
5048
uuid4,
5149
} from '@sentry/utils';
5250

53-
import { getEnvelopeEndpointWithUrlEncodedAuth, getRemoteConfigEndpoint } from './api';
51+
import { getEnvelopeEndpointWithUrlEncodedAuth } from './api';
5452
import { getIsolationScope } from './currentScopes';
5553
import { DEBUG_BUILD } from './debug-build';
5654
import { createEventEnvelope, createSessionEnvelope } from './envelope';
5755
import type { IntegrationIndex } from './integration';
5856
import { afterSetupIntegrations } from './integration';
5957
import { setupIntegration, setupIntegrations } from './integration';
60-
import { remoteConfig } from './remoteconfig';
6158
import type { Scope } from './scope';
6259
import { updateSession } from './session';
6360
import { getDynamicSamplingContextFromClient } from './tracing/dynamicSamplingContext';
@@ -120,9 +117,6 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
120117
// eslint-disable-next-line @typescript-eslint/ban-types
121118
private _hooks: Record<string, Function[]>;
122119

123-
/** Optional remote config */
124-
public readonly config?: ReturnType<typeof remoteConfig>;
125-
126120
/**
127121
* Initializes this client instance.
128122
*
@@ -154,31 +148,6 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
154148
...options.transportOptions,
155149
url,
156150
});
157-
158-
// TODO: if blockForRemoteConfig is set, client should be disabled, events
159-
// should be queued before we sample (e.g. in baseclient._captureEvent check
160-
// if enabled, otherwise queue?). baseclient._processEvent is where
161-
// sampleRate is used. then set client as ready after remote config is loaded and flush queue
162-
// TODO: create/pass transport
163-
164-
const storage = this._createRemoteStorage();
165-
// Only initialize remote config if storage is implemented
166-
if (storage) {
167-
const transport = options.transport({
168-
tunnel: options.tunnel,
169-
recordDroppedEvent: this.recordDroppedEvent.bind(this),
170-
...options.transportOptions,
171-
url: getRemoteConfigEndpoint(
172-
this._dsn,
173-
options.tunnel,
174-
options._metadata ? options._metadata.sdk : undefined,
175-
),
176-
});
177-
this.config = remoteConfig({
178-
transport,
179-
storage,
180-
});
181-
}
182151
}
183152
}
184153

@@ -340,34 +309,6 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
340309

341310
/** @inheritdoc */
342311
public init(): void {
343-
if (this.config) {
344-
this.config.fetch();
345-
// const remoteConfigFetchPromise = this.config.fetchAndApply();
346-
// TODO calling _setupIntegrations async will break the world
347-
// const { blockForRemoteConfig } = this._options;
348-
// If `blockForRemoteConfig` is configured and there is no cached config, then
349-
// if (this.config.getSource() === 'DEFAULT' && blockForRemoteConfig && blockForRemoteConfig.timeout > 0) {
350-
// new Promise(resolve => {
351-
// setTimeout(resolve, blockForRemoteConfig.timeout);
352-
// remoteConfigFetchPromise.then(resolve);
353-
// })
354-
// .then(() => this.finishInit())
355-
// .catch(() => {
356-
// // TODO: Error handling
357-
// });
358-
//
359-
// return;
360-
// }
361-
362-
// TODO these keys need to be configurable
363-
const config = this.config.getInternal({
364-
sampleRate: this._options.sampleRate,
365-
tracesSampleRate: this._options.tracesSampleRate,
366-
});
367-
this._options.sampleRate = config.sampleRate;
368-
this._options.tracesSampleRate = config.tracesSampleRate;
369-
}
370-
371312
if (this._isEnabled()) {
372313
this._setupIntegrations();
373314
}
@@ -906,11 +847,6 @@ export abstract class BaseClient<O extends ClientOptions> implements Client<O> {
906847
});
907848
}
908849

909-
/**
910-
* Creates a storage interface to be used for Remote Configuration
911-
*/
912-
protected _createRemoteStorage(): RemoteConfigStorage | void {}
913-
914850
/**
915851
* @inheritDoc
916852
*/

packages/core/src/index.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ export {
4444
export { setAsyncContextStrategy } from './asyncContext';
4545
export { getMainCarrier } from './carrier';
4646
export { makeSession, closeSession, updateSession } from './session';
47+
export { remoteConfig } from './remoteconfig';
4748
export { SessionFlusher } from './sessionflusher';
4849
export { Scope } from './scope';
4950
export { notifyEventProcessors } from './eventProcessors';
@@ -55,11 +56,7 @@ export { createTransport } from './transports/base';
5556
export { makeOfflineTransport } from './transports/offline';
5657
export { makeMultiplexedTransport } from './transports/multiplexed';
5758
export { SDK_VERSION } from './version';
58-
export {
59-
getIntegrationsToSetup,
60-
addIntegration,
61-
defineIntegration,
62-
} from './integration';
59+
export { getIntegrationsToSetup, addIntegration, defineIntegration } from './integration';
6360
export { applyScopeDataToEvent, mergeScopeData } from './utils/applyScopeDataToEvent';
6461
export { prepareEvent } from './utils/prepareEvent';
6562
export { createCheckInEnvelope } from './checkin';

0 commit comments

Comments
 (0)