diff --git a/README.md b/README.md index 7aa4360..b6f3023 100644 --- a/README.md +++ b/README.md @@ -116,10 +116,12 @@ import { LaunchDarkly } from "@convex-dev/launchdarkly"; import { components } from "./_generated/api"; import { query } from "./_generated/server"; +const launchdarkly = new LaunchDarkly(components.launchdarkly); + export const myQuery = query({ args: {}, handler: async ({ ctx }) => { - const launchdarkly = new LaunchDarkly(components.launchdarkly, ctx); + const launchdarkly = ld.sdk(ctx); const isFlagOn = await launchdarkly.boolVariation( "my-flag", { key: "myUser" }, @@ -202,16 +204,20 @@ Once configured, you may initialize `LaunchDarkly` with the appropriate componen ```typescript import { LaunchDarkly } from "@convex-dev/launchdarkly"; +const ldFirst = new LaunchDarkly(components.first, { + LAUNCHDARKLY_SDK_KEY: process.env.LAUNCHDARKLY_SDK_KEY_FIRST!, +}); + +const ldSecond = new LaunchDarkly(components.second, { + LAUNCHDARKLY_SDK_KEY: process.env.LAUNCHDARKLY_SDK_KEY_SECOND!, +}); + export const myQuery = query({ args: {}, handler: async ({ ctx }) => { - const launchdarklyFirst = new LaunchDarkly(components.first, ctx, { - LAUNCHDARKLY_SDK_KEY: process.env.LAUNCHDARKLY_SDK_KEY_FIRST! - }); + const launchdarklyFirst = ldFirst.sdk(ctx); - const launchdarklySecond = new LaunchDarkly(components.second, ctx, { - LAUNCHDARKLY_SDK_KEY: process.env.LAUNCHDARKLY_SDK_KEY_SECOND! - }); + const launchdarklySecond = ldSecond.sdk(ctx); ... }, diff --git a/example/convex/example.ts b/example/convex/example.ts index 1ce85f5..5ba075f 100644 --- a/example/convex/example.ts +++ b/example/convex/example.ts @@ -2,12 +2,14 @@ import { LaunchDarkly } from "@convex-dev/launchdarkly"; import { mutation, query } from "./_generated/server"; import { components } from "./_generated/api"; +const launchdarkly = new LaunchDarkly(components.launchdarkly); + export const listFruits = query({ handler: async (ctx) => { - const launchdarkly = new LaunchDarkly(components.launchdarkly, ctx); + const ld= = launchdarkly.sdk(ctx); const user = { key: "myUserId" }; - const showFruits = await launchdarkly.boolVariation( + const showFruits = await ld.boolVariation( "can-show-fruits", user, true @@ -21,11 +23,11 @@ export const listFruits = query({ export const buyFruit = mutation({ handler: async (ctx) => { - const launchdarkly = new LaunchDarkly(components.launchdarkly, ctx); + const ld = launchdarkly.sdk(ctx); const user = { key: "myUserId" }; - const showFruits = await launchdarkly.boolVariation( + const showFruits = await ld.boolVariation( "can-buy-fruits", user, false @@ -37,7 +39,7 @@ export const buyFruit = mutation({ }; } - launchdarkly.track("buy-fruit", user); + ld.track("buy-fruit", user); }, }); @@ -47,9 +49,9 @@ export const initialized = query({ if (!process.env.LAUNCHDARKLY_SDK_KEY) { return false; } - const launchdarkly = new LaunchDarkly(components.launchdarkly, ctx); + const ld = launchdarkly.sdk(ctx); return ( - (await launchdarkly.allFlagsState({ key: "any" })).allValues()[ + (await ld.allFlagsState({ key: "any" })).allValues()[ "can-buy-fruits" ] !== undefined ); diff --git a/src/sdk/LaunchDarkly.test.ts b/src/sdk/LaunchDarkly.test.ts index 17d4062..5352bb0 100644 --- a/src/sdk/LaunchDarkly.test.ts +++ b/src/sdk/LaunchDarkly.test.ts @@ -12,21 +12,21 @@ describe("LaunchDarkly", () => { new LaunchDarkly( // @ts-expect-error It's ok api, - {}, { LAUNCHDARKLY_SDK_KEY: "test-key", } - ); + // @ts-expect-error It's ok + ).sdk({}); expect(setTimeoutSpy).not.toHaveBeenCalled(); expect(setIntervalSpy).not.toHaveBeenCalled(); }); test("should throw an error if LAUNCHDARKLY_SDK_KEY is not provided", async () => { - await expect( - // @ts-expect-error It's ok - () => new LaunchDarkly(api, {}, {}) - ).toThrow(new Error("LAUNCHDARKLY_SDK_KEY is required")); + // @ts-expect-error It's ok + await expect(() => new LaunchDarkly(api, {}).sdk({})).toThrow( + new Error("LAUNCHDARKLY_SDK_KEY is required") + ); }); test("should not throw an error if the env var is set", () => { @@ -34,7 +34,7 @@ describe("LaunchDarkly", () => { expect(() => { // @ts-expect-error It's ok - new LaunchDarkly(api, {}, {}); + new LaunchDarkly(api, {}).sdk({}); }).not.toThrow(); vi.unstubAllEnvs(); @@ -44,11 +44,11 @@ describe("LaunchDarkly", () => { const ld = new LaunchDarkly( // @ts-expect-error It's ok api, - {}, { LAUNCHDARKLY_SDK_KEY: "test-key", } - ); + // @ts-expect-error It's ok + ).sdk({}); // @ts-expect-error We are testing internal state expect(ld.eventProcessor).not.toBeInstanceOf(EventProcessor); @@ -58,11 +58,11 @@ describe("LaunchDarkly", () => { const ld = new LaunchDarkly( // @ts-expect-error It's ok api, - { runMutation: () => {} }, { LAUNCHDARKLY_SDK_KEY: "test-key", } - ); + // @ts-expect-error It's ok + ).sdk({ runMutation: () => {} }); // @ts-expect-error We are testing internal state expect(ld.eventProcessor).toBeInstanceOf(EventProcessor); @@ -72,12 +72,12 @@ describe("LaunchDarkly", () => { const ld = new LaunchDarkly( // @ts-expect-error It's ok api, - { runMutation: () => {} }, { LAUNCHDARKLY_SDK_KEY: "test-key", sendEvents: false, } - ); + // @ts-expect-error It's ok + ).sdk({ runMutation: () => {} }); // @ts-expect-error We are testing internal state expect(ld.eventProcessor).not.toBeInstanceOf(EventProcessor); diff --git a/src/sdk/LaunchDarkly.ts b/src/sdk/LaunchDarkly.ts index e5174df..0a96514 100644 --- a/src/sdk/LaunchDarkly.ts +++ b/src/sdk/LaunchDarkly.ts @@ -17,7 +17,22 @@ import { import { RunMutationCtx, RunQueryCtx } from "../component/types"; import { ComponentApi } from "./useApi"; -export class LaunchDarkly extends LDClientImpl { +export class LaunchDarkly { + constructor( + private component: ComponentApi, + private options?: { + application?: LDOptions["application"]; + sendEvents?: boolean; + LAUNCHDARKLY_SDK_KEY?: string; + } & EventProcessorOptions + ) {} + + sdk(ctx: RunQueryCtx | RunMutationCtx) { + return new LDClient(this.component, ctx, this.options); + } +} + +class LDClient extends LDClientImpl { constructor( component: ComponentApi, ctx: RunQueryCtx | RunMutationCtx,