-
Notifications
You must be signed in to change notification settings - Fork 4
Feat/dreamsync #367
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Feat/dreamsync #367
Conversation
Caution Review failedThe pull request is closed. WalkthroughLarge refactor introducing a new DreamSync REST API (controllers, services, entities, migrations, middleware, bootstrap), a client-side auth/context + wishlist editor UI, and removal of the old DreamSync server and many client pages. eID wallet QR/signing flow is refactored to use KeyManager. Web3-adapter internals are streamlined. Minor API tweaks in other platforms and mappings. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User as User (Browser)
participant Client as DreamSync Client (LoginScreen)
participant API as AuthController
participant SSE as SSE Stream
User->>Client: Open /login
Client->>API: GET /api/auth/offer
API-->>Client: { offer, sessionId }
Note over Client: Show QR (offer)
User->>API: POST /api/auth/login { ename, session }
API-->>SSE: emit(session, { token, user })
Client->>API: GET /api/auth/sessions/{sessionId} (SSE)
SSE-->>Client: { token, user }
Client->>Client: Store token, userId
Client-->>User: Redirect to /
sequenceDiagram
autonumber
participant Svelte as scan-qr +page.svelte
participant KMF as KeyManagerFactory
participant KM as KeyManager
participant Backend as Redirect URI / auth endpoint
Svelte->>KMF: getKeyManagerForContext(ctx)
KMF-->>Svelte: KeyManager
Svelte->>KM: exists(ename)?
alt Missing key
Svelte->>KM: generate(ename)
end
Svelte->>KM: getPublicKey(ename) / get W3ID
Svelte->>KM: signPayload(ename, payload)
Svelte->>Backend: POST { ename, w3id, signature, session }
Backend-->>Svelte: 200/redirect
Estimated code review effort🎯 5 (Critical) | ⏱️ ~180 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches and finishing touches❌ Failed checks (2 warnings, 1 inconclusive)
📜 Recent review detailsConfiguration used: CodeRabbit UI Review profile: CHILL Plan: Pro ⛔ Files ignored due to path filters (9)
📒 Files selected for processing (99)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 37
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
platforms/blabsy-w3ds-auth-api/src/controllers/AuthController.ts (1)
62-62
: Remove log that exposes authentication tokens.Logging the Firebase custom token is a critical security vulnerability. These tokens are authentication credentials that can be used to impersonate users and must never appear in logs.
Apply this diff to remove the token log:
const token = await auth().createCustomToken(ename); - console.log(token);
platforms/registry/src/index.ts (1)
109-120
: Filter undefined environment variables from the platforms array.If
VITE_DREAMSYNC_BASE_URL
(or any other environment variable) is not set, the array will containundefined
values. This can break consumers expecting only valid URL strings.Apply this diff to filter out undefined values:
server.get("/platforms", async (request, reply) => { - const platforms = [ + const platforms = [ process.env.PUBLIC_PICTIQUE_BASE_URL, process.env.PUBLIC_BLABSY_BASE_URL, process.env.PUBLIC_GROUP_CHARTER_BASE_URL, process.env.PUBLIC_CERBERUS_BASE_URL, process.env.PUBLIC_EVOTING_BASE_URL, process.env.VITE_DREAMSYNC_BASE_URL - ] + ].filter((url): url is string => url !== undefined && url !== null && url !== "") return platforms });platforms/pictique-api/src/web3adapter/watchers/subscriber.ts (2)
201-226
: Fix async error handling in setTimeout callback.The try-catch wraps the
setTimeout
call but doesn't catch errors that occur inside the async callback. Errors thrown in the async code withinsetTimeout
(lines 203-221) will be unhandled, potentially causing the process to crash or leading to silent failures.Apply this pattern to properly handle async errors:
- try { - setTimeout(async () => { - try { - let globalId = await this.adapter.mappingDb.getGlobalId( - entity.id - ); - globalId = globalId ?? ""; - - if (this.adapter.lockedIds.includes(globalId)) { - console.log("locked skipping ", globalId); - return; - } - - console.log( - "sending packet for global Id", - globalId, - entity.id - ); - const envelope = await this.adapter.handleChange({ - data, - tableName: tableName.toLowerCase(), - }); - } finally { - // Always remove the pending change flag - this.pendingChanges.delete(changeKey); - } - }, 3_000); - } catch (error) { - console.error(`Error processing change for ${tableName}:`, error); - // Remove the pending change flag on error - this.pendingChanges.delete(changeKey); - } + setTimeout(async () => { + try { + let globalId = await this.adapter.mappingDb.getGlobalId( + entity.id + ); + globalId = globalId ?? ""; + + if (this.adapter.lockedIds.includes(globalId)) { + console.log("locked skipping ", globalId); + return; + } + + console.log( + "sending packet for global Id", + globalId, + entity.id + ); + const envelope = await this.adapter.handleChange({ + data, + tableName: tableName.toLowerCase(), + }); + } catch (error) { + console.error(`Error processing change for ${tableName}:`, error); + } finally { + // Always remove the pending change flag + this.pendingChanges.delete(changeKey); + } + }, 3_000);
276-303
: Fix async error handling in setTimeout callback.Same issue as in
handleChange
: the try-catch structure doesn't properly handle async errors within thesetTimeout
callback.Apply this pattern:
- try { - setTimeout(async () => { - try { - let globalId = await this.adapter.mappingDb.getGlobalId( - entity.id - ); - globalId = globalId ?? ""; - - if (this.adapter.lockedIds.includes(globalId)) { - console.log("locked skipping ", globalId); - return; - } - - console.log( - "sending packet for global Id", - globalId, - entity.id - ); - - const tableName = `${junctionInfo.entity.toLowerCase()}s`; - await this.adapter.handleChange({ - data: this.entityToPlain(parentEntity), - tableName, - }); - } finally { - // Always remove the pending change flag - this.pendingChanges.delete(changeKey); - } - }, 3_000); - } catch (error) { - console.error(error); - // Remove the pending change flag on error - this.pendingChanges.delete(changeKey); - } + setTimeout(async () => { + try { + let globalId = await this.adapter.mappingDb.getGlobalId( + entity.id + ); + globalId = globalId ?? ""; + + if (this.adapter.lockedIds.includes(globalId)) { + console.log("locked skipping ", globalId); + return; + } + + console.log( + "sending packet for global Id", + globalId, + entity.id + ); + + const tableName = `${junctionInfo.entity.toLowerCase()}s`; + await this.adapter.handleChange({ + data: this.entityToPlain(parentEntity), + tableName, + }); + } catch (error) { + console.error(error); + } finally { + // Always remove the pending change flag + this.pendingChanges.delete(changeKey); + } + }, 3_000);
🧹 Nitpick comments (18)
platforms/dreamSync/vite.config.ts (1)
6-7
: Path calculation is correct; consider removing the debug log.The
envDir
path correctly resolves to the project root (two directories up fromplatforms/dreamSync/
), which is appropriate for loading environment files in a monorepo structure. However, theconsole.log
statement will execute every time the Vite config is loaded, which could be verbose.If the logging is no longer needed for debugging, consider removing it:
const envDir = path.resolve(import.meta.dirname, "../../"); -console.log("🔍 Vite envDir:", envDir);
platforms/dreamSync/client/src/lib/utils/mobile-detection.ts (1)
34-50
: Eliminate duplicate user agent detection logic.The user agent detection code here duplicates the logic from
isMobileDevice()
(lines 7-13). This creates maintenance burden if detection patterns need updating.Consider refactoring to reuse the existing detection:
export function getAppStoreLink(): string { - if (typeof window === 'undefined') { + if (typeof window === 'undefined' || /android/i.test(navigator.userAgent || navigator.vendor)) { return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; } - const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera; - - if (/android/i.test(userAgent)) { - return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; - } - - if (/iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream) { + if (/iPad|iPhone|iPod/.test(navigator.userAgent) && !(window as any).MSStream) { return "https://apps.apple.com/in/app/eid-for-w3ds/id6747748667"; } return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; }</review_comment_end>
platforms/dreamsync-api/src/database/migrations/1760045198484-migration.ts (2)
7-7
: Add unique constraint on email and consider indexing frequently queried fields.The
handle
,ename
lack indices, which may impact query performance.Apply these changes:
- Add a unique constraint on email:
await queryRunner.query(`CREATE UNIQUE INDEX "IDX_users_email" ON "users" ("email") WHERE "email" IS NOT NULL`);
- Add indices on frequently queried fields:
await queryRunner.query(`CREATE INDEX "IDX_users_handle" ON "users" ("handle") WHERE "handle" IS NOT NULL`); await queryRunner.query(`CREATE INDEX "IDX_users_ename" ON "users" ("ename") WHERE "ename" IS NOT NULL`);
- Similarly, consider adding indices on
group.name
andgroup.ename
for better query performance.Don't forget to update the down migration to drop these indices.
8-8
: Add missing foreign keys and clarify voteId usage
- No
votes
table or FK onmessages.voteId
found—either create avotes
table and addFOREIGN KEY("voteId") REFERENCES votes(id)
with appropriateON DELETE
action, or drop thevoteId
column if unused.- Add FK constraints on
senderId
andgroupId
in this migration, usingON DELETE CASCADE
orSET NULL
per your retention policy.platforms/dreamSync/client/src/components/wysiwyg-editor.tsx (3)
21-29
: Add error handling to the HTML-to-Markdown conversion.If
turndown
encounters malformed HTML or throws an error, the function will crash without graceful degradation.Apply this diff:
function htmlToMarkdown(html: string): string { + try { const turndownService = new TurndownService({ headingStyle: 'atx', bulletListMarker: '-', codeBlockStyle: 'fenced', }) return turndownService.turndown(html) + } catch (error) { + console.error('Failed to convert HTML to Markdown:', error) + return html // Fallback to returning the HTML + } }
46-50
: Consider debouncing the onChange callback to improve performance.The
onChange
callback fires on every keystroke, which triggers Markdown conversion and parent component updates. For large documents, this can cause performance issues.Consider using a debounced version of onChange or moving the conversion to a separate save action:
import { useMemo } from 'react'; import debounce from 'lodash.debounce'; export default function WysiwygEditor({ content, onChange, placeholder = "Enter text...", className }: WysiwygEditorProps) { const debouncedOnChange = useMemo( () => debounce((markdown: string) => onChange(markdown), 300), [onChange] ); const editor = useEditor({ // ... extensions onUpdate: ({ editor }) => { const html = editor.getHTML(); const markdown = htmlToMarkdown(html); debouncedOnChange(markdown); }, // ... rest }); // ... }
10-11
: Remove redundantasync: false
configuration for marked.
marked
is synchronous by default, somarked.use({ async: false })
can be removed.platforms/dreamSync/client/src/components/auth/login-screen.tsx (1)
38-61
: Add timeout and reconnection logic for the SSE connection.The EventSource connection has no timeout, which means users could wait indefinitely if the server doesn't respond. Additionally, there's no automatic reconnection on network errors.
Apply this diff:
useEffect(() => { if (!sessionId) return; + + let timeoutId: NodeJS.Timeout | null = null; const eventSource = new EventSource( `${import.meta.env.VITE_DREAMSYNC_BASE_URL || "http://localhost:8888"}/api/auth/sessions/${sessionId}` ); + + // Set a timeout for the authentication + timeoutId = setTimeout(() => { + eventSource.close(); + console.error("Authentication timeout"); + // Optionally show user feedback here + }, 60000); // 60 second timeout eventSource.onmessage = (event) => { try { const data = JSON.parse(event.data); if (data.user && data.token) { + if (timeoutId) clearTimeout(timeoutId); setIsConnecting(true); localStorage.setItem("dreamsync_token", data.token); localStorage.setItem("dreamsync_user_id", data.user.id); window.location.href = "/"; } } catch (error) { console.error("Error parsing SSE data:", error); } }; eventSource.onerror = (error) => { console.error("SSE Error:", error); + if (timeoutId) clearTimeout(timeoutId); eventSource.close(); }; return () => { + if (timeoutId) clearTimeout(timeoutId); eventSource.close(); }; }, [sessionId, login]);platforms/dreamSync/client/src/lib/auth-context.tsx (2)
59-71
: Add input validation and loading state for the login function.The
login
function doesn't validate theename
parameter or provide loading state, which could lead to poor UX and unexpected errors.Apply this diff:
+ const [isLoggingIn, setIsLoggingIn] = useState(false); + const login = async (ename: string) => { + if (!ename || ename.trim() === "") { + throw new Error("ename is required"); + } + + setIsLoggingIn(true); try { const response = await apiClient.post("/api/auth", { ename }); const { token, user: userData } = response.data; setAuthToken(token); setAuthId(userData.id); setUser(userData); } catch (error) { console.error("Login failed:", error); throw error; + } finally { + setIsLoggingIn(false); } };Then expose
isLoggingIn
in the context:interface AuthContextType { user: User | null; isAuthenticated: boolean; isLoading: boolean; + isLoggingIn: boolean; login: (ename: string) => Promise<void>; logout: () => void; }
73-76
: Consider adding server-side session invalidation.The
logout
function only clears client-side state but doesn't notify the server to invalidate the session. This means the token remains valid until it expires naturally.If your backend supports session invalidation, consider calling a logout endpoint:
const logout = async () => { try { await apiClient.post("/api/auth/logout"); } catch (error) { console.error("Server logout failed:", error); // Continue with client-side logout even if server call fails } finally { clearAuth(); setUser(null); } };Note: This would require making
logout
async and updating all consumers.platforms/dreamSync/client/src/lib/apiClient.ts (2)
12-17
: Add timeout configuration to prevent hanging requests.The API client lacks a timeout configuration, which can cause requests to hang indefinitely if the server is unresponsive. This degrades user experience and can exhaust connection pools.
Apply this diff to add a reasonable timeout:
export const apiClient = axios.create({ baseURL, + timeout: 30000, // 30 seconds headers: { "Content-Type": "application/json", }, });
34-44
: Consider using router-based navigation instead ofwindow.location.href
.Using
window.location.href
for navigation causes a full page reload, which disrupts the SPA experience and loses application state. Consider injecting a router-based navigation function or emitting an event that the auth context can handle.For a cleaner architecture, you could:
- Create a custom event that the
AuthProvider
listens for- Have the
AuthProvider
handle the logout logic and navigation- Dispatch that event from the interceptor
Example approach:
// In interceptor if (error.response?.status === 401) { localStorage.removeItem("dreamsync_token"); localStorage.removeItem("dreamsync_user_id"); window.dispatchEvent(new CustomEvent('auth:unauthorized')); }Then in your
AuthProvider
, listen for this event and use proper router navigation.Alternatively, if you prefer to keep the current approach for simplicity, the existing implementation is functional but less optimal for SPA patterns.
platforms/dreamSync/client/src/pages/wishlist-editor.tsx (3)
47-84
: Consider making title editable and adding privacy control.The wishlist title is hardcoded to "My Dream Wishlist" and
isPublic
is alwaystrue
. This limits user control over their wishlist. Consider adding UI controls for these fields.You could add state for title and privacy:
const [wishlistTitle, setWishlistTitle] = useState("My Dream Wishlist"); const [isPublic, setIsPublic] = useState(true);Then add input fields in the UI and use these values in the save handler:
response = await apiClient.put(`/api/wishlists/${existingWishlist.id}`, { - title: "My Dream Wishlist", + title: wishlistTitle, content: wishlistContent, - isPublic: true + isPublic: isPublic });This provides users with more flexibility in managing their wishlists.
74-74
: Useunknown
instead ofany
for error type.TypeScript best practices recommend using
unknown
for caught errors and narrowing the type as needed. This provides better type safety.Apply this diff:
- } catch (error: any) { + } catch (error: unknown) { console.error("Error saving wishlist:", error);
26-45
: Remove sorting concern – server orders byupdatedAt DESC
; add user-facing error toast.The backend’s
WishlistService.getUserWishlists
usesorder: { updatedAt: "DESC" }
, soresponse.data[0]
is already the latest wishlist. Enhance the catch block to notify users on failure:} catch (error) { console.error("Error loading existing wishlist:", error); + toast({ + title: "Error loading wishlist", + description: "Unable to fetch your wishlist. Please try again.", + variant: "destructive", + }); } finally {platforms/dreamsync-api/src/database/migrations/1760422131457-migration.ts (1)
7-7
: Consider using jsonb instead of json for PostgreSQL.The migration adds a
json
column type. If this is PostgreSQL (which appears likely given the broader codebase context), consider usingjsonb
instead for better performance and indexing capabilities. Thejsonb
type is more efficient for queries and supports indexing, whilejson
stores data as plain text.If using PostgreSQL, apply this diff:
- await queryRunner.query(`ALTER TABLE "group" ADD "originalMatchParticipants" json`); + await queryRunner.query(`ALTER TABLE "group" ADD "originalMatchParticipants" jsonb`);And update the down migration:
await queryRunner.query(`ALTER TABLE "group" DROP COLUMN "originalMatchParticipants"`);Note: Also update the corresponding entity definition in
Group.ts
fromtype: "json"
totype: "jsonb"
for consistency.platforms/dreamsync-api/src/database/entities/User.ts (1)
64-65
: Add missing definite assignment assertion for consistency.The
wishlists
relation is missing the definite assignment assertion (!
) that's used on other required relations throughout the entity. While this will still work at runtime, it creates inconsistency with the rest of the entity's property declarations.Apply this diff for consistency:
@OneToMany(() => Wishlist, (wishlist) => wishlist.user) - wishlists: Wishlist[]; + wishlists!: Wishlist[];platforms/dreamsync-api/src/controllers/UserController.ts (1)
50-64
: Leverage the database search instead of fetching every user
search
currently loads the entire user table into memory and filters it in Node. That will thrash memory and degrade latency once the user base grows, and it ignores any DB-level filtering we already wrote inUserService.searchUsers
. Please delegate the query to the service so the database does the heavy lifting:- const users = await this.userService.getAllUsers(); - const filteredUsers = users.filter(user => - user.name?.toLowerCase().includes(q.toLowerCase()) || - user.handle?.toLowerCase().includes(q.toLowerCase()) || - user.ename?.toLowerCase().includes(q.toLowerCase()) - ); - - res.json(filteredUsers.map(user => ({ + const users = await this.userService.searchUsers(q); + + res.json(users.map(user => ({ id: user.id, ename: user.ename, name: user.name, handle: user.handle, avatarUrl: user.avatarUrl, isVerified: user.isVerified, })));
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (5)
infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet.xcodeproj/project.pbxproj
is excluded by!**/gen/**
infrastructure/eid-wallet/src-tauri/gen/apple/eid-wallet_iOS/Info.plist
is excluded by!**/gen/**
platforms/dreamSync/client/public/W3DS.svg
is excluded by!**/*.svg
platforms/dreamSync/package-lock.json
is excluded by!**/package-lock.json
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (94)
infrastructure/eVoting/src/components/signing-interface.tsx
(0 hunks)infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte
(6 hunks)platforms/blabsy-w3ds-auth-api/src/controllers/AuthController.ts
(1 hunks)platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts
(3 hunks)platforms/dreamSync/client/src/App.tsx
(3 hunks)platforms/dreamSync/client/src/components/auth/login-screen.tsx
(1 hunks)platforms/dreamSync/client/src/components/auth/protected-route.tsx
(1 hunks)platforms/dreamSync/client/src/components/wysiwyg-editor.tsx
(1 hunks)platforms/dreamSync/client/src/hooks/useAuth.ts
(1 hunks)platforms/dreamSync/client/src/lib/apiClient.ts
(1 hunks)platforms/dreamSync/client/src/lib/auth-context.tsx
(1 hunks)platforms/dreamSync/client/src/lib/authUtils.ts
(1 hunks)platforms/dreamSync/client/src/lib/utils/mobile-detection.ts
(1 hunks)platforms/dreamSync/client/src/pages/dashboard.tsx
(0 hunks)platforms/dreamSync/client/src/pages/groups.tsx
(0 hunks)platforms/dreamSync/client/src/pages/login.tsx
(1 hunks)platforms/dreamSync/client/src/pages/matches-new.tsx
(0 hunks)platforms/dreamSync/client/src/pages/profile.tsx
(0 hunks)platforms/dreamSync/client/src/pages/suggestions.tsx
(0 hunks)platforms/dreamSync/client/src/pages/wishlist-editor.tsx
(1 hunks)platforms/dreamSync/client/src/pages/wishlist-item.tsx
(0 hunks)platforms/dreamSync/client/src/pages/wishlist.tsx
(0 hunks)platforms/dreamSync/package.json
(1 hunks)platforms/dreamSync/server/aiSuggestionsService.ts
(0 hunks)platforms/dreamSync/server/auth.ts
(0 hunks)platforms/dreamSync/server/db.ts
(0 hunks)platforms/dreamSync/server/ensureFullyPopulatedData.ts
(0 hunks)platforms/dreamSync/server/fixPasswords.ts
(0 hunks)platforms/dreamSync/server/generateTestSuggestions.ts
(0 hunks)platforms/dreamSync/server/index.ts
(0 hunks)platforms/dreamSync/server/openai.ts
(0 hunks)platforms/dreamSync/server/replitAuth.ts
(0 hunks)platforms/dreamSync/server/routes.ts
(0 hunks)platforms/dreamSync/server/seedComprehensiveData.ts
(0 hunks)platforms/dreamSync/server/seedData.ts
(0 hunks)platforms/dreamSync/server/seedEnhancedData.ts
(0 hunks)platforms/dreamSync/server/seedExtensiveData.ts
(0 hunks)platforms/dreamSync/server/storage.ts
(0 hunks)platforms/dreamSync/server/vite.ts
(0 hunks)platforms/dreamSync/vite.config.ts
(2 hunks)platforms/dreamsync-api/README.md
(1 hunks)platforms/dreamsync-api/package.json
(1 hunks)platforms/dreamsync-api/reset.sh
(1 hunks)platforms/dreamsync-api/src/auth.ts
(1 hunks)platforms/dreamsync-api/src/controllers/AuthController.ts
(1 hunks)platforms/dreamsync-api/src/controllers/MatchController.ts
(1 hunks)platforms/dreamsync-api/src/controllers/UserController.ts
(1 hunks)platforms/dreamsync-api/src/controllers/WebhookController.ts
(1 hunks)platforms/dreamsync-api/src/controllers/WishlistController.ts
(1 hunks)platforms/dreamsync-api/src/database/data-source.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/Group.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/Match.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/Message.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/User.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/UserEVaultMapping.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/WebhookProcessing.ts
(1 hunks)platforms/dreamsync-api/src/database/entities/Wishlist.ts
(1 hunks)platforms/dreamsync-api/src/database/migrations/1760045198484-migration.ts
(1 hunks)platforms/dreamsync-api/src/database/migrations/1760080210824-migration.ts
(1 hunks)platforms/dreamsync-api/src/database/migrations/1760087325046-AddUserEVaultMapping.ts
(1 hunks)platforms/dreamsync-api/src/database/migrations/1760087896024-AddMatchConsentFields.ts
(1 hunks)platforms/dreamsync-api/src/database/migrations/1760422131457-migration.ts
(1 hunks)platforms/dreamsync-api/src/database/migrations/1760427215447-migration.ts
(1 hunks)platforms/dreamsync-api/src/index.ts
(1 hunks)platforms/dreamsync-api/src/middleware/auth.ts
(1 hunks)platforms/dreamsync-api/src/services/AIMatchingService.ts
(1 hunks)platforms/dreamsync-api/src/services/ConsentService.ts
(1 hunks)platforms/dreamsync-api/src/services/GroupService.ts
(1 hunks)platforms/dreamsync-api/src/services/MatchNotificationService.ts
(1 hunks)platforms/dreamsync-api/src/services/MatchingJob.ts
(1 hunks)platforms/dreamsync-api/src/services/MatchingService.ts
(1 hunks)platforms/dreamsync-api/src/services/MessageService.ts
(1 hunks)platforms/dreamsync-api/src/services/PlatformEVaultService.ts
(1 hunks)platforms/dreamsync-api/src/services/SharedMatchingService.ts
(1 hunks)platforms/dreamsync-api/src/services/UserService.ts
(1 hunks)platforms/dreamsync-api/src/services/WebhookProcessingService.ts
(1 hunks)platforms/dreamsync-api/src/services/WishlistService.ts
(1 hunks)platforms/dreamsync-api/src/types/express.d.ts
(1 hunks)platforms/dreamsync-api/src/utils/jwt.ts
(1 hunks)platforms/dreamsync-api/src/utils/typeorm-adapter.ts
(1 hunks)platforms/dreamsync-api/src/web3adapter/index.ts
(1 hunks)platforms/dreamsync-api/src/web3adapter/mappings/group.mapping.json
(1 hunks)platforms/dreamsync-api/src/web3adapter/mappings/message.mapping.json
(1 hunks)platforms/dreamsync-api/src/web3adapter/mappings/user.mapping.json
(1 hunks)platforms/dreamsync-api/src/web3adapter/watchers/subscriber.ts
(1 hunks)platforms/dreamsync-api/test-matchmaking-mock.ts
(1 hunks)platforms/dreamsync-api/test-matchmaking.ts
(1 hunks)platforms/dreamsync-api/tsconfig.json
(1 hunks)platforms/marketplace/package.json
(1 hunks)platforms/pictique-api/package.json
(1 hunks)platforms/pictique-api/src/controllers/WebhookController.ts
(1 hunks)platforms/pictique-api/src/web3adapter/mappings/chat.mapping.json
(1 hunks)platforms/pictique-api/src/web3adapter/watchers/subscriber.ts
(1 hunks)platforms/registry/src/index.ts
(1 hunks)
💤 Files with no reviewable changes (24)
- platforms/dreamSync/client/src/pages/groups.tsx
- platforms/dreamSync/server/fixPasswords.ts
- platforms/dreamSync/client/src/pages/wishlist.tsx
- platforms/dreamSync/server/seedComprehensiveData.ts
- platforms/dreamSync/server/replitAuth.ts
- platforms/dreamSync/client/src/pages/matches-new.tsx
- platforms/dreamSync/client/src/pages/profile.tsx
- platforms/dreamSync/client/src/pages/wishlist-item.tsx
- platforms/dreamSync/server/routes.ts
- platforms/dreamSync/server/generateTestSuggestions.ts
- platforms/dreamSync/server/seedEnhancedData.ts
- platforms/dreamSync/server/ensureFullyPopulatedData.ts
- platforms/dreamSync/server/storage.ts
- platforms/dreamSync/server/seedExtensiveData.ts
- platforms/dreamSync/server/index.ts
- platforms/dreamSync/server/seedData.ts
- platforms/dreamSync/server/openai.ts
- platforms/dreamSync/server/vite.ts
- platforms/dreamSync/client/src/pages/dashboard.tsx
- platforms/dreamSync/server/db.ts
- infrastructure/eVoting/src/components/signing-interface.tsx
- platforms/dreamSync/server/aiSuggestionsService.ts
- platforms/dreamSync/client/src/pages/suggestions.tsx
- platforms/dreamSync/server/auth.ts
🧰 Additional context used
🧬 Code graph analysis (34)
platforms/dreamSync/client/src/lib/auth-context.tsx (1)
platforms/dreamSync/client/src/lib/apiClient.ts (1)
apiClient
(12-17)
platforms/dreamsync-api/src/database/entities/Group.ts (3)
platforms/dreamsync-api/src/database/entities/Match.ts (1)
Entity
(26-105)platforms/dreamsync-api/src/database/entities/User.ts (1)
Entity
(13-75)platforms/dreamsync-api/src/database/entities/Message.ts (1)
Entity
(12-40)
platforms/dreamsync-api/src/services/UserService.ts (1)
platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/database/entities/User.ts (4)
platforms/dreamsync-api/src/database/entities/Group.ts (1)
Entity
(14-81)platforms/dreamsync-api/src/database/entities/Match.ts (1)
Entity
(26-105)platforms/dreamsync-api/src/database/entities/Wishlist.ts (1)
Entity
(14-54)platforms/dreamsync-api/src/database/entities/Message.ts (1)
Entity
(12-40)
platforms/dreamsync-api/src/database/entities/Match.ts (2)
platforms/dreamsync-api/src/database/entities/User.ts (1)
Entity
(13-75)platforms/dreamsync-api/src/database/entities/Wishlist.ts (1)
Entity
(14-54)
platforms/dreamsync-api/src/services/ConsentService.ts (2)
platforms/dreamsync-api/src/services/GroupService.ts (1)
GroupService
(6-239)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/database/data-source.ts (1)
infrastructure/web3-adapter/src/logging/transport.js (1)
envPath
(10-10)
platforms/dreamsync-api/src/services/WebhookProcessingService.ts (1)
platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/auth.ts (2)
platforms/dreamsync-api/src/utils/typeorm-adapter.ts (1)
typeormAdapter
(4-6)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/database/entities/Message.ts (2)
platforms/dreamsync-api/src/database/entities/Group.ts (1)
Entity
(14-81)platforms/dreamsync-api/src/database/entities/User.ts (1)
Entity
(13-75)
platforms/dreamSync/client/src/pages/wishlist-editor.tsx (3)
platforms/dreamSync/client/src/lib/auth-context.tsx (1)
useAuth
(85-91)platforms/dreamSync/client/src/lib/apiClient.ts (1)
apiClient
(12-17)platforms/dreamSync/client/src/components/wysiwyg-editor.tsx (1)
WysiwygEditor
(37-197)
platforms/dreamsync-api/test-matchmaking.ts (1)
platforms/dreamsync-api/src/services/AIMatchingService.ts (1)
AIMatchingService
(10-700)
platforms/dreamsync-api/src/services/MatchNotificationService.ts (3)
platforms/dreamsync-api/src/services/UserService.ts (1)
UserService
(4-69)platforms/dreamsync-api/src/services/GroupService.ts (1)
GroupService
(6-239)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/database/entities/Wishlist.ts (2)
platforms/dreamsync-api/src/database/entities/Match.ts (1)
Entity
(26-105)platforms/dreamsync-api/src/database/entities/User.ts (1)
Entity
(13-75)
platforms/dreamsync-api/src/web3adapter/watchers/subscriber.ts (4)
platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts (1)
adapter
(73-78)platforms/pictique-api/src/web3adapter/watchers/subscriber.ts (1)
adapter
(17-22)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)platforms/evoting-api/src/web3adapter/watchers/subscriber.ts (1)
PostgresSubscriber
(30-468)
platforms/dreamsync-api/src/middleware/auth.ts (2)
platforms/dreamsync-api/src/utils/jwt.ts (1)
verifyToken
(9-11)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/services/MatchingService.ts (1)
platforms/dreamsync-api/src/services/SharedMatchingService.ts (3)
MatchResult
(3-11)WishlistData
(13-22)MatchingService
(24-176)
platforms/dreamsync-api/src/index.ts (9)
platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)platforms/dreamsync-api/src/services/PlatformEVaultService.ts (1)
PlatformEVaultService
(41-313)platforms/dreamsync-api/src/services/MatchingJob.ts (1)
MatchingJob
(3-75)platforms/dreamsync-api/src/controllers/UserController.ts (1)
UserController
(4-131)platforms/dreamsync-api/src/controllers/AuthController.ts (1)
AuthController
(7-104)platforms/dreamsync-api/src/controllers/WebhookController.ts (1)
WebhookController
(13-360)platforms/dreamsync-api/src/controllers/WishlistController.ts (1)
WishlistController
(4-131)platforms/dreamsync-api/src/controllers/MatchController.ts (1)
MatchController
(5-99)platforms/dreamsync-api/src/middleware/auth.ts (2)
authMiddleware
(6-38)authGuard
(40-45)
platforms/dreamsync-api/src/services/GroupService.ts (1)
platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/test-matchmaking-mock.ts (1)
platforms/dreamsync-api/src/services/MatchingService.ts (3)
MatchingService
(36-280)WishlistData
(15-24)MatchResult
(3-13)
platforms/dreamSync/client/src/components/auth/protected-route.tsx (2)
platforms/dreamSync/client/src/lib/auth-context.tsx (1)
useAuth
(85-91)platforms/dreamSync/client/src/components/auth/login-screen.tsx (1)
LoginScreen
(8-163)
platforms/dreamsync-api/src/services/SharedMatchingService.ts (1)
platforms/dreamsync-api/src/services/MatchingService.ts (3)
MatchResult
(3-13)WishlistData
(15-24)MatchingService
(36-280)
platforms/dreamsync-api/src/services/PlatformEVaultService.ts (3)
platforms/dreamsync-api/src/index.ts (1)
PlatformEVaultService
(129-129)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)infrastructure/web3-adapter/src/index.js (5)
registryEntropy
(62-62)now
(118-118)attempt
(131-131)client
(137-137)delay
(167-167)
platforms/dreamsync-api/src/services/WishlistService.ts (1)
platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/services/AIMatchingService.ts (3)
platforms/dreamsync-api/src/services/MatchingService.ts (4)
MatchingService
(36-280)WishlistData
(15-24)GroupData
(26-34)MatchResult
(3-13)platforms/dreamsync-api/src/services/MatchNotificationService.ts (1)
MatchNotificationService
(10-1061)platforms/dreamsync-api/src/database/data-source.ts (1)
AppDataSource
(29-29)
platforms/dreamsync-api/src/services/MatchingJob.ts (1)
platforms/dreamsync-api/src/services/AIMatchingService.ts (1)
AIMatchingService
(10-700)
platforms/dreamsync-api/src/controllers/WebhookController.ts (4)
platforms/dreamsync-api/src/services/GroupService.ts (1)
GroupService
(6-239)platforms/dreamsync-api/src/services/ConsentService.ts (1)
ConsentService
(9-1604)platforms/dreamsync-api/src/services/WebhookProcessingService.ts (1)
WebhookProcessingService
(6-140)platforms/dreamsync-api/src/web3adapter/watchers/subscriber.ts (1)
adapter
(15-20)
platforms/dreamsync-api/src/database/entities/UserEVaultMapping.ts (1)
platforms/dreamsync-api/src/database/entities/Match.ts (1)
Entity
(26-105)
platforms/dreamSync/client/src/components/auth/login-screen.tsx (3)
platforms/dreamSync/client/src/lib/auth-context.tsx (1)
useAuth
(85-91)platforms/dreamSync/client/src/lib/apiClient.ts (1)
apiClient
(12-17)platforms/dreamSync/client/src/lib/utils/mobile-detection.ts (3)
getAppStoreLink
(34-50)isMobileDevice
(1-26)getDeepLinkUrl
(28-32)
platforms/dreamsync-api/src/controllers/UserController.ts (1)
platforms/dreamsync-api/src/services/UserService.ts (1)
UserService
(4-69)
platforms/dreamsync-api/src/controllers/AuthController.ts (3)
platforms/blabsy-w3ds-auth-api/src/controllers/AuthController.ts (1)
AuthController
(5-71)platforms/dreamsync-api/src/services/UserService.ts (1)
UserService
(4-69)platforms/dreamsync-api/src/utils/jwt.ts (1)
signToken
(5-7)
platforms/dreamsync-api/src/controllers/WishlistController.ts (1)
platforms/dreamsync-api/src/services/WishlistService.ts (1)
WishlistService
(6-131)
platforms/dreamSync/client/src/App.tsx (2)
platforms/dreamSync/client/src/pages/wishlist-editor.tsx (1)
WishlistEditor
(17-187)platforms/dreamSync/client/src/lib/auth-context.tsx (1)
AuthProvider
(33-83)
platforms/dreamsync-api/src/controllers/MatchController.ts (1)
platforms/dreamsync-api/src/services/AIMatchingService.ts (1)
AIMatchingService
(10-700)
🪛 ast-grep (0.39.6)
platforms/dreamsync-api/src/services/MatchNotificationService.ts
[warning] 429-429: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\{${userADisplayName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\}
, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 435-435: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\{${userADisplayName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\}
, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 443-443: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\{${userBDisplayName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\}
, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
[warning] 449-449: Regular expression constructed from variable input detected. This can lead to Regular Expression Denial of Service (ReDoS) attacks if the variable contains malicious patterns. Use libraries like 'recheck' to validate regex safety or use static patterns.
Context: new RegExp(\\{${userBDisplayName.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\}
, 'g')
Note: [CWE-1333] Inefficient Regular Expression Complexity [REFERENCES]
- https://owasp.org/www-community/attacks/Regular_expression_Denial_of_Service_-_ReDoS
- https://cwe.mitre.org/data/definitions/1333.html
(regexp-from-variable)
🪛 LanguageTool
platforms/dreamsync-api/README.md
[grammar] ~3-~3: There might be a mistake here.
Context: ...mSync platform, cloned from evoting-api with focus on user management, groups, and m...
(QB_NEW_EN)
[grammar] ~7-~7: There might be a mistake here.
Context: ...rofiles, authentication, and user search - Group Management: Group creation, memb...
(QB_NEW_EN)
[grammar] ~8-~8: There might be a mistake here.
Context: ...creation, membership, and administration - Messaging: Group messaging with system...
(QB_NEW_EN)
[grammar] ~9-~9: There might be a mistake here.
Context: ...up messaging with system message support - Web3 Integration: Web3Adapter integrat...
(QB_NEW_EN)
[grammar] ~10-~10: There might be a mistake here.
Context: ...n for decentralized data synchronization - Authentication: JWT-based authenticati...
(QB_NEW_EN)
[grammar] ~17-~17: There might be a mistake here.
Context: ...s with followers/following relationships - Group: Groups with members, admins, an...
(QB_NEW_EN)
[grammar] ~18-~18: There might be a mistake here.
Context: ...s with members, admins, and participants - Message: Messages within groups, inclu...
(QB_NEW_EN)
[grammar] ~94-~94: There might be a mistake here.
Context: ...ration for: - User data synchronization - Message synchronization (system messages...
(QB_NEW_EN)
[grammar] ~95-~95: There might be a mistake here.
Context: ...e synchronization (system messages only) - Group data synchronization ## Differenc...
(QB_NEW_EN)
[grammar] ~102-~102: There might be a mistake here.
Context: ...uses on: - User management and profiles - Group functionality - Basic messaging - ...
(QB_NEW_EN)
[grammar] ~103-~103: There might be a mistake here.
Context: ...ement and profiles - Group functionality - Basic messaging - Web3Adapter integratio...
(QB_NEW_EN)
[grammar] ~104-~104: There might be a mistake here.
Context: ... - Group functionality - Basic messaging - Web3Adapter integration for users and me...
(QB_NEW_EN)
🔇 Additional comments (28)
platforms/dreamSync/vite.config.ts (1)
40-40
: LGTM! Correctly configures envDir for the monorepo.Explicitly setting
envDir
ensures that environment variables are loaded from the project root, which is the correct approach for a monorepo structure where multiple platforms share a common configuration.platforms/dreamsync-api/src/database/migrations/1760045198484-migration.ts (2)
16-24
: Clarify the distinction between group relationship tables.Three separate many-to-many tables exist for group-user relationships:
group_members
,group_admins
, andgroup_participants
. The semantic difference between "members" and "participants" is unclear.Verify whether:
- All three tables are necessary, or if roles could be consolidated into a single
group_members
table with arole
column- The distinction serves a specific business requirement
- Users can exist in multiple tables simultaneously (e.g., can an admin also be a participant?)
This design could lead to data inconsistencies if the relationships aren't mutually exclusive or if the business rules aren't clearly enforced at the application level.
39-70
: LGTM: Down migration correctly reverses the up migration.The down migration properly drops all constraints, indices, and tables in the correct reverse order, ensuring clean rollback.
platforms/registry/src/index.ts (1)
16-21
: Review the CORS wildcard configuration.The CORS configuration allows all origins (
origin: "*"
). While this may be intentional for a public registry service, ensure this aligns with your security requirements. If the registry handles sensitive operations or tokens, restrict origins to known platforms.platforms/dreamSync/client/src/pages/login.tsx (1)
1-5
: LGTM!The refactoring to delegate login logic to the
LoginScreen
component simplifies this file and improves separation of concerns.platforms/dreamSync/client/src/hooks/useAuth.ts (1)
1-5
: LGTM!Delegating to the centralized auth context improves maintainability and reduces duplication. The public interface remains unchanged.
platforms/dreamSync/client/src/components/auth/protected-route.tsx (1)
11-27
: LGTM!The authentication flow is correctly implemented with proper loading and unauthenticated state handling.
platforms/dreamSync/client/src/App.tsx (2)
44-49
: LGTM!The authentication provider is correctly positioned in the component hierarchy, wrapping all components that need auth state access.
34-34
: LGTM!Simplified routing to focus on the WishlistEditor aligns with the PR objectives.
platforms/dreamSync/client/src/components/auth/login-screen.tsx (1)
48-49
: Document the XSS risk of localStorage token storage.Storing authentication tokens in
localStorage
makes them vulnerable to XSS attacks. While this is a common pattern, ensure:
- Your Content Security Policy (CSP) is strict
- All user-generated content is properly sanitized
- You use httpOnly cookies for sensitive production environments
Based on learnings from security best practices, consider using httpOnly cookies for token storage in production to mitigate XSS risks.
platforms/dreamSync/client/src/lib/auth-context.tsx (2)
39-57
: LGTM!The initialization logic correctly handles token validation and gracefully clears auth state on errors.
85-91
: LGTM!The
useAuth
hook properly enforces usage within anAuthProvider
with a clear error message.platforms/dreamSync/client/src/pages/wishlist-editor.tsx (2)
90-101
: LGTM!The loading state provides good visual feedback with an animated spinner and clear messaging. The styling and user experience are well-implemented.
103-186
: LGTM! Well-structured UI with good visual hierarchy.The component UI is well-organized with clear sections, appropriate visual feedback, and helpful tips for users. The conditional rendering based on
existingWishlist
provides good context.One minor optional improvement: consider extracting the tips array as a constant for better maintainability:
const WISHLIST_TIPS = [ "Be specific about what you want and what you can offer", "Include both short-term and long-term goals", "Don't be afraid to dream big!", "Update your wishlist regularly as you grow and change" ];Then map over it in the render, but this is purely optional for code organization.
platforms/dreamSync/client/src/lib/authUtils.ts (2)
5-16
: LGTM! Token management functions are well-implemented.The token management functions are properly implemented with SSR safety checks in
getAuthToken()
. The localStorage keydreamsync_token
is consistent with the usage inapiClient.ts
.
18-34
: LGTM! ID management and clearAuth helper are well-implemented.The user ID management functions follow the same pattern as token management with proper SSR safety. The
clearAuth()
helper provides a convenient way to clear all authentication data, which is consistent with the logout flow inapiClient.ts
.platforms/dreamsync-api/src/web3adapter/mappings/group.mapping.json (1)
1-24
: LGTM! Consistent array mapping syntax.The mapping definitions use consistent array notation (
[].id
) for all user collection fields (admins
,participants
,members
), which provides clear and uniform data transformation rules for the web3 adapter.platforms/dreamsync-api/tsconfig.json (1)
1-23
: LGTM! Appropriate TypeScript configuration for TypeORM.The configuration correctly enables decorator support (
experimentalDecorators
,emitDecoratorMetadata
) required for TypeORM entities, andstrictPropertyInitialization: false
is a standard practice when using TypeORM's definite assignment assertions.platforms/dreamsync-api/src/database/entities/WebhookProcessing.ts (1)
1-38
: LGTM! Well-designed webhook deduplication entity.The entity correctly uses a unique index on
webhookId
(line 4) for idempotent webhook processing, and stores the full payload injsonb
(line 30) for debugging. The status lifecycle (pending
→processing
→completed
/failed
) is clear and appropriate.Consider implementing a cleanup strategy for old completed records to prevent unbounded growth (e.g., a scheduled job to delete records older than 30 days with status
completed
).platforms/dreamsync-api/src/database/entities/User.ts (1)
48-62
: LGTM! Self-referential many-to-many relations correctly configured.The
followers
andfollowing
relationships are properly set up with explicit join table configurations, correctly modeling the bidirectional follow relationships.platforms/dreamsync-api/src/web3adapter/mappings/user.mapping.json (1)
18-19
: No transformation syntax needed for followers/following
Subscriber watchers handleuser_followers
/user_following
viaownedJunctionTables
and emit updates for thefollowers
andfollowing
fields—simple mappings inuser.mapping.json
are correct.platforms/dreamsync-api/src/types/express.d.ts (1)
1-9
: LGTM!Standard Express namespace augmentation for attaching authenticated user information to requests. This pattern integrates well with the authentication middleware.
platforms/dreamsync-api/src/web3adapter/index.ts (1)
1-1
: LGTM!Clean barrel export pattern that exposes the adapter at the module level.
platforms/pictique-api/src/web3adapter/watchers/subscriber.ts (1)
9-9
: LGTM!Import path correctly updated to use the public "web3-adapter" package instead of the relative infrastructure path.
platforms/blabsy-w3ds-auth-api/src/controllers/WebhookController.ts (1)
49-49
: LGTM!The
admins
field is properly integrated into the Chat type and processing logic, with consistent parsing (extracting IDs from parentheses) and safe defaulting via nullish coalescing.Also applies to: 291-293, 309-309
platforms/dreamsync-api/src/web3adapter/mappings/message.mapping.json (1)
1-15
: LGTM!The mapping configuration follows the web3-adapter schema conventions. Ensure runtime validation confirms that the relationship syntax (e.g.,
users(sender.id)
,groups(group.id)
) aligns with the adapter's mapping engine expectations.platforms/dreamsync-api/src/auth.ts (1)
5-11
: LGTM!Standard
betterAuth
initialization with appropriate configuration for email/password auth and TypeORM adapter integration. The localhost fallback fortrustedOrigins
is suitable for development.platforms/dreamsync-api/README.md (1)
1-107
: LGTM!Comprehensive documentation covering features, setup, environment variables, and API endpoints. The static analysis warnings about list formatting are pedantic—the current markdown is widely supported and readable.
// 🔐 Get the real public key for voter identification using KeyManager | ||
let voterPublicKey: string; | ||
try { | ||
await generate("default"); | ||
console.log( | ||
"✅ Default key generated/verified for blind voting", | ||
); | ||
} catch (edit) { | ||
console.log( | ||
"Default key already exists or generation failed:", | ||
edit, | ||
); | ||
} | ||
// Get the appropriate key manager for blind voting | ||
const keyManager = | ||
await KeyManagerFactory.getKeyManagerForContext( | ||
vault.ename, | ||
"signing", | ||
); | ||
|
||
// Get the public key | ||
voterPublicKey = await getPublicKey("default"); | ||
console.log("🔑 Voter public key retrieved:", voterPublicKey); | ||
} catch (error) { | ||
console.error("Failed to get cryptographic public key:", error); | ||
// Fallback to ename if crypto fails | ||
voterPublicKey = vault.ename || "unknown_public_key"; | ||
} | ||
// Ensure the key exists | ||
if (!(await keyManager.exists(vault.ename))) { | ||
await keyManager.generate(vault.ename); | ||
} | ||
|
||
// Dynamically import the blindvote library | ||
const { VotingSystem } = await import("blindvote"); | ||
// Get the W3ID (public key) | ||
const w3idResult = await keyManager.getPublicKey(vault.ename); | ||
if (!w3idResult) { | ||
throw new Error("Failed to get W3ID"); | ||
} | ||
voterPublicKey = w3idResult; | ||
|
||
// Use the user's W3ID as the voter ID (strip @ prefix if present) | ||
const voterId = vault.ename?.startsWith("@") | ||
? vault.ename.slice(1) | ||
: vault.ename; | ||
console.log("🔍 DEBUG: Using voter ID:", voterId); | ||
console.log("🔑 Voter W3ID retrieved:", voterPublicKey); | ||
} catch (error) { | ||
console.error("Failed to get W3ID using KeyManager:", error); | ||
// Fallback to ename if KeyManager fails | ||
voterPublicKey = vault.ename || "unknown_public_key"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Use the retrieved W3ID in the blind vote payload
Line 865 still posts vault?.ename
even though we just derived the voter’s W3ID via KeyManager
. That breaks the new backend contract (and defeats the fallback) because the server keeps receiving the old identifier instead of the signed public key. Please wire the fetched value through.
- userW3id: vault?.ename || "",
+ userW3id: voterPublicKey,
Also applies to: 861-868
try { | ||
const { ename, session } = req.body; | ||
|
||
console.log(req.body) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove debug log that may expose sensitive data.
Logging the entire request body (req.body
) can expose sensitive information such as user identifiers (ename
) and session tokens in production logs, creating compliance risks (GDPR/CCPA violations) and security vulnerabilities if logs are compromised.
Apply this diff to remove the debug log:
-
- console.log(req.body)
-
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
console.log(req.body) |
🤖 Prompt for AI Agents
In platforms/blabsy-w3ds-auth-api/src/controllers/AuthController.ts around line
56, remove the debug console.log(req.body) which can leak sensitive user/session
data; simply delete that logging statement (or replace it with a non-sensitive,
structured audit log if needed—e.g., log only request ID or sanitized fields)
and ensure no other debug prints of full request bodies remain in the
controller.
if [ ! -f "../../../.env" ]; then | ||
echo "❌ .env file not found at ../../../.env" | ||
echo "Please create a .env file with the required environment variables" | ||
exit 1 | ||
fi | ||
|
||
# Load environment variables | ||
source ../../../.env | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Resolve .env
path relative to the script.
When this script is invoked from the repo root (e.g., bash platforms/dreamsync-api/reset.sh
), the check at Line 9 inspects ../../../.env
relative to the current working directory, not the script’s location. That resolves outside the repository, so the check (and subsequent source
) fails and the reset exits immediately. Derive the path from the script directory instead.
-# Check if .env file exists
-if [ ! -f "../../../.env" ]; then
+# Resolve paths relative to this script
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+ENV_FILE="${SCRIPT_DIR}/../../../.env"
+
+# Check if .env file exists
+if [ ! -f "${ENV_FILE}" ]; then
echo "❌ .env file not found at ../../../.env"
echo "Please create a .env file with the required environment variables"
exit 1
fi
# Load environment variables
-source ../../../.env
+source "${ENV_FILE}"
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In platforms/dreamsync-api/reset.sh around lines 9 to 17, the script currently
checks and sources ../../../.env relative to the current working directory which
fails when invoked from elsewhere; change it to compute the script directory
(e.g., DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)") and derive the .env
path from that directory (use the correct relative path from the script
location, e.g. "$DIR/../../.env"), then test -f against that computed path and
source that computed path so the script works regardless of the current working
directory.
const { ename, session, w3id, signature } = req.body; | ||
|
||
if (!ename) { | ||
return res.status(400).json({ error: "ename is required" }); | ||
} | ||
|
||
if (!session) { | ||
return res.status(400).json({ error: "session is required" }); | ||
} | ||
|
||
// Only find existing users - don't create new ones during auth | ||
const user = await this.userService.findUser(ename); | ||
|
||
if (!user) { | ||
// User doesn't exist - they need to be created via webhook first | ||
return res.status(404).json({ | ||
error: "User not found", | ||
message: "User must be created via eVault webhook before authentication" | ||
}); | ||
} | ||
|
||
const token = signToken({ userId: user.id }); | ||
|
||
const data = { | ||
user: { | ||
id: user.id, | ||
ename: user.ename, | ||
name: user.name, | ||
handle: user.handle, | ||
description: user.description, | ||
avatarUrl: user.avatarUrl, | ||
bannerUrl: user.bannerUrl, | ||
isVerified: user.isVerified, | ||
isPrivate: user.isPrivate, | ||
email: user.email, | ||
emailVerified: user.emailVerified, | ||
createdAt: user.createdAt, | ||
updatedAt: user.updatedAt, | ||
}, | ||
token, | ||
}; | ||
this.eventEmitter.emit(session, data); | ||
res.status(200).send(); | ||
} catch (error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Login flow issues tokens without authenticating the caller
login
only checks that an ename
and session
string are present. It never verifies the provided w3id
/signature
, never challenges the caller, and happily signs a JWT for any existing user. An attacker can POST { ename: "victim", session: "xyz" }
and immediately obtain a valid token.
We must actually authenticate: validate the signature (or other credential) against the expected challenge, ensure the session belongs to that challenge, and reject the request otherwise. Until that is in place, do not emit tokens.
const updates = req.body; | ||
const user = await this.userService.updateUser(req.user.id, updates); | ||
|
||
if (!user) { | ||
return res.status(404).json({ error: "User not found" }); | ||
} | ||
|
||
res.json({ | ||
id: user.id, | ||
ename: user.ename, | ||
name: user.name, | ||
handle: user.handle, | ||
description: user.description, | ||
avatarUrl: user.avatarUrl, | ||
bannerUrl: user.bannerUrl, | ||
isVerified: user.isVerified, | ||
isPrivate: user.isPrivate, | ||
email: user.email, | ||
emailVerified: user.emailVerified, | ||
createdAt: user.createdAt, | ||
updatedAt: user.updatedAt, | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do not persist arbitrary request bodies into the user record
req.body
is handed straight to UserService.updateUser
, which issues a raw repository update with whatever fields the caller supplies. A malicious client can flip privileged flags like isVerified
, isPrivate
, or emailVerified
, overwrite another user’s email, or mutate audit fields. Please whitelist the mutable profile attributes (e.g. name, handle, description, avatarUrl, bannerUrl) and drop everything else before calling the service, or add server-side validation to updateUser
so only expected keys make it to the database.
Example fix:
- const updates = req.body;
- const user = await this.userService.updateUser(req.user.id, updates);
+ const { name, handle, description, avatarUrl, bannerUrl } = req.body ?? {};
+ const updates = Object.fromEntries(
+ Object.entries({
+ name,
+ handle,
+ description,
+ avatarUrl,
+ bannerUrl,
+ }).filter(([, value]) => value !== undefined)
+ );
+
+ if (Object.keys(updates).length === 0) {
+ return res.status(400).json({ error: "No updatable fields provided" });
+ }
+
+ const user = await this.userService.updateUser(req.user.id, updates);
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const updates = req.body; | |
const user = await this.userService.updateUser(req.user.id, updates); | |
if (!user) { | |
return res.status(404).json({ error: "User not found" }); | |
} | |
res.json({ | |
id: user.id, | |
ename: user.ename, | |
name: user.name, | |
handle: user.handle, | |
description: user.description, | |
avatarUrl: user.avatarUrl, | |
bannerUrl: user.bannerUrl, | |
isVerified: user.isVerified, | |
isPrivate: user.isPrivate, | |
email: user.email, | |
emailVerified: user.emailVerified, | |
createdAt: user.createdAt, | |
updatedAt: user.updatedAt, | |
}); | |
// only allow updating these profile fields | |
const { name, handle, description, avatarUrl, bannerUrl } = req.body ?? {}; | |
const updates = Object.fromEntries( | |
Object.entries({ | |
name, | |
handle, | |
description, | |
avatarUrl, | |
bannerUrl, | |
}).filter(([, value]) => value !== undefined) | |
); | |
if (Object.keys(updates).length === 0) { | |
return res.status(400).json({ error: "No updatable fields provided" }); | |
} | |
const user = await this.userService.updateUser(req.user.id, updates); | |
if (!user) { | |
return res.status(404).json({ error: "User not found" }); | |
} | |
res.json({ | |
id: user.id, | |
ename: user.ename, | |
name: user.name, | |
handle: user.handle, | |
description: user.description, | |
avatarUrl: user.avatarUrl, | |
bannerUrl: user.bannerUrl, | |
isVerified: user.isVerified, | |
isPrivate: user.isPrivate, | |
email: user.email, | |
emailVerified: user.emailVerified, | |
createdAt: user.createdAt, | |
updatedAt: user.updatedAt, | |
}); |
🤖 Prompt for AI Agents
In platforms/dreamsync-api/src/controllers/UserController.ts around lines 104 to
125, the controller currently passes req.body straight to updateUser which
allows clients to persist arbitrary fields (including privileged flags and audit
fields). Replace that by whitelisting allowed updatable profile attributes (e.g.
name, handle, description, avatarUrl, bannerUrl) and building a new updates
object from req.body that only copies those keys (with type
checks/normalization), explicitly ignore/omit fields like id, email, isVerified,
isPrivate, emailVerified, createdAt, updatedAt, and any other server-controlled
properties, then call this.userService.updateUser(req.user.id, filteredUpdates);
alternatively, add server-side validation in UserService.updateUser to reject or
strip any unexpected keys before performing the repository update and ensure
audit fields cannot be altered by clients.
// Check for touch capability | ||
if ('ontouchstart' in window || navigator.maxTouchPoints > 0) { | ||
return true; | ||
} | ||
|
||
// Check screen size | ||
if (window.innerWidth <= 768) { | ||
return true; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Touch and screen size checks may cause false positives.
The touch capability check (line 16) will classify any device with a touchscreen—including laptops and desktops with touchscreens—as mobile. Additionally, the screen width check (line 21) uses the current window size rather than device capabilities, so a desktop user with a narrow browser window would be classified as mobile.
Consider limiting mobile detection to user agent checks only, or add additional constraints (e.g., require both touch AND small screen AND mobile UA pattern) to reduce false positives.
</review_comment_end>
🤖 Prompt for AI Agents
In platforms/dreamSync/client/src/lib/utils/mobile-detection.ts around lines 15
to 23, the current detection returns true for any device with touch or small
window width which causes false positives (touch-enabled laptops and narrow
desktop windows). Change the logic to be stricter by requiring a mobile
user-agent pattern plus touch and small screen together (e.g., require
navigator.userAgent match against a mobile regex AND ('ontouchstart' in window
|| navigator.maxTouchPoints > 0) AND window.innerWidth <= 768), or alternatively
replace the current checks with a single reliable user-agent only check; update
the function to use one of these approaches and ensure tests or callers are
adjusted accordingly.
export function getDeepLinkUrl(qrData: string): string { | ||
// Extract the deep link URL from the QR data | ||
// This assumes the QR data contains a URL that can be opened directly | ||
return qrData; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Implement extraction logic or remove the function.
The function currently just returns the input parameter without any extraction, parsing, or validation. The comment suggests it should "extract the deep link URL from the QR data," but the implementation is a simple pass-through.
Either implement the actual extraction logic if QR data contains metadata/encoding that needs parsing, or remove this function entirely if no transformation is needed.
</review_comment_end>
const [wishlistContent, setWishlistContent] = useState(sampleWishlistTemplate); | ||
const [isSaving, setIsSaving] = useState(false); | ||
const [isLoading, setIsLoading] = useState(true); | ||
const [existingWishlist, setExistingWishlist] = useState<any>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion | 🟠 Major
Define a proper type for existingWishlist
instead of any
.
Using any
bypasses TypeScript's type checking and can lead to runtime errors. Define an interface or type for the wishlist structure to ensure type safety.
Add a type definition at the top of the file:
interface Wishlist {
id: string;
title: string;
content: string;
isPublic: boolean;
createdAt?: string;
updatedAt?: string;
}
Then update the state declaration:
- const [existingWishlist, setExistingWishlist] = useState<any>(null);
+ const [existingWishlist, setExistingWishlist] = useState<Wishlist | null>(null);
🤖 Prompt for AI Agents
In platforms/dreamSync/client/src/pages/wishlist-editor.tsx around line 23, the
state existingWishlist is typed as any; define a proper Wishlist interface at
the top of the file (including id, title, content, isPublic, and optional
createdAt/updatedAt) and update the useState declaration to use
useState<Wishlist | null> instead of any so TypeScript enforces the structure
across the component.
"@tailwindcss/typography": "^0.5.15", | ||
"@tailwindcss/vite": "^4.1.3", | ||
"@types/node": "20.16.11", | ||
"@types/react": "^18.3.11", | ||
"@types/react-dom": "^18.3.1", | ||
"@types/turndown": "^5.0.5", | ||
"@vitejs/plugin-react": "^4.3.2", | ||
"autoprefixer": "^10.4.20", | ||
"drizzle-kit": "^0.30.4", | ||
"postcss": "^8.4.47", | ||
"tailwindcss": "^3.4.17", | ||
"typescript": "5.6.3", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Blocker: @tailwindcss/vite
requires Tailwind CSS v4, but you're still on 3.4.x.
The Vite plugin is only compatible with the new Tailwind v4 engine. With [email protected]
the plugin throws at startup, so vite dev/build
will crash. Either downgrade to the traditional PostCSS setup (remove @tailwindcss/vite
and configure Tailwind 3 normally) or upgrade the entire stack to Tailwind v4 (alpha) before shipping.
🤖 Prompt for AI Agents
In platforms/dreamSync/package.json around lines 85 to 96, the dependency
@tailwindcss/vite requires Tailwind CSS v4 while package.json lists
[email protected], which will cause Vite to crash; fix by either removing
@tailwindcss/vite and revert to the PostCSS/Tailwind v3 setup (update build/vite
and postcss config to use the traditional tailwindcss plugin) or upgrade
tailwindcss and any related config/plugins to v4-compatible versions across the
project so the @tailwindcss/vite plugin can be used safely.
@@ -7,6 +7,7 @@ | |||
"name": "name", | |||
"type": "type", | |||
"participants": "users(participants[].id),participantIds", | |||
"admins": "users(admins),admins", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
Verify the admins mapping syntax for consistency.
The admins
mapping uses "users(admins),admins"
while the participants
mapping on line 9 uses "users(participants[].id),participantIds"
with explicit array notation []
and .id
accessor.
If admins
is an array field (like participants
), the mapping should follow the same pattern for consistency. If it's a single value, the current syntax may be correct, but this needs verification against the actual data structure.
Run the following script to check the admins field structure in the Chat entity or related code:
🏁 Script executed:
#!/bin/bash
# Description: Find Chat entity definition and check admins field structure
# Search for Chat entity/model definitions
rg -nP --type=ts -A10 -B2 'class\s+Chat|interface\s+Chat' | head -50
# Search for admins field usage in chat context
rg -nP --type=ts 'admins.*:.*\[\]|admins.*Array' | head -20
Length of output: 3677
Verify admins
property definition and type in Chat.ts
before finalizing the mapping:
🏁 Script executed:
#!/bin/bash
# Inspect the Chat entity definition and locate the admins property
rg -nP --type=ts 'export class Chat' -A15 platforms/pictique-api/src/database/entities/Chat.ts
rg -nP --type=ts 'admins' -C3 platforms/pictique-api/src/database/entities/Chat.ts
Length of output: 476
Align admins
mapping with your entity
The chat.mapping.json
at line 10 defines "admins": "users(admins),admins"
, but the Chat
entity has no admins
field. Either add a corresponding admins
relation in Chat.ts
or remove/update this mapping to target an existing property.
🤖 Prompt for AI Agents
In platforms/pictique-api/src/web3adapter/mappings/chat.mapping.json around line
10, the mapping entry "admins": "users(admins),admins" references a non-existent
admins field on the Chat entity; fix by either adding an admins
relation/property on Chat.ts that matches the mapping (define the proper
relation type, inverse side and persistence configuration) or remove/replace the
mapping entry with the correct existing Chat property name (or adjust the
relation target to an existing entity property), then run typechecks/compile to
ensure the mapping and entity stay in sync.
Description of change
Issue Number
Type of change
How the change has been tested
Change checklist
Summary by CodeRabbit
New Features
Changes
Documentation