Skip to content

Commit 02c4c03

Browse files
fix(evlog): skip unnecessary Nitro adapter probes (#298)
1 parent ab912ba commit 02c4c03

3 files changed

Lines changed: 173 additions & 1 deletion

File tree

.changeset/quiet-adapter-probe.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"evlog": patch
3+
---
4+
5+
Avoid unnecessary Nitro runtime-config probes when drain adapter overrides or env vars already satisfy the env-backed config fields.

packages/evlog/src/adapters/_config.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export async function resolveAdapterConfig<T>(
2121
fields: ConfigField<T>[],
2222
overrides?: Partial<T>,
2323
): Promise<Partial<T>> {
24-
const runtimeConfig = await getRuntimeConfig()
24+
const runtimeConfig = shouldProbeRuntimeConfig(fields, overrides)
25+
? await getRuntimeConfig()
26+
: undefined
2527
const evlogNs = runtimeConfig?.evlog?.[namespace]
2628
const rootNs = runtimeConfig?.[namespace]
2729

@@ -38,6 +40,20 @@ export async function resolveAdapterConfig<T>(
3840
return config as Partial<T>
3941
}
4042

43+
function shouldProbeRuntimeConfig<T>(
44+
fields: ConfigField<T>[],
45+
overrides?: Partial<T>,
46+
): boolean {
47+
// Optional tuning fields (e.g. timeout/retries) should not trigger Nitro
48+
// virtual-module imports when env/overrides already resolve the env-backed
49+
// adapter fields in non-Nitro runtimes.
50+
return fields.some(({ key, env }) => {
51+
if (overrides?.[key] !== undefined) return false
52+
if (!env) return false
53+
return resolveEnv(env) === undefined
54+
})
55+
}
56+
4157
function resolveEnv(envKeys?: string[]): string | undefined {
4258
if (!envKeys) return undefined
4359
for (const key of envKeys) {
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
import { afterEach, describe, expect, it, vi } from 'vitest'
2+
3+
vi.mock('../../src/shared/nitroConfigBridge', () => ({
4+
getNitroRuntimeConfigRecord: vi.fn(),
5+
}))
6+
7+
// eslint-disable-next-line import/first -- Must import after vi.mock
8+
import { resolveAdapterConfig } from '../../src/adapters/_config'
9+
// eslint-disable-next-line import/first -- Must import after vi.mock
10+
import { getNitroRuntimeConfigRecord } from '../../src/shared/nitroConfigBridge'
11+
12+
interface TestAdapterConfig {
13+
apiKey?: string
14+
endpoint?: string
15+
site?: string
16+
timeout?: number
17+
}
18+
19+
describe('resolveAdapterConfig', () => {
20+
afterEach(() => {
21+
vi.clearAllMocks()
22+
vi.unstubAllEnvs()
23+
})
24+
25+
it('skips the Nitro runtime probe when overrides and env already satisfy env-backed fields', async () => {
26+
const runtimeProbe = vi.mocked(getNitroRuntimeConfigRecord)
27+
runtimeProbe.mockResolvedValue({
28+
evlog: {
29+
test: {
30+
timeout: 30_000,
31+
},
32+
},
33+
})
34+
35+
const config = await resolveAdapterConfig<TestAdapterConfig>(
36+
'test',
37+
[
38+
{ key: 'apiKey', env: ['TEST_API_KEY'] },
39+
{ key: 'endpoint', env: ['TEST_ENDPOINT'] },
40+
{ key: 'timeout' },
41+
],
42+
{
43+
apiKey: 'override-key',
44+
endpoint: 'https://override.example.com',
45+
},
46+
)
47+
48+
expect(runtimeProbe).not.toHaveBeenCalled()
49+
expect(config).toEqual({
50+
apiKey: 'override-key',
51+
endpoint: 'https://override.example.com',
52+
timeout: undefined,
53+
})
54+
})
55+
56+
it('skips the Nitro runtime probe when env alone satisfies the remaining env-backed fields', async () => {
57+
vi.stubEnv('TEST_API_KEY', 'env-key')
58+
vi.stubEnv('TEST_ENDPOINT', 'https://env.example.com')
59+
60+
const runtimeProbe = vi.mocked(getNitroRuntimeConfigRecord)
61+
62+
const config = await resolveAdapterConfig<TestAdapterConfig>(
63+
'test',
64+
[
65+
{ key: 'apiKey', env: ['TEST_API_KEY'] },
66+
{ key: 'endpoint', env: ['TEST_ENDPOINT'] },
67+
{ key: 'timeout' },
68+
],
69+
)
70+
71+
expect(runtimeProbe).not.toHaveBeenCalled()
72+
expect(config).toEqual({
73+
apiKey: 'env-key',
74+
endpoint: 'https://env.example.com',
75+
timeout: undefined,
76+
})
77+
})
78+
79+
it('probes Nitro runtime config when an env-backed field is still unresolved', async () => {
80+
const runtimeProbe = vi.mocked(getNitroRuntimeConfigRecord)
81+
runtimeProbe.mockResolvedValue({
82+
evlog: {
83+
test: {
84+
apiKey: 'runtime-key',
85+
endpoint: 'https://runtime.example.com',
86+
},
87+
},
88+
test: {
89+
endpoint: 'https://root.example.com',
90+
timeout: 15_000,
91+
},
92+
})
93+
94+
const config = await resolveAdapterConfig<TestAdapterConfig>(
95+
'test',
96+
[
97+
{ key: 'apiKey', env: ['TEST_API_KEY'] },
98+
{ key: 'endpoint', env: ['TEST_ENDPOINT'] },
99+
{ key: 'timeout' },
100+
],
101+
)
102+
103+
expect(runtimeProbe).toHaveBeenCalledTimes(1)
104+
expect(config).toEqual({
105+
apiKey: 'runtime-key',
106+
endpoint: 'https://runtime.example.com',
107+
timeout: 15_000,
108+
})
109+
})
110+
111+
it('preserves override then runtime then env precedence when the probe is required', async () => {
112+
vi.stubEnv('TEST_API_KEY', 'env-key')
113+
vi.stubEnv('TEST_ENDPOINT', 'https://env.example.com')
114+
115+
const runtimeProbe = vi.mocked(getNitroRuntimeConfigRecord)
116+
runtimeProbe.mockResolvedValue({
117+
evlog: {
118+
test: {
119+
apiKey: 'runtime-key',
120+
endpoint: 'https://runtime.example.com',
121+
site: 'runtime-site',
122+
},
123+
},
124+
test: {
125+
endpoint: 'https://root.example.com',
126+
timeout: 5_000,
127+
},
128+
})
129+
130+
const config = await resolveAdapterConfig<TestAdapterConfig>(
131+
'test',
132+
[
133+
{ key: 'apiKey', env: ['TEST_API_KEY'] },
134+
{ key: 'endpoint', env: ['TEST_ENDPOINT'] },
135+
{ key: 'site', env: ['TEST_SITE'] },
136+
{ key: 'timeout' },
137+
],
138+
{
139+
apiKey: 'override-key',
140+
},
141+
)
142+
143+
expect(runtimeProbe).toHaveBeenCalledTimes(1)
144+
expect(config).toEqual({
145+
apiKey: 'override-key',
146+
endpoint: 'https://runtime.example.com',
147+
site: 'runtime-site',
148+
timeout: 5_000,
149+
})
150+
})
151+
})

0 commit comments

Comments
 (0)