Skip to content

Commit 8b12cc3

Browse files
cherkanovartclaude
andauthored
feat(sdk): add PostHog usage tracking (#1999)
* feat(sdk): add PostHog usage tracking Track SDK method calls (localize*, recognizeLocale) with start/success/error events via PostHog. Identity is resolved through /whoami endpoint with fallback to hashed API key. Respects DO_NOT_TRACK=1 for opt-out. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * chore: add changeset for SDK PostHog tracking Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> * fix(sdk): correct SDK_PACKAGE name and Content-Type header Fix SDK_PACKAGE constant to match actual package name "@lingo.dev/_sdk" and fix malformed "ContentType" header to proper "Content-Type" in whoami request headers. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent b81fcce commit 8b12cc3

File tree

10 files changed

+684
-168
lines changed

10 files changed

+684
-168
lines changed

.changeset/sdk-posthog-tracking.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@lingo.dev/_sdk": minor
3+
---
4+
5+
Add PostHog usage tracking for SDK method calls

packages/sdk/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
"@lingo.dev/_spec": "workspace:*",
3434
"@paralleldrive/cuid2": "2.2.2",
3535
"jsdom": "25.0.1",
36+
"posthog-node": "5.14.0",
3637
"zod": "4.1.12"
3738
},
3839
"devDependencies": {

packages/sdk/src/index.spec.ts

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
import { describe, it, expect, vi } from "vitest";
2+
3+
vi.mock("./utils/observability");
4+
25
import { LingoDotDevEngine } from "./index";
36

47
describe("ReplexicaEngine", () => {
@@ -95,8 +98,8 @@ describe("ReplexicaEngine", () => {
9598
describe("localizeStringArray", () => {
9699
it("should localize an array of strings and maintain order", async () => {
97100
const engine = new LingoDotDevEngine({ apiKey: "test" });
98-
const mockLocalizeObject = vi.spyOn(engine, "localizeObject");
99-
mockLocalizeObject.mockImplementation(async (obj: any) => {
101+
const mockLocalizeRaw = vi.spyOn(engine as any, "_localizeRaw");
102+
mockLocalizeRaw.mockImplementation(async (obj: any) => {
100103
// Simulate translation by adding 'ES:' prefix to all string values
101104
return Object.fromEntries(
102105
Object.entries(obj).map(([key, value]) => [key, `ES:${value}`]),
@@ -110,8 +113,8 @@ describe("ReplexicaEngine", () => {
110113
targetLocale: "es",
111114
});
112115

113-
// Verify the mapped object was passed to localizeObject
114-
expect(mockLocalizeObject).toHaveBeenCalledWith(
116+
// Verify the mapped object was passed to _localizeRaw
117+
expect(mockLocalizeRaw).toHaveBeenCalledWith(
115118
{
116119
item_0: "Hello",
117120
item_1: "Goodbye",
@@ -130,15 +133,15 @@ describe("ReplexicaEngine", () => {
130133

131134
it("should handle empty array", async () => {
132135
const engine = new LingoDotDevEngine({ apiKey: "test" });
133-
const mockLocalizeObject = vi.spyOn(engine, "localizeObject");
134-
mockLocalizeObject.mockImplementation(async () => ({}));
136+
const mockLocalizeRaw = vi.spyOn(engine as any, "_localizeRaw");
137+
mockLocalizeRaw.mockImplementation(async () => ({}));
135138

136139
const result = await engine.localizeStringArray([], {
137140
sourceLocale: "en",
138141
targetLocale: "es",
139142
});
140143

141-
expect(mockLocalizeObject).toHaveBeenCalledWith(
144+
expect(mockLocalizeRaw).toHaveBeenCalledWith(
142145
{},
143146
{
144147
sourceLocale: "en",

0 commit comments

Comments
 (0)