diff --git a/package-lock.json b/package-lock.json
index af13290..e34b948 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@snap/react-camera-kit",
- "version": "0.1.0",
+ "version": "0.2.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@snap/react-camera-kit",
- "version": "0.1.0",
+ "version": "0.2.0",
"license": "MIT",
"dependencies": {
"stable-hash": "^0.0.6"
diff --git a/package.json b/package.json
index 86f705c..1036be6 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@snap/react-camera-kit",
- "version": "0.1.0",
+ "version": "0.2.0",
"description": "React Camera Kit for web applications",
"type": "module",
"main": "./dist/cjs/index.js",
diff --git a/src/CameraKitProvider.test.tsx b/src/CameraKitProvider.test.tsx
index 9d39150..ea82ecd 100644
--- a/src/CameraKitProvider.test.tsx
+++ b/src/CameraKitProvider.test.tsx
@@ -382,6 +382,62 @@ describe("CameraKitProvider", () => {
expect(result.current.lenses).toHaveLength(2);
});
+ it("should clear lens cache on re-bootstrap", async () => {
+ const mockLens = { id: "lens-1", groupId: "group-1" } as Lens;
+ (mockKit.lensRepository.loadLens as any).mockResolvedValue(mockLens);
+
+ const mockKit2 = {
+ destroy: jest.fn().mockResolvedValue(undefined),
+ createSession: jest.fn().mockResolvedValue(mockSession),
+ lensRepository: {
+ loadLens: jest.fn().mockResolvedValue(mockLens),
+ loadLensGroups: jest.fn(),
+ },
+ } as any;
+
+ mockBootstrapCameraKit.mockReset().mockResolvedValueOnce(mockKit).mockResolvedValueOnce(mockKit2);
+
+ let stabilityKey = "key-1";
+ const wrapper = ({ children }: { children: React.ReactNode }) => (
+
+ {children}
+
+ );
+
+ const { result, rerender } = renderHook(() => useCameraKit(), { wrapper });
+
+ await waitFor(() => {
+ expect(result.current.sdkStatus).toBe("ready");
+ });
+
+ // Fetch a lens — populates the cache
+ await act(async () => {
+ await result.current.fetchLens("lens-1", "group-1");
+ });
+
+ expect(mockKit.lensRepository.loadLens).toHaveBeenCalledTimes(1);
+ expect(result.current.lenses).toHaveLength(1);
+
+ // Trigger re-bootstrap by changing stabilityKey
+ stabilityKey = "key-2";
+ rerender();
+
+ await waitFor(() => {
+ expect(result.current.sdkStatus).toBe("ready");
+ expect(mockBootstrapCameraKit).toHaveBeenCalledTimes(2);
+ });
+
+ // Lenses state should have been cleared
+ expect(result.current.lenses).toHaveLength(0);
+
+ // Fetch the same lens again — should NOT hit cache, should call new kit's loadLens
+ await act(async () => {
+ await result.current.fetchLens("lens-1", "group-1");
+ });
+
+ expect(mockKit2.lensRepository.loadLens).toHaveBeenCalledWith("lens-1", "group-1");
+ });
+
it("should apply lens", async () => {
const mockLens = { id: "lens-1", groupId: "group-1" } as Lens;
(mockKit.lensRepository.loadLens as any).mockResolvedValue(mockLens);
diff --git a/src/CameraKitProvider.tsx b/src/CameraKitProvider.tsx
index 82d8045..720c42c 100644
--- a/src/CameraKitProvider.tsx
+++ b/src/CameraKitProvider.tsx
@@ -352,6 +352,10 @@ export const CameraKitProvider: React.FC = ({
const abortController = new AbortController();
const emit = eventFactoryRef.current?.();
+ // Clear stale lens cache — the old kit's lensRepository is no longer valid.
+ lensCache.current.clear();
+ setLenses([]);
+
setCameraKitState({ status: "initializing" });
emit?.({ kind: "bootstrap-attempt" });
log.info("bootstrap_attempt");