Skip to content

Commit 21ce0e7

Browse files
fix: make X-Glean options survive Speakeasy SDK regeneration
The X-Glean feature added in PR #95 placed custom properties directly in src/lib/config.ts, which is regenerated by Speakeasy. This caused CI failures when the Generate workflow ran, as the custom properties were overwritten. This fix: - Creates a separate XGleanOptions interface in src/hooks/x-glean-options.ts (hooks directory is not regenerated after initial creation) - Updates the hook to cast options to the new interface - Updates tests to use intersection types for type safety - Removes the custom properties from config.ts (they would be removed during regeneration anyway) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
1 parent d1f16b4 commit 21ce0e7

4 files changed

Lines changed: 44 additions & 16 deletions

File tree

src/__tests__/x-glean.test.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,19 @@ import { afterEach, beforeEach, describe, expect, it } from "vitest";
22
import { XGlean } from "../hooks/x-glean.js";
33
import { BeforeRequestContext } from "../hooks/types.js";
44
import { SDKOptions } from "../lib/config.js";
5+
import { XGleanOptions } from "../hooks/x-glean-options.js";
56

67
function createMockRequest(): Request {
78
return new Request("https://example.com/api/test");
89
}
910

10-
function createMockContext(options: SDKOptions = {}): BeforeRequestContext {
11+
/**
12+
* Creates a mock BeforeRequestContext for testing.
13+
* Uses intersection type to support both base SDKOptions and X-Glean custom options.
14+
*/
15+
function createMockContext(
16+
options: SDKOptions & XGleanOptions = {},
17+
): BeforeRequestContext {
1118
return {
1219
baseURL: "https://example.com",
1320
operationID: "test-operation",

src/hooks/x-glean-options.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
/**
2+
* X-Glean custom options for configuring deprecation and experimental headers.
3+
*
4+
* These properties allow configuring X-Glean headers through the SDK constructor.
5+
* Since SDKOptions in lib/config.ts is generated by Speakeasy and gets overwritten
6+
* during regeneration, we define these as a separate type that can be used with
7+
* intersection types.
8+
*/
9+
10+
/**
11+
* Custom SDK options for X-Glean header configuration.
12+
* Use these options when constructing the SDK client to configure
13+
* experimental features and deprecation testing.
14+
*/
15+
export interface XGleanOptions {
16+
/**
17+
* Exclude API endpoints that will be deprecated after this date.
18+
* Use this to test your integration against upcoming deprecations.
19+
* Format: YYYY-MM-DD (e.g., '2026-10-15')
20+
*
21+
* More information: https://developers.glean.com/deprecations/overview
22+
*/
23+
excludeDeprecatedAfter?: string | undefined;
24+
/**
25+
* When true, enables experimental API features that are not yet generally available.
26+
* Use this to preview and test new functionality.
27+
*/
28+
includeExperimental?: boolean | undefined;
29+
}

src/hooks/x-glean.ts

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { BeforeRequestContext, BeforeRequestHook } from "./types.js";
2+
import { XGleanOptions } from "./x-glean-options.js";
23

34
/**
45
* Get the first non-empty value from the provided arguments.
@@ -14,14 +15,18 @@ function getFirstValue(
1415

1516
export class XGlean implements BeforeRequestHook {
1617
beforeRequest(hookCtx: BeforeRequestContext, request: Request): Request {
18+
// Cast options to include X-Glean custom properties
19+
// These properties may be passed by users but aren't in the generated SDKOptions type
20+
const options = hookCtx.options as XGleanOptions;
21+
1722
const deprecatedValue = getFirstValue(
1823
process.env["X_GLEAN_EXCLUDE_DEPRECATED_AFTER"],
19-
hookCtx.options.excludeDeprecatedAfter,
24+
options.excludeDeprecatedAfter,
2025
);
2126

2227
const experimentalValue = getFirstValue(
2328
process.env["X_GLEAN_INCLUDE_EXPERIMENTAL"],
24-
hookCtx.options.includeExperimental === true ? "true" : undefined,
29+
options.includeExperimental === true ? "true" : undefined,
2530
);
2631

2732
if (deprecatedValue) {

src/lib/config.ts

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -40,19 +40,6 @@ export type SDKOptions = {
4040
retryConfig?: RetryConfig;
4141
timeoutMs?: number;
4242
debugLogger?: Logger;
43-
/**
44-
* Exclude API endpoints that will be deprecated after this date.
45-
* Use this to test your integration against upcoming deprecations.
46-
* Format: YYYY-MM-DD (e.g., '2026-10-15')
47-
*
48-
* More information: https://developers.glean.com/deprecations/overview
49-
*/
50-
excludeDeprecatedAfter?: string | undefined;
51-
/**
52-
* When true, enables experimental API features that are not yet generally available.
53-
* Use this to preview and test new functionality.
54-
*/
55-
includeExperimental?: boolean | undefined;
5643
};
5744

5845
export function serverURLFromOptions(options: SDKOptions): URL | null {

0 commit comments

Comments
 (0)