Skip to content

Commit 47f5ced

Browse files
committed
♻️ share context to access remote configuration metrics
preliminary refactoring, metrics introduced in next commit
1 parent c711cfc commit 47f5ced

File tree

1 file changed

+100
-96
lines changed

1 file changed

+100
-96
lines changed

packages/rum-core/src/domain/configuration/remoteConfiguration.ts

Lines changed: 100 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -64,30 +64,110 @@ export function applyRemoteConfiguration(
6464
}
6565
})
6666
return appliedConfiguration
67-
}
6867

69-
function resolveConfigurationProperty(property: unknown): unknown {
70-
if (Array.isArray(property)) {
71-
return property.map(resolveConfigurationProperty)
72-
}
73-
if (isObject(property)) {
74-
if (isSerializedOption(property)) {
75-
const type = property.rcSerializedType
76-
switch (type) {
77-
case 'string':
78-
return property.value
79-
case 'regex':
80-
return resolveRegex(property.value)
81-
case 'dynamic':
82-
return resolveDynamicOption(property)
83-
default:
84-
display.error(`Unsupported remote configuration: "rcSerializedType": "${type as string}"`)
85-
return
68+
// share context to access metrics
69+
70+
function resolveConfigurationProperty(property: unknown): unknown {
71+
if (Array.isArray(property)) {
72+
return property.map(resolveConfigurationProperty)
73+
}
74+
if (isObject(property)) {
75+
if (isSerializedOption(property)) {
76+
const type = property.rcSerializedType
77+
switch (type) {
78+
case 'string':
79+
return property.value
80+
case 'regex':
81+
return resolveRegex(property.value)
82+
case 'dynamic':
83+
return resolveDynamicOption(property)
84+
default:
85+
display.error(`Unsupported remote configuration: "rcSerializedType": "${type as string}"`)
86+
return
87+
}
8688
}
89+
return mapValues(property, resolveConfigurationProperty)
90+
}
91+
return property
92+
}
93+
94+
function resolveContextProperty(
95+
contextManager: ReturnType<typeof createContextManager>,
96+
contextItems: ContextItem[]
97+
) {
98+
contextItems.forEach(({ key, value }) => {
99+
contextManager.setContextProperty(key, resolveConfigurationProperty(value))
100+
})
101+
}
102+
103+
function resolveDynamicOption(property: DynamicOption) {
104+
const strategy = property.strategy
105+
let resolvedValue: unknown
106+
switch (strategy) {
107+
case 'cookie':
108+
resolvedValue = resolveCookieValue(property)
109+
break
110+
case 'dom':
111+
resolvedValue = resolveDomValue(property)
112+
break
113+
case 'js':
114+
resolvedValue = resolveJsValue(property)
115+
break
116+
default:
117+
display.error(`Unsupported remote configuration: "strategy": "${strategy as string}"`)
118+
return
119+
}
120+
const extractor = property.extractor
121+
if (extractor !== undefined && typeof resolvedValue === 'string') {
122+
return extractValue(extractor, resolvedValue)
123+
}
124+
return resolvedValue
125+
}
126+
127+
function resolveCookieValue({ name }: { name: string }) {
128+
return getCookie(name)
129+
}
130+
131+
function resolveDomValue({ selector, attribute }: { selector: string; attribute?: string }) {
132+
let element: Element | null
133+
try {
134+
element = document.querySelector(selector)
135+
} catch {
136+
element = null
137+
display.error(`Invalid selector in the remote configuration: '${selector}'`)
87138
}
88-
return mapValues(property, resolveConfigurationProperty)
139+
if (element === null || isForbidden(element, attribute)) {
140+
return
141+
}
142+
const domValue = attribute !== undefined ? element.getAttribute(attribute) : element.textContent
143+
return domValue ?? undefined
144+
}
145+
146+
function isForbidden(element: Element, attribute: string | undefined) {
147+
return element.getAttribute('type') === 'password' && attribute === 'value'
148+
}
149+
150+
function resolveJsValue({ path }: { path: string }): unknown {
151+
let current = window as unknown as { [key: string]: unknown }
152+
153+
const pathParts = parseJsonPath(path)
154+
if (pathParts.length === 0) {
155+
display.error(`Invalid JSON path in the remote configuration: '${path}'`)
156+
return
157+
}
158+
for (const pathPart of pathParts) {
159+
if (!(pathPart in current)) {
160+
return
161+
}
162+
try {
163+
current = current[pathPart] as { [key: string]: unknown }
164+
} catch (e) {
165+
display.error(`Error accessing: '${path}'`, e)
166+
return
167+
}
168+
}
169+
return current
89170
}
90-
return property
91171
}
92172

93173
function isObject(property: unknown): property is { [key: string]: unknown } {
@@ -106,82 +186,6 @@ function resolveRegex(pattern: string): RegExp | undefined {
106186
}
107187
}
108188

109-
function resolveContextProperty(contextManager: ReturnType<typeof createContextManager>, contextItems: ContextItem[]) {
110-
contextItems.forEach(({ key, value }) => {
111-
contextManager.setContextProperty(key, resolveConfigurationProperty(value))
112-
})
113-
}
114-
115-
function resolveDynamicOption(property: DynamicOption) {
116-
const strategy = property.strategy
117-
let resolvedValue: unknown
118-
switch (strategy) {
119-
case 'cookie':
120-
resolvedValue = resolveCookieValue(property)
121-
break
122-
case 'dom':
123-
resolvedValue = resolveDomValue(property)
124-
break
125-
case 'js':
126-
resolvedValue = resolveJsValue(property)
127-
break
128-
default:
129-
display.error(`Unsupported remote configuration: "strategy": "${strategy as string}"`)
130-
return
131-
}
132-
const extractor = property.extractor
133-
if (extractor !== undefined && typeof resolvedValue === 'string') {
134-
return extractValue(extractor, resolvedValue)
135-
}
136-
return resolvedValue
137-
}
138-
139-
function resolveCookieValue({ name }: { name: string }) {
140-
return getCookie(name)
141-
}
142-
143-
function resolveDomValue({ selector, attribute }: { selector: string; attribute?: string }) {
144-
let element: Element | null
145-
try {
146-
element = document.querySelector(selector)
147-
} catch {
148-
element = null
149-
display.error(`Invalid selector in the remote configuration: '${selector}'`)
150-
}
151-
if (element === null || isForbidden(element, attribute)) {
152-
return
153-
}
154-
const domValue = attribute !== undefined ? element.getAttribute(attribute) : element.textContent
155-
return domValue ?? undefined
156-
}
157-
158-
function isForbidden(element: Element, attribute: string | undefined) {
159-
return element.getAttribute('type') === 'password' && attribute === 'value'
160-
}
161-
162-
function resolveJsValue({ path }: { path: string }): unknown {
163-
let current = window as unknown as { [key: string]: unknown }
164-
165-
const pathParts = parseJsonPath(path)
166-
if (pathParts.length === 0) {
167-
display.error(`Invalid JSON path in the remote configuration: '${path}'`)
168-
return
169-
}
170-
for (const pathPart of pathParts) {
171-
if (!(pathPart in current)) {
172-
return
173-
}
174-
try {
175-
current = current[pathPart] as { [key: string]: unknown }
176-
} catch (e) {
177-
display.error(`Error accessing: '${path}'`, e)
178-
return
179-
}
180-
}
181-
182-
return current
183-
}
184-
185189
function extractValue(extractor: SerializedRegex, candidate: string) {
186190
const resolvedExtractor = resolveRegex(extractor.value)
187191
if (resolvedExtractor === undefined) {

0 commit comments

Comments
 (0)