-
Notifications
You must be signed in to change notification settings - Fork 0
feat(posthog): Added SDK data to header in requests, for Posthog filtering #44
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
5dc9ec4
feat(posthog): Added header injection to requests through galileo-gen…
Murike ebe4917
feat(posthog): Updated means of retrieving package version.
Murike 28df640
feat(posthog): Updated lint disable comment.
Murike c7d17e8
feat(posthog): Updated lint disable comment with ticket number.
Murike 6a6df85
feat(posthog): Removed compiler configuration.
Murike ac581ff
feat(posthog): Improved package.json path resolution.
Murike 772f656
feat(posthog): Removed unecessary linting comment.
Murike 39ac5aa
feat(posthog): Cloned request for header processing.
Murike 50a8c51
feat(posthog): Added coverage failure case in tests.
Murike File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| import type { BeforeRequestContext, BeforeRequestHook } from "./types.js"; | ||
|
|
||
| let cachedVersion: string | null = null; | ||
|
|
||
| function loadVersion(): string { | ||
| if (cachedVersion) { | ||
| return cachedVersion; | ||
| } | ||
|
|
||
| try { | ||
| // NOTES: require is being used for now, using import demands appropriate | ||
| // compiler configuration, which won't be enabled yet due to Speakeasy's | ||
| // particular way of enabling persistent edits conflicting with workflow. | ||
| // Ticket sc-56960 created for this investigation. | ||
| const packageJsonPath = require.resolve("galileo-generated/package.json"); | ||
| // eslint-disable-next-line @typescript-eslint/no-require-imports | ||
| const packageJson = require(packageJsonPath); | ||
Murike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cachedVersion = packageJson.version; | ||
| return cachedVersion ?? "unknown"; | ||
| } catch { | ||
| return "unknown"; | ||
| } | ||
Murike marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| } | ||
|
|
||
| function getSdkIdentifier(version: string): string { | ||
| return `galileo-generated/${version}`; | ||
| } | ||
|
|
||
| export class SDKIdentifierHook implements BeforeRequestHook { | ||
| async beforeRequest( | ||
| _hookCtx: BeforeRequestContext, | ||
| request: Request, | ||
| ): Promise<Request> { | ||
| const newRequest = request.clone(); | ||
|
|
||
| const version = loadVersion(); | ||
| const sdkIdentifier = getSdkIdentifier(version); | ||
| newRequest.headers.set("X-Galileo-SDK", sdkIdentifier); | ||
| return newRequest; | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added missing test. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,176 @@ | ||
| import { describe, test, expect, vi } from "vitest"; | ||
| import { SDKIdentifierHook } from "../../hooks/sdk-identifier.js"; | ||
| import type { BeforeRequestContext } from "../../hooks/types.js"; | ||
|
|
||
| describe("SDKIdentifierHook", () => { | ||
| const mockContext: BeforeRequestContext = { | ||
| baseURL: new URL("http://localhost:8088"), | ||
| operationID: "testOperation", | ||
| oAuth2Scopes: null, | ||
| retryConfig: { strategy: "none" }, | ||
| resolvedSecurity: null, | ||
| options: {}, | ||
| }; | ||
|
|
||
| describe("beforeRequest", () => { | ||
| test("adds X-Galileo-SDK header to request", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request = new Request("http://localhost:8088/api/test"); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
|
|
||
| expect(modifiedRequest.headers.has("X-Galileo-SDK")).toBe(true); | ||
| }); | ||
|
|
||
| test("header contains galileo-generated prefix", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request = new Request("http://localhost:8088/api/test"); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
| const headerValue = modifiedRequest.headers.get("X-Galileo-SDK"); | ||
|
|
||
| expect(headerValue).toMatch(/^galileo-generated\//); | ||
| }); | ||
|
|
||
| test("header contains valid version format", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request = new Request("http://localhost:8088/api/test"); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
| const headerValue = modifiedRequest.headers.get("X-Galileo-SDK"); | ||
|
|
||
| expect(headerValue).toMatch(/^galileo-generated\/\d+\.\d+\.\d+/); | ||
| }); | ||
|
|
||
| test("preserves existing headers", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request = new Request("http://localhost:8088/api/test", { | ||
| headers: { | ||
| "Content-Type": "application/json", | ||
| Authorization: "Bearer token", | ||
| }, | ||
| }); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
|
|
||
| expect(modifiedRequest.headers.get("Content-Type")).toBe("application/json"); | ||
| expect(modifiedRequest.headers.get("Authorization")).toBe("Bearer token"); | ||
| expect(modifiedRequest.headers.has("X-Galileo-SDK")).toBe(true); | ||
| }); | ||
|
|
||
| test("returns a Request object", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request = new Request("http://localhost:8088/api/test"); | ||
|
|
||
| const result = await hook.beforeRequest(mockContext, request); | ||
|
|
||
| expect(result instanceof Request).toBe(true); | ||
| }); | ||
|
|
||
| test("does not modify request method or body", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const body = JSON.stringify({ test: "data" }); | ||
| const request = new Request("http://localhost:8088/api/test", { | ||
| method: "POST", | ||
| body, | ||
| }); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
|
|
||
| expect(modifiedRequest.method).toBe("POST"); | ||
| }); | ||
|
|
||
| test("works with different HTTP methods", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
|
|
||
| for (const method of ["GET", "POST", "PUT", "DELETE", "PATCH"]) { | ||
| const request = new Request("http://localhost:8088/api/test", { | ||
| method, | ||
| }); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
|
|
||
| expect(modifiedRequest.headers.has("X-Galileo-SDK")).toBe(true); | ||
| expect(modifiedRequest.method).toBe(method); | ||
| } | ||
| }); | ||
|
|
||
| test("header value is consistent across multiple calls", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request1 = new Request("http://localhost:8088/api/test"); | ||
| const request2 = new Request("http://localhost:8088/api/test"); | ||
|
|
||
| const modifiedRequest1 = await hook.beforeRequest(mockContext, request1); | ||
| const modifiedRequest2 = await hook.beforeRequest(mockContext, request2); | ||
|
|
||
| const header1 = modifiedRequest1.headers.get("X-Galileo-SDK"); | ||
| const header2 = modifiedRequest2.headers.get("X-Galileo-SDK"); | ||
|
|
||
| expect(header1).toBe(header2); | ||
| }); | ||
|
|
||
| test("overwrites existing X-Galileo-SDK header", async () => { | ||
| const hook = new SDKIdentifierHook(); | ||
| const request = new Request("http://localhost:8088/api/test", { | ||
| headers: { | ||
| "X-Galileo-SDK": "old-value", | ||
| }, | ||
| }); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
| const headerValue = modifiedRequest.headers.get("X-Galileo-SDK"); | ||
|
|
||
| expect(headerValue).toMatch(/^galileo-generated\//); | ||
| expect(headerValue).not.toBe("old-value"); | ||
| }); | ||
|
|
||
| test("handles loadVersion() failure gracefully with fallback to unknown", async () => { | ||
| vi.resetModules(); | ||
|
|
||
| vi.doMock("../../hooks/sdk-identifier.js", async () => { | ||
| return { | ||
| SDKIdentifierHook: class { | ||
| async beforeRequest( | ||
| _hookCtx: BeforeRequestContext, | ||
| request: Request, | ||
| ): Promise<Request> { | ||
| const newRequest = request.clone(); | ||
|
|
||
| const loadVersionWithFailure = (): string => { | ||
| try { | ||
| throw new Error("Failed to load package.json (ESM runtime issue)"); | ||
| } catch { | ||
| return "unknown"; | ||
| } | ||
| }; | ||
|
|
||
| const version = loadVersionWithFailure(); | ||
| const sdkIdentifier = `galileo-generated/${version}`; | ||
| newRequest.headers.set("X-Galileo-SDK", sdkIdentifier); | ||
| return newRequest; | ||
| } | ||
| }, | ||
| }; | ||
| }); | ||
|
|
||
| const { SDKIdentifierHook: MockedHook } = await import("../../hooks/sdk-identifier.js"); | ||
| const hook = new MockedHook(); | ||
| const request = new Request("http://localhost:8088/api/test"); | ||
|
|
||
| const modifiedRequest = await hook.beforeRequest(mockContext, request); | ||
| const headerValue = modifiedRequest.headers.get("X-Galileo-SDK"); | ||
|
|
||
| expect(headerValue).toBe("galileo-generated/unknown"); | ||
|
|
||
| vi.doUnmock("../../hooks/sdk-identifier.js"); | ||
| }); | ||
| }); | ||
|
|
||
| describe("hook integration", () => { | ||
| test("hook implements BeforeRequestHook interface", () => { | ||
| const hook = new SDKIdentifierHook(); | ||
|
|
||
| expect(typeof hook.beforeRequest).toBe("function"); | ||
| }); | ||
| }); | ||
| }); |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.