Skip to content

Commit ad1d130

Browse files
fix: clear lens cache on re-bootstrap (#4)
## Summary - Fix stale lens references after SDK re-initialization: the lens cache retained objects from the old `lensRepository`, causing `fetchLens` to return lenses bound to a destroyed kit instance - Clear `lensCache` and reset `lenses` state at the start of the bootstrap effect, before the new kit is created ## Test plan - [ ] New test: "should clear lens cache on re-bootstrap" — verifies that after a `stabilityKey` change triggers re-bootstrap, previously cached lenses are evicted and `fetchLens` calls the new kit's `loadLens` - [ ] Full test suite passes
1 parent aca3a43 commit ad1d130

4 files changed

Lines changed: 63 additions & 3 deletions

File tree

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@snap/react-camera-kit",
3-
"version": "0.1.0",
3+
"version": "0.2.0",
44
"description": "React Camera Kit for web applications",
55
"type": "module",
66
"main": "./dist/cjs/index.js",

src/CameraKitProvider.test.tsx

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,62 @@ describe("CameraKitProvider", () => {
382382
expect(result.current.lenses).toHaveLength(2);
383383
});
384384

385+
it("should clear lens cache on re-bootstrap", async () => {
386+
const mockLens = { id: "lens-1", groupId: "group-1" } as Lens;
387+
(mockKit.lensRepository.loadLens as any).mockResolvedValue(mockLens);
388+
389+
const mockKit2 = {
390+
destroy: jest.fn().mockResolvedValue(undefined),
391+
createSession: jest.fn().mockResolvedValue(mockSession),
392+
lensRepository: {
393+
loadLens: jest.fn().mockResolvedValue(mockLens),
394+
loadLensGroups: jest.fn(),
395+
},
396+
} as any;
397+
398+
mockBootstrapCameraKit.mockReset().mockResolvedValueOnce(mockKit).mockResolvedValueOnce(mockKit2);
399+
400+
let stabilityKey = "key-1";
401+
const wrapper = ({ children }: { children: React.ReactNode }) => (
402+
<CameraKitProvider apiToken="test-token" stabilityKey={stabilityKey}>
403+
{children}
404+
</CameraKitProvider>
405+
);
406+
407+
const { result, rerender } = renderHook(() => useCameraKit(), { wrapper });
408+
409+
await waitFor(() => {
410+
expect(result.current.sdkStatus).toBe("ready");
411+
});
412+
413+
// Fetch a lens — populates the cache
414+
await act(async () => {
415+
await result.current.fetchLens("lens-1", "group-1");
416+
});
417+
418+
expect(mockKit.lensRepository.loadLens).toHaveBeenCalledTimes(1);
419+
expect(result.current.lenses).toHaveLength(1);
420+
421+
// Trigger re-bootstrap by changing stabilityKey
422+
stabilityKey = "key-2";
423+
rerender();
424+
425+
await waitFor(() => {
426+
expect(result.current.sdkStatus).toBe("ready");
427+
expect(mockBootstrapCameraKit).toHaveBeenCalledTimes(2);
428+
});
429+
430+
// Lenses state should have been cleared
431+
expect(result.current.lenses).toHaveLength(0);
432+
433+
// Fetch the same lens again — should NOT hit cache, should call new kit's loadLens
434+
await act(async () => {
435+
await result.current.fetchLens("lens-1", "group-1");
436+
});
437+
438+
expect(mockKit2.lensRepository.loadLens).toHaveBeenCalledWith("lens-1", "group-1");
439+
});
440+
385441
it("should apply lens", async () => {
386442
const mockLens = { id: "lens-1", groupId: "group-1" } as Lens;
387443
(mockKit.lensRepository.loadLens as any).mockResolvedValue(mockLens);

src/CameraKitProvider.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ export const CameraKitProvider: React.FC<CameraKitProviderProps> = ({
352352
const abortController = new AbortController();
353353
const emit = eventFactoryRef.current?.();
354354

355+
// Clear stale lens cache — the old kit's lensRepository is no longer valid.
356+
lensCache.current.clear();
357+
setLenses([]);
358+
355359
setCameraKitState({ status: "initializing" });
356360
emit?.({ kind: "bootstrap-attempt" });
357361
log.info("bootstrap_attempt");

0 commit comments

Comments
 (0)