From c323b8db94904e84bdf0a99b7147e45521bfdd29 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Wed, 5 Mar 2025 19:32:07 +0100 Subject: [PATCH 1/6] fix:(browser-sdk,react-sdk): depecate enabledCheck and configCheck event listeners in favour of just `check`. --- packages/browser-sdk/README.md | 3 +-- packages/browser-sdk/src/client.ts | 1 + packages/browser-sdk/src/hooksManager.ts | 11 +++++++++++ packages/openfeature-browser-provider/package.json | 4 ++-- 4 files changed, 15 insertions(+), 4 deletions(-) diff --git a/packages/browser-sdk/README.md b/packages/browser-sdk/README.md index a64ad6dd..32c773fe 100644 --- a/packages/browser-sdk/README.md +++ b/packages/browser-sdk/README.md @@ -274,8 +274,7 @@ See details in [Feedback HTTP API](https://docs.bucket.co/reference/http-trackin Event listeners allow for capturing various events occurring in the `BucketClient`. This is useful to build integrations with other system or for various debugging purposes. There are 5 kinds of events: -- `configCheck`: Your code used a feature config -- `enabledCheck`: Your code checked whether a specific feature should be enabled +- `check`: Your code used `isEnabled` or `config` for a feature - `featuresUpdated`: Features were updated. Either because they were loaded as part of initialization or because the user/company updated - `user`: User information updated (similar to the `identify` call used in tracking terminology) - `company`: Company information updated (sometimes to the `group` call used in tracking terminology) diff --git a/packages/browser-sdk/src/client.ts b/packages/browser-sdk/src/client.ts index 85d36d5e..a0a2de53 100644 --- a/packages/browser-sdk/src/client.ts +++ b/packages/browser-sdk/src/client.ts @@ -799,6 +799,7 @@ export class BucketClient { checkEvent.action == "check-config" ? "configCheck" : "enabledCheck", checkEvent, ); + this.hooks.trigger("check", checkEvent); }); } diff --git a/packages/browser-sdk/src/hooksManager.ts b/packages/browser-sdk/src/hooksManager.ts index f01e75ff..9d684184 100644 --- a/packages/browser-sdk/src/hooksManager.ts +++ b/packages/browser-sdk/src/hooksManager.ts @@ -5,8 +5,17 @@ import { CompanyContext, UserContext } from "./context"; * @internal */ export interface HookArgs { + /** + * Deprecated: Use `check` instead. + * @deprecated + */ configCheck: CheckEvent; + /** + * Deprecated: Use `check` instead. + * @deprecated + */ enabledCheck: CheckEvent; + check: CheckEvent; featuresUpdated: RawFeatures; user: UserContext; company: CompanyContext; @@ -28,6 +37,7 @@ export class HooksManager { private hooks: { enabledCheck: ((arg0: CheckEvent) => void)[]; configCheck: ((arg0: CheckEvent) => void)[]; + check: ((arg0: CheckEvent) => void)[]; featuresUpdated: ((arg0: RawFeatures) => void)[]; user: ((arg0: UserContext) => void)[]; company: ((arg0: CompanyContext) => void)[]; @@ -35,6 +45,7 @@ export class HooksManager { } = { enabledCheck: [], configCheck: [], + check: [], featuresUpdated: [], user: [], company: [], diff --git a/packages/openfeature-browser-provider/package.json b/packages/openfeature-browser-provider/package.json index 31a4c64d..dc4efeb6 100644 --- a/packages/openfeature-browser-provider/package.json +++ b/packages/openfeature-browser-provider/package.json @@ -29,9 +29,9 @@ "types": "./dist/index.d.ts", "exports": { ".": { + "types": "./dist/index.d.ts", "import": "./dist/bucket-openfeature-browser-provider.mjs", - "require": "./dist/bucket-openfeature-browser-provider.umd.js", - "types": "./dist/index.d.ts" + "require": "./dist/bucket-openfeature-browser-provider.umd.js" } }, "dependencies": { From 78d5dfc0662445a1ffc2a76e3fe37901638d6987 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Wed, 5 Mar 2025 19:37:20 +0100 Subject: [PATCH 2/6] update tests + docs --- packages/browser-sdk/index.html | 2 +- packages/browser-sdk/test/client.test.ts | 8 +++++ .../browser-sdk/test/hooksManager.test.ts | 34 +++++++++++++------ packages/react-sdk/README.md | 2 +- packages/react-sdk/src/index.tsx | 4 +-- 5 files changed, 36 insertions(+), 14 deletions(-) diff --git a/packages/browser-sdk/index.html b/packages/browser-sdk/index.html index 6768647d..bc4133fa 100644 --- a/packages/browser-sdk/index.html +++ b/packages/browser-sdk/index.html @@ -54,7 +54,7 @@ document.getElementById("loading").style.display = "none"; }); - bucket.on("enabledCheck", (check) => + bucket.on("check", (check) => console.log(`Check event for ${check.key}`), ); diff --git a/packages/browser-sdk/test/client.test.ts b/packages/browser-sdk/test/client.test.ts index 59c8a6d8..2fc02980 100644 --- a/packages/browser-sdk/test/client.test.ts +++ b/packages/browser-sdk/test/client.test.ts @@ -80,6 +80,7 @@ describe("BucketClient", () => { const trackHook = vi.fn(); const userHook = vi.fn(); const companyHook = vi.fn(); + const checkHook = vi.fn(); const checkHookIsEnabled = vi.fn(); const checkHookConfig = vi.fn(); const featuresUpdated = vi.fn(); @@ -87,6 +88,7 @@ describe("BucketClient", () => { client.on("track", trackHook); client.on("user", userHook); client.on("company", companyHook); + client.on("check", checkHook); client.on("configCheck", checkHookConfig); client.on("enabledCheck", checkHookIsEnabled); client.on("featuresUpdated", featuresUpdated); @@ -108,10 +110,14 @@ describe("BucketClient", () => { // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- special getter triggering event client.getFeature("featureA").isEnabled; expect(checkHookIsEnabled).toHaveBeenCalled(); + expect(checkHook).toHaveBeenCalled(); + + checkHook.mockReset(); // eslint-disable-next-line @typescript-eslint/no-unused-expressions -- special getter triggering event client.getFeature("featureA").config; expect(checkHookConfig).toHaveBeenCalled(); + expect(checkHook).toHaveBeenCalled(); expect(featuresUpdated).not.toHaveBeenCalled(); await client.updateOtherContext({ key: "value" }); @@ -121,6 +127,7 @@ describe("BucketClient", () => { client.off("track", trackHook); client.off("user", userHook); client.off("company", companyHook); + client.off("check", checkHook); client.off("configCheck", checkHookConfig); client.off("enabledCheck", checkHookIsEnabled); client.off("featuresUpdated", featuresUpdated); @@ -147,6 +154,7 @@ describe("BucketClient", () => { expect(trackHook).not.toHaveBeenCalled(); expect(userHook).not.toHaveBeenCalled(); expect(companyHook).not.toHaveBeenCalled(); + expect(checkHook).not.toHaveBeenCalled(); expect(checkHookIsEnabled).not.toHaveBeenCalled(); expect(checkHookConfig).not.toHaveBeenCalled(); expect(featuresUpdated).not.toHaveBeenCalled(); diff --git a/packages/browser-sdk/test/hooksManager.test.ts b/packages/browser-sdk/test/hooksManager.test.ts index ae17de64..4e0e7715 100644 --- a/packages/browser-sdk/test/hooksManager.test.ts +++ b/packages/browser-sdk/test/hooksManager.test.ts @@ -12,6 +12,20 @@ describe("HookManager", () => { }); it("should add and trigger check-is-enabled hooks", () => { + const callback = vi.fn(); + hookManager.addHook("check", callback); + + const checkEvent: CheckEvent = { + action: "check-is-enabled", + key: "test-key", + value: true, + }; + hookManager.trigger("check", checkEvent); + + expect(callback).toHaveBeenCalledWith(checkEvent); + }); + + it("should add and trigger enabledCheck hooks", () => { const callback = vi.fn(); hookManager.addHook("enabledCheck", callback); @@ -94,15 +108,15 @@ describe("HookManager", () => { const callback1 = vi.fn(); const callback2 = vi.fn(); - hookManager.addHook("enabledCheck", callback1); - hookManager.addHook("enabledCheck", callback2); + hookManager.addHook("check", callback1); + hookManager.addHook("check", callback2); const checkEvent: CheckEvent = { action: "check-is-enabled", key: "test-key", value: true, }; - hookManager.trigger("enabledCheck", checkEvent); + hookManager.trigger("check", checkEvent); expect(callback1).toHaveBeenCalledWith(checkEvent); expect(callback2).toHaveBeenCalledWith(checkEvent); @@ -112,16 +126,16 @@ describe("HookManager", () => { const callback1 = vi.fn(); const callback2 = vi.fn(); - hookManager.addHook("enabledCheck", callback1); - hookManager.addHook("enabledCheck", callback2); - hookManager.removeHook("enabledCheck", callback1); + hookManager.addHook("check", callback1); + hookManager.addHook("check", callback2); + hookManager.removeHook("check", callback1); const checkEvent: CheckEvent = { action: "check-is-enabled", key: "test-key", value: true, }; - hookManager.trigger("enabledCheck", checkEvent); + hookManager.trigger("check", checkEvent); expect(callback1).not.toHaveBeenCalled(); expect(callback2).toHaveBeenCalledWith(checkEvent); @@ -131,8 +145,8 @@ describe("HookManager", () => { const callback1 = vi.fn(); const callback2 = vi.fn(); - const removeHook1 = hookManager.addHook("enabledCheck", callback1); - hookManager.addHook("enabledCheck", callback2); + const removeHook1 = hookManager.addHook("check", callback1); + hookManager.addHook("check", callback2); removeHook1(); const checkEvent: CheckEvent = { @@ -140,7 +154,7 @@ describe("HookManager", () => { key: "test-key", value: true, }; - hookManager.trigger("enabledCheck", checkEvent); + hookManager.trigger("check", checkEvent); expect(callback1).not.toHaveBeenCalled(); expect(callback2).toHaveBeenCalledWith(checkEvent); diff --git a/packages/react-sdk/README.md b/packages/react-sdk/README.md index 06485f54..b76b0fb9 100644 --- a/packages/react-sdk/README.md +++ b/packages/react-sdk/README.md @@ -409,7 +409,7 @@ function LoggingWrapper({ children }: { children: ReactNode }) { const client = useClient(); useEffect(() => { - client.on("enabledCheck", (evt) => { + client.on("check", (evt) => { console.log(`The feature ${evt.key} is ${evt.value} for user.`); }); }, [client]); diff --git a/packages/react-sdk/src/index.tsx b/packages/react-sdk/src/index.tsx index 4b7906c5..5096b147 100644 --- a/packages/react-sdk/src/index.tsx +++ b/packages/react-sdk/src/index.tsx @@ -362,8 +362,8 @@ export function useUpdateOtherContext() { * ```ts * const client = useClient(); * useEffect(() => { - * return client?.on("enabledCheck", () => { - * console.log("enabledCheck hook called"); + * return client?.on("check", () => { + * console.log("check hook called"); * }); * }, [client]); * ``` From d784ce5d73ca61503189a084751d4a2a99c356b3 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Wed, 5 Mar 2025 19:38:00 +0100 Subject: [PATCH 3/6] fix test --- packages/browser-sdk/test/client.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/browser-sdk/test/client.test.ts b/packages/browser-sdk/test/client.test.ts index 2fc02980..cf306cd9 100644 --- a/packages/browser-sdk/test/client.test.ts +++ b/packages/browser-sdk/test/client.test.ts @@ -136,6 +136,7 @@ describe("BucketClient", () => { trackHook.mockReset(); userHook.mockReset(); companyHook.mockReset(); + checkHook.mockReset(); checkHookIsEnabled.mockReset(); checkHookConfig.mockReset(); featuresUpdated.mockReset(); From 0e2fd162d26860457369df1d7d4160e7167fdc04 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Wed, 5 Mar 2025 19:39:39 +0100 Subject: [PATCH 4/6] publish new patch version --- packages/browser-sdk/package.json | 2 +- packages/react-sdk/package.json | 4 ++-- yarn.lock | 16 ++++++++++++++-- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/packages/browser-sdk/package.json b/packages/browser-sdk/package.json index 9f0ade77..7f5daa8a 100644 --- a/packages/browser-sdk/package.json +++ b/packages/browser-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@bucketco/browser-sdk", - "version": "3.1.0", + "version": "3.1.1", "packageManager": "yarn@4.1.1", "license": "MIT", "repository": { diff --git a/packages/react-sdk/package.json b/packages/react-sdk/package.json index 263479da..abe100bb 100644 --- a/packages/react-sdk/package.json +++ b/packages/react-sdk/package.json @@ -1,6 +1,6 @@ { "name": "@bucketco/react-sdk", - "version": "3.1.0", + "version": "3.1.1", "license": "MIT", "repository": { "type": "git", @@ -34,7 +34,7 @@ } }, "dependencies": { - "@bucketco/browser-sdk": "3.1.0", + "@bucketco/browser-sdk": "3.1.1", "canonical-json": "^0.0.4", "rollup": "^4.2.0" }, diff --git a/yarn.lock b/yarn.lock index 4d3e7513..c11cb521 100644 --- a/yarn.lock +++ b/yarn.lock @@ -417,7 +417,19 @@ __metadata: languageName: node linkType: hard -"@bucketco/browser-sdk@npm:3.1.0, @bucketco/browser-sdk@workspace:packages/browser-sdk": +"@bucketco/browser-sdk@npm:3.1.0": + version: 3.1.0 + resolution: "@bucketco/browser-sdk@npm:3.1.0" + dependencies: + "@floating-ui/dom": "npm:^1.6.8" + canonical-json: "npm:^0.0.4" + js-cookie: "npm:^3.0.5" + preact: "npm:^10.22.1" + checksum: 10c0/a53174fa826b990087ef434f3d9cb09dbd80b707783fa208d872f499b42e7dcebe326ff78225aa621670138c0059d60361e68903fd129dd25af1ed0d85a1428d + languageName: node + linkType: hard + +"@bucketco/browser-sdk@npm:3.1.1, @bucketco/browser-sdk@workspace:packages/browser-sdk": version: 0.0.0-use.local resolution: "@bucketco/browser-sdk@workspace:packages/browser-sdk" dependencies: @@ -580,7 +592,7 @@ __metadata: version: 0.0.0-use.local resolution: "@bucketco/react-sdk@workspace:packages/react-sdk" dependencies: - "@bucketco/browser-sdk": "npm:3.1.0" + "@bucketco/browser-sdk": "npm:3.1.1" "@bucketco/eslint-config": "workspace:^" "@bucketco/tsconfig": "workspace:^" "@testing-library/react": "npm:^15.0.7" From a53b6b404f7703b280c43f9da9afaeb746e98990 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Wed, 5 Mar 2025 20:03:50 +0100 Subject: [PATCH 5/6] update comments --- packages/browser-sdk/src/client.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/browser-sdk/src/client.ts b/packages/browser-sdk/src/client.ts index a0a2de53..a86fb777 100644 --- a/packages/browser-sdk/src/client.ts +++ b/packages/browser-sdk/src/client.ts @@ -480,30 +480,31 @@ export class BucketClient { } /** - * Add a hook to the client. + * Add an event listener * - * @param hook Hook to add. + * @param type Type of events to listen for + * @param handler The function to call when the event is triggered. * @returns A function to remove the hook. */ on( type: THookType, handler: (args0: HookArgs[THookType]) => void, ) { - this.hooks.addHook(type, handler); - return () => this.hooks.removeHook(type, handler); + return this.hooks.addHook(type, handler); } /** - * Remove a hook from the client. + * Remove an event listener + * + * @param type Type of event to remove. + * @param handler The same function that was passed to `on`. * - * @param hook Hook to add. - * @returns A function to remove the hook. */ off( type: THookType, handler: (args0: HookArgs[THookType]) => void, ) { - return this.hooks.removeHook(type, handler); + this.hooks.removeHook(type, handler); } /** From 26083f9fdedd38278022a29e3eed57f5e824e005 Mon Sep 17 00:00:00 2001 From: Ron Cohen Date: Thu, 6 Mar 2025 09:24:21 +0100 Subject: [PATCH 6/6] update test names --- packages/browser-sdk/test/hooksManager.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/browser-sdk/test/hooksManager.test.ts b/packages/browser-sdk/test/hooksManager.test.ts index 4e0e7715..6cae9c56 100644 --- a/packages/browser-sdk/test/hooksManager.test.ts +++ b/packages/browser-sdk/test/hooksManager.test.ts @@ -11,7 +11,7 @@ describe("HookManager", () => { hookManager = new HooksManager(); }); - it("should add and trigger check-is-enabled hooks", () => { + it("should add and trigger `check` hooks", () => { const callback = vi.fn(); hookManager.addHook("check", callback); @@ -25,7 +25,7 @@ describe("HookManager", () => { expect(callback).toHaveBeenCalledWith(checkEvent); }); - it("should add and trigger enabledCheck hooks", () => { + it("should add and trigger `enabledCheck` hooks", () => { const callback = vi.fn(); hookManager.addHook("enabledCheck", callback); @@ -39,7 +39,7 @@ describe("HookManager", () => { expect(callback).toHaveBeenCalledWith(checkEvent); }); - it("should add and trigger configCheck hooks", () => { + it("should add and trigger `configCheck` hooks", () => { const callback = vi.fn(); hookManager.addHook("configCheck", callback); @@ -53,7 +53,7 @@ describe("HookManager", () => { expect(callback).toHaveBeenCalledWith(checkEvent); }); - it("should add and trigger features-updated hooks", () => { + it("should add and trigger `featuresUpdated` hooks", () => { const callback = vi.fn(); hookManager.addHook("featuresUpdated", callback); @@ -65,7 +65,7 @@ describe("HookManager", () => { expect(callback).toHaveBeenCalledWith(features); }); - it("should add and trigger track hooks", () => { + it("should add and trigger `track` hooks", () => { const callback = vi.fn(); const user: UserContext = { id: "user-id", name: "user-name" }; const company: CompanyContext = { id: "company-id", name: "company-name" }; @@ -83,7 +83,7 @@ describe("HookManager", () => { }); }); - it("should add and trigger user hooks", () => { + it("should add and trigger `user` hooks", () => { const callback = vi.fn(); hookManager.addHook("user", callback); @@ -94,7 +94,7 @@ describe("HookManager", () => { expect(callback).toHaveBeenCalledWith(user); }); - it("should add and trigger company hooks", () => { + it("should add and trigger `company` hooks", () => { const callback = vi.fn(); hookManager.addHook("company", callback);