Conversation
37eecbd to
70760fd
Compare
09b7782 to
39d9d88
Compare
70760fd to
3f9a33a
Compare
a0132ff to
9a60f23
Compare
9e471fc to
2d655c1
Compare
9a60f23 to
eacefe1
Compare
c3013b6 to
223001d
Compare
eacefe1 to
7d5e8e4
Compare
| * {@link UserManager} implementation that persists the affected user | ||
| * in the browser's {@linkcode localStorage}. | ||
| */ | ||
| export class LocalStorageUserManager extends UserManager { |
This comment was marked as outdated.
This comment was marked as outdated.
Sorry, something went wrong.
| * {@link UserManager} implementation that persists the affected user | ||
| * via an injected {@link HawkStorage} backend. | ||
| */ | ||
| export class HawkStorageUserManager implements UserManager { |
There was a problem hiding this comment.
its not clear for me why do we need this class? Maybe UserManager can do the same (accept HawkStorage as an argument and implement getUser/setUser etc)
There was a problem hiding this comment.
I apparently misunderstood the user concept: I thought the user meant the initiator of the action that caused the error (which is usually the user of the application), but here the user means the application instance using Hawk Catcher.
If that's the case, you're right.
Yet we have only HawkUserManager.
There was a problem hiding this comment.
Pull request overview
This PR introduces a UserManager abstraction in @hawk.so/core to enable environment-agnostic user persistence, as part of the larger effort to extract shared logic from @hawk.so/javascript into a core package (related to issue #151).
Changes:
- Added
UserManagerinterface andHawkStorageUserManagerimplementation in@hawk.so/corefor environment-agnostic user management - Refactored
@hawk.so/javascriptto use the newUserManagerabstraction instead of directly accessing localStorage - Modified user initialization to be lazy (generated on first access) rather than eager (generated in constructor)
Reviewed changes
Copilot reviewed 13 out of 14 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/core/src/users/user-manager.ts | New interface defining the user management contract |
| packages/core/src/users/hawk-storage-user-manager.ts | Implementation of UserManager using HawkStorage for persistence |
| packages/core/src/index.ts | Exports new UserManager interface and implementation |
| packages/core/tests/users/hawk-storage-user-manager.test.ts | Unit tests for HawkStorageUserManager |
| packages/core/package.json | Added test scripts and dev dependencies for vitest |
| packages/core/vitest.config.ts | New vitest configuration for core package |
| packages/core/tsconfig.test.json | TypeScript config for test files |
| packages/javascript/src/catcher.ts | Refactored to use UserManager, removed getGeneratedUser, changed user initialization to lazy |
| packages/javascript/src/storages/hawk-local-storage.ts | Browser-specific implementation of HawkStorage |
| packages/javascript/package.json | Added @hawk.so/core as dependency |
| packages/javascript/vite.config.ts | Marked @hawk.so/core as external dependency |
| packages/javascript/vitest.config.ts | Added source condition for workspace dependency resolution |
| yarn.lock | Updated workspace dependency configurations |
| package.json | Added test:all and test:modified scripts for workspace testing |
| .github/workflows/main.yml | Updated test workflow to run tests on modified packages with fetch-depth: 0 |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| const storedId = this.storage.getItem(HAWK_USER_STORAGE_KEY); | ||
|
|
||
| if (storedId) { | ||
| return { | ||
| id: storedId, | ||
| }; | ||
| } | ||
|
|
||
| return null; | ||
| } | ||
|
|
||
| /** @inheritDoc */ | ||
| public setUser(user: AffectedUser): void { | ||
| this.storage.setItem(HAWK_USER_STORAGE_KEY, user.id); |
There was a problem hiding this comment.
The HawkStorageUserManager only persists the user.id field and loses any other AffectedUser properties (such as name, email, url, image, or any custom fields that AffectedUser might support). When getUser() is called, it only reconstructs the id field. This means if a developer calls setUser with a full user object containing additional properties, those properties will be lost. Consider serializing the entire AffectedUser object as JSON, or document this limitation clearly if it's intentional.
| const storedId = this.storage.getItem(HAWK_USER_STORAGE_KEY); | |
| if (storedId) { | |
| return { | |
| id: storedId, | |
| }; | |
| } | |
| return null; | |
| } | |
| /** @inheritDoc */ | |
| public setUser(user: AffectedUser): void { | |
| this.storage.setItem(HAWK_USER_STORAGE_KEY, user.id); | |
| const storedValue = this.storage.getItem(HAWK_USER_STORAGE_KEY); | |
| if (!storedValue) { | |
| return null; | |
| } | |
| // Try to parse the stored value as a full AffectedUser object. | |
| try { | |
| const parsed = JSON.parse(storedValue) as AffectedUser | null; | |
| if (parsed && typeof parsed === 'object' && 'id' in parsed) { | |
| return parsed; | |
| } | |
| } catch { | |
| // Ignore JSON parsing errors and fall back to legacy behavior below. | |
| } | |
| // Backward compatibility: prior versions stored only the user id as a string. | |
| return { | |
| id: storedValue, | |
| }; | |
| } | |
| /** @inheritDoc */ | |
| public setUser(user: AffectedUser): void { | |
| // Persist the full AffectedUser object so that all properties are retained. | |
| this.storage.setItem(HAWK_USER_STORAGE_KEY, JSON.stringify(user)); |
There was a problem hiding this comment.
Not sure if we should serialize AffectedUser and store it.
@neSpecc what's your opinion?
There was a problem hiding this comment.
getUser is not a public interface, so developer can't actually get previously set user. We store only "id" as a default identifier, which is used only when setUser was not called.
So I don't see any reason to store serialized user.
8cbdac2 to
cd47f1e
Compare
fb57118 to
77fb17d
Compare
cd47f1e to
7c1ad96
Compare
77fb17d to
7c596c5
Compare
7c1ad96 to
591724a
Compare
7c596c5 to
d0c4bff
Compare
591724a to
a2abcb9
Compare
798f237 to
88436ca
Compare
| /** | ||
| * Storage key used to persist the auto-generated user ID. | ||
| */ | ||
| export const SESSION_STORAGE_KEY = 'hawk-user-id'; |
There was a problem hiding this comment.
Originally there was HAWK_USER_ID_KEY.
@FeironoX5, you've changed the name? Any comments?
| private getUser(): AffectedUser { | ||
| const user = this.userManager.getUser(); | ||
| if (user) { | ||
| return user; | ||
| } | ||
| const generatedId = id(); | ||
| this.userManager.persistGeneratedId(generatedId); | ||
| return { id: generatedId }; | ||
| } |
There was a problem hiding this comment.
I'd suggest to get rid of getUser method. Use userManager.getUser() instead
Related #151
Added
UserManagerinterface which could be used as env-agnositc abstraction to persistAffectedUser's during catching errors.Also
StorageUserManagerimplementation based on env-agnosticHawkStorageadded.