Skip to content

@jlnstack/notifications#51

Open
jln13x wants to merge 7 commits intomainfrom
jln13x/notification-inbox
Open

@jlnstack/notifications#51
jln13x wants to merge 7 commits intomainfrom
jln13x/notification-inbox

Conversation

@jln13x
Copy link
Owner

@jln13x jln13x commented Jan 23, 2026

Summary

Complete notification management system with type-safe inbox support. Includes core manager with memory adapter, HTTP client for browser use, React hooks/context for UI integration, and Next.js server handlers for API routes.

Key Features

  • Type-safe notification definitions using Standard Schema
  • In-memory adapter for development/testing
  • HTTP client for remote notifications via API
  • React client with query deduplication and stale-while-revalidate
  • Server handlers with authentication scoping
  • Comprehensive tests covering critical logic

🤖 Generated with Claude Code

jln13x and others added 2 commits January 23, 2026 10:36
…dules

Add focused tests for critical logic in http-manager, react client, and server handlers. Remove clearMemoryStore from public exports as it's only needed internally for testing.

Co-Authored-By: Claude Haiku 4.5 <[email protected]>
@vercel
Copy link

vercel bot commented Jan 23, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Review Updated (UTC)
jlnstack Ready Ready Preview, Comment Jan 23, 2026 10:46pm

Request Review

@jln13x jln13x changed the title Add notification package with client, react, and server integrations @jlnstack/notifications Jan 23, 2026
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Jan 23, 2026

Greptile Summary

Added comprehensive notification management system with type-safe inbox support. The implementation includes a core manager with memory adapter, HTTP client for browser use, React hooks/context for UI integration, and Next.js server handlers for API routes.

Key architectural decisions:

  • Type-safe notification definitions using Standard Schema (compatible with Zod, Valibot, ArkType)
  • External store pattern for React client using useSyncExternalStore for proper React 18+ concurrent rendering
  • Query deduplication and stale-while-revalidate caching strategy
  • Server-side authentication scoping via getId callback
  • Ownership verification on all server endpoints to prevent unauthorized access

Implementation highlights:

  • Global memory store persists across hot reloads using Symbol.for
  • Proper error handling with JSON parsing fallbacks in HTTP client
  • Comprehensive test coverage including runtime tests and type tests
  • Documentation follows repository guidelines with proper meta.json structure and index card entry

Confidence Score: 5/5

  • This PR is safe to merge with minimal risk
  • Score reflects well-architected implementation with comprehensive test coverage (434 test lines covering core logic), proper type safety using Standard Schema, security-conscious server handlers with ownership verification, and adherence to repository documentation guidelines. The code follows TypeScript best practices with proper type inference and minimal explicit annotations as per AGENTS.md
  • No files require special attention

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

30 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +271 to +273
async markManyAsRead(ids: string[]): Promise<void> {
await Promise.all(ids.map((id) => manager.markAsRead(id)));
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: markManyAsRead uses Promise.all with individual markAsRead calls, triggering separate API requests for each ID. Consider adding a batch endpoint /read-many for better performance with large ID arrays

Suggested change
async markManyAsRead(ids: string[]): Promise<void> {
await Promise.all(ids.map((id) => manager.markAsRead(id)));
},
async markManyAsRead(ids: string[]): Promise<void> {
await request(
baseUrl,
"/read-many",
{
method: "POST",
body: JSON.stringify({ ids }),
},
fetchFn,
deserializeFn
);
},

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/notification/src/client/http-manager.ts
Line: 271:273

Comment:
**style:** `markManyAsRead` uses `Promise.all` with individual `markAsRead` calls, triggering separate API requests for each ID. Consider adding a batch endpoint `/read-many` for better performance with large ID arrays

```suggestion
    async markManyAsRead(ids: string[]): Promise<void> {
      await request(
        baseUrl,
        "/read-many",
        {
          method: "POST",
          body: JSON.stringify({ ids }),
        },
        fetchFn,
        deserializeFn
      );
    },
```

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines 322 to 327
async deleteMany(filter: Omit<NotificationFilter<Types>, "userId">): Promise<number> {
// List matching notifications and delete each
const notifications = await manager.list(filter);
await Promise.all(notifications.map((n) => manager.delete(n.id)));
return notifications.length;
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: deleteMany lists all matching notifications client-side then deletes individually. For large result sets, consider adding a server endpoint that performs bulk deletion to reduce network overhead

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Prompt To Fix With AI
This is a comment left during a code review.
Path: packages/notification/src/client/http-manager.ts
Line: 322:327

Comment:
**style:** `deleteMany` lists all matching notifications client-side then deletes individually. For large result sets, consider adding a server endpoint that performs bulk deletion to reduce network overhead

<sub>Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!</sub>

How can I resolve this? If you propose a fix, please make it concise.

- Fix non-null assertions by adding proper type guards
- Remove unused variables and functions (filterKey, serializeFilter, NextResponse)
- Add htmlFor attributes to labels for accessibility
- Replace forEach with for...of to avoid implicit returns
- Remove unused imports

Co-Authored-By: Claude Haiku 4.5 <[email protected]>
- Add getId handler for server-side auth context
- Remove userId from HTTP client calls (determined server-side)
- Fix data type from unknown to Record<string, unknown>

Co-Authored-By: Claude Opus 4.5 <[email protected]>
…ientId

- Rename package from @jlnstack/notification to @jlnstack/notifications
- Refactor send() API from send(type, options) to send({ type, ...options })
- Rename userId to recipientId throughout to support notifications to
  any entity type (users, workspaces, teams, etc.)

Co-Authored-By: Claude Opus 4.5 <[email protected]>
- Add parseNotificationData function that validates data through Standard Schema
- Add NotificationValidationError class with descriptive error messages
- Require all notification type schemas to implement Standard Schema (Zod, Valibot, etc.)
- Return 400 Bad Request for validation errors in server handlers
- Add comprehensive tests for schema validation behavior

Co-Authored-By: Claude Opus 4.5 <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant