-
Notifications
You must be signed in to change notification settings - Fork 4
Feat/build action #360
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/build action #360
Conversation
WalkthroughThis PR makes large, cross-repository edits: switches the control-panel SvelteKit adapter to Node and adjusts its build/deps; converts many Blabsy animation imports to motion/react; integrates web3-adapter as a package in Cerberus and updates web3-adapter internals; removes/changes many UI primitives in Group Charter Manager; expands eID Wallet deep-link/scan/sign/blind-vote flows and crypto key APIs; adds prerender flags in Pictique; and applies many formatting, dependency, and minor behavior tweaks across projects. Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor User
participant App as "eID Wallet App"
participant DL as "Deep-link/QR Handler"
participant KM as "KeyManager (HW/SW)"
participant Platform as "Platform Backend"
participant EV as "eVault / Registry"
User->>App: Open app / Scan QR
App->>DL: parse content -> intent
DL-->>App: intent (auth | sign | blind-vote | reveal)
alt auth intent
App->>EV: check auth / vault
EV-->>App: auth result
App-->>User: navigate or prompt login
else sign intent
App->>KM: ensure key / pubkey
KM-->>App: publicKey
App->>KM: sign(payload)
KM-->>App: signature
App->>Platform: POST signed payload / redirect
Platform-->>App: ack
App-->>User: success UI / redirect
else blind-vote
App->>Platform: fetch poll / register
App->>App: build privacy payload (commitment)
App->>KM: sign(commitment)
KM-->>App: signature
App->>Platform: submit vote
Platform-->>App: receipt
App-->>User: success UI
else reveal
App->>App: load stored vote
App->>KM: sign(reveal)
KM-->>App: signature
App->>Platform: submit reveal
Platform-->>App: confirmation
App-->>User: reveal success
end
Estimated code review effort🎯 5 (Critical) | ⏱️ ~120–180 minutes Possibly related PRs
Suggested reviewers
Poem
Pre-merge checks and finishing touches❌ Failed checks (4 warnings)
✅ Passed checks (1 passed)
✨ Finishing touches
🧪 Generate unit tests (beta)
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: 12
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (4)
platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (1)
121-179
: Remove redundant type cast and refactor the setTimeout workaround.Three issues to address:
Line 122: The type cast
charter as Charter
is redundant—TypeScript already narrowscharter
to typeCharter
inside theif (charter)
block.Lines 158-177: Using
setTimeout
to manually set form values is a brittle workaround that suggests a timing issue with form initialization. This pattern can fail during fast re-renders or component unmounting.Duplicate form value setting: Values are set via
form.reset()
and then again viaform.setValue()
calls inside setTimeout, which is inefficient.Apply this refactor:
useEffect(() => { if (charter) { - const charterData = charter as Charter; - const guidelines = charterData.guidelines || []; + const guidelines = charter.guidelines || []; - console.log("Charter data loaded:", charterData); - console.log("Charter name:", charterData.name); - console.log("Charter description:", charterData.description); + console.log("Charter data loaded:", charter); + console.log("Charter name:", charter.name); + console.log("Charter description:", charter.description); console.log("Charter guidelines:", guidelines); - console.log("Charter groupId:", charterData.groupId); + console.log("Charter groupId:", charter.groupId); // Set guidelines state first setGuidelines(guidelines.length > 0 ? guidelines : [""]); // Reset form with current charter data const formValues = { - name: charterData.name || "", - description: charterData.description || "", + name: charter.name || "", + description: charter.description || "", guidelines: guidelines, - groupId: charterData.groupId || undefined, + groupId: charter.groupId || undefined, isActive: - charterData.isActive !== undefined ? charterData.isActive : true, + charter.isActive !== undefined ? charter.isActive : true, autoApprove: - charterData.autoApprove !== undefined - ? charterData.autoApprove + charter.autoApprove !== undefined + ? charter.autoApprove : false, allowPosts: - charterData.allowPosts !== undefined - ? charterData.allowPosts + charter.allowPosts !== undefined + ? charter.allowPosts : true, }; console.log("Form values to set:", formValues); - // Use reset to populate all form fields at once form.reset(formValues); - - // Also manually set values to ensure they stick - setTimeout(() => { - form.setValue("name", charterData.name || ""); - form.setValue("description", charterData.description || ""); - form.setValue("guidelines", guidelines); - form.setValue("groupId", charterData.groupId || undefined); - form.setValue( - "isActive", - charterData.isActive !== undefined ? charterData.isActive : true - ); - form.setValue( - "autoApprove", - charterData.autoApprove !== undefined - ? charterData.autoApprove - : false - ); - form.setValue( - "allowPosts", - charterData.allowPosts !== undefined ? charterData.allowPosts : true - ); - }, 100); } }, [charter, form]);If
form.reset()
alone doesn't properly initialize the form fields, investigate the root cause (e.g., form initialization timing, default values mismatch) rather than relying on setTimeout as a workaround.platforms/blabsy/src/components/user/user-edit-profile.tsx (1)
172-173
: Guard revokeObjectURL calls to avoid runtime errors
URL.revokeObjectURL(editUserData.coverPhotoURL ?? '')
can throw if passed''
or a non-blob URL. Guard before calling.Use:
-URL.revokeObjectURL(editUserData.coverPhotoURL ?? ''); +if (editUserData.coverPhotoURL?.startsWith('blob:')) { + URL.revokeObjectURL(editUserData.coverPhotoURL); +}And in
cleanImage
loop:-imagesKey.forEach((image) => - URL.revokeObjectURL(editUserData[image] ?? '') -); +imagesKey.forEach((image) => { + const url = editUserData[image]; + if (url && url.startsWith('blob:')) URL.revokeObjectURL(url); +});Also applies to: 181-183
platforms/blabsy/src/components/chat/chat-window.tsx (1)
49-49
: Sanitize HTML before using dangerouslySetInnerHTML (XSS risk)User/system messages are injected as HTML without sanitization. This is a critical XSS vector. Sanitize the HTML and add safe link attributes.
Apply this diff to wrap with sanitize and strengthen anchor tags:
- <div className="text-sm font-medium text-gray-600 dark:text-gray-400 whitespace-pre-wrap text-left"> - <div dangerouslySetInnerHTML={{ __html: displayText.replace(/<a href="([^"]+)">([^<]+)<\/a>/g, '<a href="$1" class="text-blue-600 hover:text-blue-800 underline">$2</a>') }} /> + <div className="text-sm font-medium text-gray-600 dark:text-gray-400 whitespace-pre-wrap text-left"> + <div dangerouslySetInnerHTML={{ __html: sanitize( + displayText.replace( + /<a href="([^"]+)">([^<]+)<\/a>/g, + '<a href="$1" class="text-blue-600 hover:text-blue-800 underline" target="_blank" rel="noopener noreferrer nofollow">$2</a>' + ) + ) }} />- <div className='break-words whitespace-pre-wrap' dangerouslySetInnerHTML={{ __html: displayText.replace(/<a href="([^"]+)">([^<]+)<\/a>/g, '<a href="$1" class="text-blue-600 hover:text-blue-800 underline">$2</a>') }} /> + <div className='break-words whitespace-pre-wrap' dangerouslySetInnerHTML={{ __html: sanitize( + displayText.replace( + /<a href="([^"]+)">([^<]+)<\/a>/g, + '<a href="$1" class="text-blue-600 hover:text-blue-800 underline" target="_blank" rel="noopener noreferrer nofollow">$2</a>' + ) + ) }} />And add a top-level import (outside the changed lines):
import { sanitize } from 'isomorphic-dompurify';You’ll need to add isomorphic-dompurify as a dependency.
Based on static analysis hints.
Also applies to: 106-106
platforms/blabsy/src/components/aside/aside-trends.tsx (1)
14-18
: Remove unusedvariants
export.The
variants
object is exported but never used—animation props are inlined directly on themotion.div
at lines 42-44. This creates dead code and duplicates the variant values.Additionally, for consistency with the rest of the codebase (see
platforms/blabsy/src/components/input/input.tsx
,platforms/blabsy/src/components/sidebar/more-settings.tsx
, etc.), consider using theVariants
type frommotion/react
and spreading the variants object instead of inlining.Option 1 (remove unused export):
-export const variants = { - initial: { opacity: 0 }, - animate: { opacity: 1 }, - transition: { duration: 0.8 } -}; - type AsideTrendsProps = {Option 2 (use the variants object consistently):
+import type { Variants } from 'motion/react'; + -export const variants = { +export const variants: Variants = { initial: { opacity: 0 }, - animate: { opacity: 1 }, - transition: { duration: 0.8 } + animate: { opacity: 1, transition: { duration: 0.8 } } };And update the motion.div:
<motion.div - initial={{ opacity: 0 }} - animate={{ opacity: 1 }} - transition={{ duration: 0.8 }} + {...variants} className={cn(Also applies to: 42-44
🧹 Nitpick comments (14)
platforms/group-charter-manager/src/app/page.tsx (1)
217-296
: LGTM! Well-structured group card refactor.The refactored group card rendering logic is clear and correctly handles all charter states (signed, unsigned, missing). The conditional rendering properly cascades through
hasCharter
→hasSigned
→ appropriate UI elements with safe fallbacks throughout.The visual indicators (color-coded icons, pulsing dot for unsigned charters, CheckCircle overlay for signed state) provide good user feedback.
Optional accessibility enhancement:
Consider adding an
aria-label
to the pulsing indicator on line 241 to improve screen reader support:<div className="flex items-center gap-2"> - <div className="w-2 h-2 bg-yellow-400 rounded-full animate-pulse"></div> + <div className="w-2 h-2 bg-yellow-400 rounded-full animate-pulse" aria-label="Pending signature"></div> <p>Please sign the charter</p> </div>platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
674-749
: Consider extracting repeated vote display logic.The logic for displaying vote details based on voting mode (normal/point/rank) is duplicated across multiple sections of the component. This increases maintenance burden and the risk of inconsistencies.
Consider extracting this into a reusable component or helper functions:
// components/VoteDetailsDisplay.tsx interface VoteDetailsProps { voteData: VoteData; pollOptions: string[]; } export function VoteDetailsDisplay({ voteData, pollOptions }: VoteDetailsProps) { if (voteData.mode === 'normal' && Array.isArray(voteData.data)) { return <NormalVoteDisplay data={voteData.data} options={pollOptions} />; } if (voteData.mode === 'point' && typeof voteData.data === 'object') { return <PointVoteDisplay data={voteData.data} options={pollOptions} />; } if (voteData.mode === 'rank' && Array.isArray(voteData.data)) { return <RankVoteDisplay data={voteData.data} options={pollOptions} />; } return null; }This would eliminate ~150 lines of duplicated code and make the component more maintainable.
Also applies to: 855-930
platforms/group-charter-manager/package.json (1)
71-71
: Maintain consistent file ending.The trailing newline was removed here, which is inconsistent with other files in this PR (e.g.,
platforms/cerberus/package.json
andplatforms/eVoting/tsconfig.json
added trailing newlines).Apply this diff to add a trailing newline:
} -} +} +platforms/blabsy/src/components/modal/image-modal.tsx (1)
107-108
: Avoidany
on exit animation; align variant typesCasting
backdrop.exit
toany
masks type issues. Prefer typing the variants in./modal
using motion’s types and consume them here without assertions, or narrow to the accepted exit union.Example direction:
- In
./modal
, type variants with motion/react types (e.g.,Variants
/MotionProps
).- Here, use
exit={tweet ? backdrop.exit : undefined}
without casts once types align.platforms/blabsy/src/components/input/image-preview.tsx (1)
23-32
: Type motion props instead of relying on inferenceExplicitly typing the animation props improves safety during future upgrades.
Apply this refactor:
+import type { MotionProps } from 'motion/react'; -const variants = { +const motionProps: Pick<MotionProps, 'initial' | 'animate' | 'exit' | 'transition'> = { initial: { opacity: 0, scale: 0.5 }, animate: { opacity: 1, scale: 1, transition: { duration: 0.3 } }, exit: { opacity: 0, scale: 0.5 }, transition: { type: 'spring' as const, duration: 0.5 } }; ... - {...variants} + {...motionProps}Also applies to: 144-145
platforms/blabsy/src/lib/context/window-context.tsx (1)
1-1
: Prefer type-only React imports; avoid shadowing the context type name
- Import ReactNode as a type and drop the unused default React import (automatic JSX runtime).
- Optional: rename the WindowContext type to WindowContextValue to avoid name collision with the context variable.
Apply this diff for imports and children typing:
-import React, { createContext, useContext, useEffect, useState, ReactNode } from 'react'; +import { createContext, useContext, useEffect, useState } from 'react'; +import type { ReactNode } from 'react';Optional (outside the changed lines): rename the type for clarity
// before type WindowContext = { windowSize: WindowSize; isMobile: boolean }; const WindowContext = createContext<WindowContext | null>(null); export function useWindow(): WindowContext { /* ... */ } // after type WindowContextValue = { windowSize: WindowSize; isMobile: boolean }; const WindowContext = createContext<WindowContextValue | null>(null); export function useWindow(): WindowContextValue { /* ... */ }Also applies to: 16-16
platforms/blabsy/src/components/ui/loading.tsx (1)
2-2
: Use a type-only import for FC; drop default React importAutomatic JSX runtime doesn’t require React at runtime here. Keep FC if preferred, but import it as a type.
-import React, { FC } from 'react'; +import type { FC } from 'react';infrastructure/control-panel/src/lib/services/cacheService.ts (3)
21-21
: Restore LowDB typing with type-only import; keep generics for db.data shapeAvoid any; preserve data shape and editor support without impacting bundles.
- private db: any | null = null; + // Type-only reference keeps this out of client bundles + private db: import('lowdb').Low<CacheData> | null = null;Additionally (outside changed lines), keep generics when constructing:
// before this.db = new Low(adapter, defaultData); // after this.db = new Low<CacheData>(adapter, defaultData);
106-114
: Wrap writes in try/catch to avoid unhandled promise rejectionsDisk writes can fail (FS perms, serverless, etc.). Add error handling around write calls.
- this.db.data = { + this.db.data = { evaults, lastUpdated: Date.now(), isStale: false - }; - await this.db.write(); + }; + try { + await this.db.write(); + } catch (err) { + console.error('Failed to write cache file:', err); + }- this.db.data.isStale = true; - await this.db.write(); + this.db.data.isStale = true; + try { + await this.db.write(); + } catch (err) { + console.error('Failed to mark cache stale:', err); + }- this.db.data = defaultData; - await this.db.write(); + this.db.data = defaultData; + try { + await this.db.write(); + } catch (err) { + console.error('Failed to clear cache:', err); + }Also applies to: 123-126, 170-174
31-54
: Optional: de-duplicate concurrent init callsMultiple concurrent callers before isInitialized flips may run init twice. Consider an initPromise to serialize.
private initPromise: Promise<void> | null = null; private async init() { if (this.isInitialized) return; if (this.initPromise) return this.initPromise; this.initPromise = (async () => { try { const { Low } = await import('lowdb'); const { JSONFile } = await import('lowdb/node'); const adapter = new JSONFile<CacheData>(CACHE_FILE); this.db = new Low<CacheData>(adapter, defaultData); await this.db.read(); if (!this.db.data) { this.db.data = defaultData; await this.db.write(); } this.isInitialized = true; } catch (e) { console.error('Failed to initialize cache service:', e); } finally { this.initPromise = null; } })(); return this.initPromise; }platforms/blabsy/src/components/ui/custom-icon.tsx (1)
2-2
: Use type-only import and ComponentType; keep runtime bundle lean
- Drop default React import; import ComponentType as a type.
- Use ComponentType directly in the Icons map type.
-import React from 'react'; +import type { ComponentType } from 'react';-const Icons: Record<string, React.ComponentType<IconProps>> = { +const Icons: Record<string, ComponentType<IconProps>> = {Optional (outside changed lines): define Icons first, then
export type IconName = keyof typeof Icons;for clearer flow.
Also applies to: 14-14
platforms/blabsy/src/components/chat/chat-window.tsx (2)
4-4
: Remove unused importdate-fns set is unused.
-import { formatDistanceToNow, set } from 'date-fns'; +import { formatDistanceToNow } from 'date-fns';
145-167
: Optional: fetch participant docs in parallelCurrent loop is sequential. Parallelize Firestore reads for faster header rendering on large groups.
const ids = currentChat.participants.filter((pid) => pid !== user?.id); const docs = await Promise.all(ids.map((pid) => getDoc(doc(db, 'users', pid)))); docs.forEach((userDoc, i) => { if (userDoc.exists()) newParticipantsData[ids[i]] = userDoc.data() as User; }); if (user) newParticipantsData[user.id] = user;platforms/blabsy/src/components/aside/aside-trends.tsx (1)
2-2
: Remove unnecessary React import.The explicit
React
import is not required with modern JSX transform (React 17+). This import can be safely removed.Apply this diff:
import Link from 'next/link'; -import React from 'react'; import cn from 'clsx';
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (101)
infrastructure/control-panel/package.json
(2 hunks)infrastructure/control-panel/src/lib/services/cacheService.ts
(2 hunks)infrastructure/control-panel/svelte.config.js
(1 hunks)infrastructure/control-panel/vite.config.ts
(1 hunks)mappings/.gitignore
(1 hunks)metastate.compose.yml
(1 hunks)package.json
(1 hunks)platforms/blabsy/package.json
(3 hunks)platforms/blabsy/src/components/aside/aside-trends.tsx
(4 hunks)platforms/blabsy/src/components/aside/suggestions.tsx
(1 hunks)platforms/blabsy/src/components/chat/chat-window.tsx
(7 hunks)platforms/blabsy/src/components/input/image-preview.tsx
(5 hunks)platforms/blabsy/src/components/input/input-form.tsx
(2 hunks)platforms/blabsy/src/components/input/input-options.tsx
(1 hunks)platforms/blabsy/src/components/input/input.tsx
(2 hunks)platforms/blabsy/src/components/layout/user-follow-layout.tsx
(1 hunks)platforms/blabsy/src/components/layout/user-home-layout.tsx
(1 hunks)platforms/blabsy/src/components/login/login-main.tsx
(3 hunks)platforms/blabsy/src/components/modal/image-modal.tsx
(3 hunks)platforms/blabsy/src/components/modal/modal.tsx
(1 hunks)platforms/blabsy/src/components/sidebar/mobile-sidebar.tsx
(1 hunks)platforms/blabsy/src/components/sidebar/more-settings.tsx
(2 hunks)platforms/blabsy/src/components/sidebar/sidebar-profile.tsx
(1 hunks)platforms/blabsy/src/components/tweet/number-stats.tsx
(1 hunks)platforms/blabsy/src/components/tweet/tweet-actions.tsx
(2 hunks)platforms/blabsy/src/components/tweet/tweet-share.tsx
(1 hunks)platforms/blabsy/src/components/tweet/tweet-status.tsx
(1 hunks)platforms/blabsy/src/components/tweet/tweet.tsx
(2 hunks)platforms/blabsy/src/components/ui/custom-icon.tsx
(10 hunks)platforms/blabsy/src/components/ui/loading.tsx
(2 hunks)platforms/blabsy/src/components/user/user-cards.tsx
(1 hunks)platforms/blabsy/src/components/user/user-edit-profile.tsx
(2 hunks)platforms/blabsy/src/components/user/user-header.tsx
(1 hunks)platforms/blabsy/src/components/user/user-nav.tsx
(1 hunks)platforms/blabsy/src/components/user/user-share.tsx
(1 hunks)platforms/blabsy/src/components/view/view-tweet.tsx
(1 hunks)platforms/blabsy/src/lib/context/window-context.tsx
(2 hunks)platforms/blabsy/src/lib/hooks/useInfiniteScroll.tsx
(1 hunks)platforms/blabsy/src/lib/utils.ts
(1 hunks)platforms/blabsy/src/pages/bookmarks.tsx
(1 hunks)platforms/blabsy/src/pages/home.tsx
(1 hunks)platforms/blabsy/src/pages/people.tsx
(1 hunks)platforms/blabsy/src/pages/tweet/[id].tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/index.tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/likes.tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/media.tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/with_replies.tsx
(1 hunks)platforms/blabsy/tsconfig.json
(2 hunks)platforms/cerberus/package.json
(2 hunks)platforms/cerberus/src/controllers/WebhookController.ts
(1 hunks)platforms/cerberus/src/web3adapter/watchers/subscriber.ts
(1 hunks)platforms/cerberus/tsconfig.json
(2 hunks)platforms/eVoting/next.config.ts
(1 hunks)platforms/eVoting/src/app/(app)/[id]/page.tsx
(46 hunks)platforms/eVoting/src/app/(auth)/login/page.tsx
(2 hunks)platforms/eVoting/src/app/(auth)/logout/page.tsx
(0 hunks)platforms/eVoting/src/app/(auth)/register/page.tsx
(0 hunks)platforms/eVoting/src/components/poll-card.tsx
(0 hunks)platforms/eVoting/src/hooks/use-toast.ts
(1 hunks)platforms/eVoting/src/lib/apiClient.ts
(2 hunks)platforms/eVoting/tsconfig.json
(2 hunks)platforms/group-charter-manager/package.json
(3 hunks)platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx
(7 hunks)platforms/group-charter-manager/src/app/charter/[id]/page.tsx
(7 hunks)platforms/group-charter-manager/src/app/page.tsx
(5 hunks)platforms/group-charter-manager/src/components/auth/login-screen.tsx
(4 hunks)platforms/group-charter-manager/src/components/charter-signing-status.tsx
(2 hunks)platforms/group-charter-manager/src/components/layout/navbar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/accordion.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/alert.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/aspect-ratio.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/avatar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/breadcrumb.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/calendar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/carousel.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/chart.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/checkbox.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/collapsible.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/context-menu.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/drawer.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/hover-card.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/input-otp.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/menubar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/navigation-menu.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/pagination.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/progress.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/radio-group.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/resizable.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/scroll-area.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/select.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/sidebar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/slider.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/table.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/tabs.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/textarea.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/toggle-group.tsx
(0 hunks)platforms/group-charter-manager/src/components/wysiwyg-editor.tsx
(2 hunks)platforms/pictique/src/routes/(protected)/group/[id]/+page.ts
(1 hunks)platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts
(1 hunks)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts
(1 hunks)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts
(1 hunks)
💤 Files with no reviewable changes (32)
- platforms/group-charter-manager/src/components/ui/drawer.tsx
- platforms/group-charter-manager/src/components/ui/alert.tsx
- platforms/group-charter-manager/src/components/ui/textarea.tsx
- platforms/group-charter-manager/src/components/ui/accordion.tsx
- platforms/group-charter-manager/src/components/ui/tabs.tsx
- platforms/eVoting/src/components/poll-card.tsx
- platforms/group-charter-manager/src/components/ui/hover-card.tsx
- platforms/group-charter-manager/src/components/ui/table.tsx
- platforms/group-charter-manager/src/components/ui/slider.tsx
- platforms/group-charter-manager/src/components/ui/resizable.tsx
- platforms/group-charter-manager/src/components/ui/toggle-group.tsx
- platforms/group-charter-manager/src/components/ui/checkbox.tsx
- platforms/group-charter-manager/src/components/ui/sidebar.tsx
- platforms/group-charter-manager/src/components/ui/menubar.tsx
- platforms/group-charter-manager/src/components/ui/progress.tsx
- platforms/group-charter-manager/src/components/ui/aspect-ratio.tsx
- platforms/group-charter-manager/src/components/ui/chart.tsx
- platforms/group-charter-manager/src/components/layout/navbar.tsx
- platforms/eVoting/src/app/(auth)/logout/page.tsx
- platforms/group-charter-manager/src/components/ui/select.tsx
- platforms/group-charter-manager/src/components/ui/avatar.tsx
- platforms/group-charter-manager/src/components/ui/scroll-area.tsx
- platforms/group-charter-manager/src/components/ui/radio-group.tsx
- platforms/group-charter-manager/src/components/ui/context-menu.tsx
- platforms/eVoting/src/app/(auth)/register/page.tsx
- platforms/group-charter-manager/src/components/ui/carousel.tsx
- platforms/group-charter-manager/src/components/ui/calendar.tsx
- platforms/group-charter-manager/src/components/ui/navigation-menu.tsx
- platforms/group-charter-manager/src/components/ui/pagination.tsx
- platforms/group-charter-manager/src/components/ui/input-otp.tsx
- platforms/group-charter-manager/src/components/ui/breadcrumb.tsx
- platforms/group-charter-manager/src/components/ui/collapsible.tsx
🧰 Additional context used
🧬 Code graph analysis (11)
platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
prerender
(1-1)
platforms/blabsy/src/components/login/login-main.tsx (1)
platforms/pictique/src/declaration.d.ts (1)
QRCode
(3-6)
platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
prerender
(1-1)
platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (1)
platforms/dreamSync/shared/schema.ts (1)
groups
(120-134)
platforms/group-charter-manager/src/app/charter/[id]/page.tsx (1)
platforms/group-charter-manager/src/components/charter-signing-status.tsx (1)
CharterSigningStatus
(31-141)
platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
prerender
(1-1)
platforms/group-charter-manager/src/components/auth/login-screen.tsx (1)
platforms/group-charter-manager/src/lib/utils/mobile-detection.ts (1)
isMobileDevice
(1-6)
platforms/blabsy/src/components/modal/image-modal.tsx (1)
platforms/blabsy/src/components/modal/modal.tsx (1)
backdrop
(34-34)
platforms/blabsy/src/components/aside/aside-trends.tsx (5)
platforms/blabsy/src/components/input/input.tsx (1)
variants
(38-41)platforms/blabsy/src/components/sidebar/more-settings.tsx (1)
variants
(13-21)platforms/blabsy/src/components/tweet/tweet-actions.tsx (1)
variants
(30-38)platforms/blabsy/src/components/tweet/tweet.tsx (1)
variants
(30-34)platforms/blabsy/src/components/user/user-header.tsx (1)
variants
(11-15)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
prerender
(1-1)
platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
platforms/eVoting/src/lib/pollApi.ts (1)
pollApi
(102-199)
🪛 ast-grep (0.39.6)
platforms/blabsy/src/components/chat/chat-window.tsx
[warning] 105-105: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🔇 Additional comments (54)
platforms/blabsy/src/components/sidebar/sidebar-profile.tsx (1)
1-1
: Import migration looks good.
AnimatePresence
andmotion
are provided bymotion/react
, so this aligns with the Motion migration without requiring any other changes here.platforms/eVoting/src/hooks/use-toast.ts (1)
158-158
: LGTM! Type annotation improves type safety.Adding the explicit
boolean
type annotation to theonOpenChange
parameter is a good practice and likely resolves a TypeScript compilation error related to implicit typing.platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
1-1
: LGTM! Correctly disables prerendering for protected dynamic route.This change appropriately disables static prerendering for a protected route with dynamic parameters, which resolves the build failure. SvelteKit cannot prerender routes that require runtime data or authentication context.
platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
1-1
: LGTM! Consistent with other protected routes.The prerender configuration correctly disables static generation for this dynamic profile route, matching the pattern used in other protected routes.
platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
1-1
: LGTM! Appropriate configuration for messages route.The prerender setting correctly ensures this dynamic messages route is server-rendered at request time rather than statically generated during build.
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
1-1
: LGTM! Fixes build issue for dynamic group routes.This configuration correctly disables prerendering for the group detail route, which is essential for routes with dynamic segments under protected paths. The change successfully addresses the build failures mentioned in issue #359.
platforms/blabsy/src/pages/user/[id]/index.tsx (1)
2-2
: Migration fromframer-motion
tomotion/react
is completeThe
motion
package (^12.0.0
) is declared inplatforms/blabsy/package.json
, and no remainingframer-motion
imports were found across the blabsy platform.platforms/blabsy/src/pages/people.tsx (1)
2-2
: Confirm animation behavior and build resolution.
motion
is present in package.json at ^12.0.0. Please:
- Test that
motion.div
transitions work as before- Verify this resolves build issue #359
platforms/group-charter-manager/src/components/wysiwyg-editor.tsx (1)
32-34
: LGTM! Type assertion correctly addresses TypeScript inference.The type assertion is valid given the
async: false
configuration at line 11. When marked is configured synchronously,parse()
returns a string directly rather than a Promise, but TypeScript's type definitions may not properly reflect this conditional return type. This assertion is a reasonable workaround.platforms/group-charter-manager/src/components/charter-signing-status.tsx (1)
20-21
: Verify backend includes isAdmin/isOwner
Ensure the/api/groups/:groupId/charter/signing-status
response populates these optional fields so admin/owner badges render correctly.platforms/blabsy/src/pages/bookmarks.tsx (1)
2-2
: Approve migration to motion/react.The
motion
package is declared at version ^12.0.0 in platforms/blabsy/package.json and noframer-motion
imports remain.platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (6)
48-53
: LGTM!The schema extension appropriately makes the new fields optional, which is correct for an update/edit operation where users may only modify specific fields.
61-79
: LGTM!The Charter interface is well-structured with appropriate types. The nested group object provides useful context for the charter edit form.
81-88
: LGTM!The Group interface definition is appropriate for the group selection component.
100-104
: LGTM!The placeholder data is appropriately typed and clearly marked with TODO comments for future implementation.
321-321
: LGTM!The formatting improvements and the platform fallback (
group.platform || "unknown"
) are appropriate defensive programming practices.Also applies to: 326-329, 380-380
447-448
: LGTM!The multi-line formatting of the placeholder text improves readability without changing functionality.
platforms/blabsy/src/components/user/user-share.tsx (2)
43-62
: Usage of motion components appears correct.The component correctly uses
AnimatePresence
(line 43) to handle enter/exit animations andmotion.div
(line 48) as a polymorphic component with HeadlessUI'sPopover.Panel
. The variants spreading (line 49) follows the expected pattern for motion animations.Assuming the
motion/react
package maintains API compatibility withframer-motion
, this implementation should work without changes.
3-3
: Verified motion package migration:motion
is inpackage.json
, allframer-motion
imports removed, and everyAnimatePresence
,motion
, and related type import now correctly comes frommotion/react
.platforms/group-charter-manager/src/app/page.tsx (1)
186-187
: LGTM! Clean visual styling update.The transition from
trend
/trendDirection
props to gradient-based styling simplifies the StatsCard component interface and provides a cleaner visual design with gradient backgrounds.Also applies to: 192-193
platforms/group-charter-manager/src/components/auth/login-screen.tsx (1)
105-118
: LGTM: Formatting improvements.The JSX structure and indentation changes improve code readability without altering functionality. The conditional text update on line 156 correctly adapts messaging for mobile vs. desktop contexts.
Also applies to: 156-158, 172-178
platforms/blabsy/src/pages/user/[id]/with_replies.tsx (1)
1-1
: Migration from framer-motion to motion/react validated
motion
dependency (^12.0.0) exists in package.jsonAnimatePresence
frommotion/react
supportsmode='popLayout'
identically- No API or type issues detected; build and behavior remain unchanged
platforms/eVoting/src/app/(app)/[id]/page.tsx (2)
438-438
: Remove redundantas string
casts onvisibility
.The
visibility
field is already typed as'public' | 'private'
, so you can compare directly:selectedPoll.visibility !== "private"Apply this refactor at lines 438, 555, and 1276.
Likely an incorrect or invalid review comment.
1-1412
: Build verification needed for eVoting platformThe build failed in CI due to missing dependencies (“next: not found”). Please ensure the
platforms/eVoting
project installs its dependencies and builds successfully:cd platforms/eVoting pnpm install pnpm build
platforms/blabsy/src/components/aside/suggestions.tsx (1)
2-2
: LGTM! Import path updated correctly.The migration from
framer-motion
tomotion/react
is applied consistently. The motion API usage remains unchanged, ensuring backward compatibility.platforms/blabsy/src/components/input/input-options.tsx (1)
2-2
: LGTM! Animation import migrated successfully.The import path update from
framer-motion
tomotion/react
maintains full compatibility with existing motion component usage throughout the file.platforms/blabsy/src/components/input/input.tsx (1)
3-3
: LGTM! Animation imports migrated consistently.Both runtime components (
AnimatePresence
,motion
) and type imports (Variants
) have been correctly updated tomotion/react
. The migration maintains full API compatibility with no changes to component behavior.Also applies to: 23-23
platforms/blabsy/src/components/user/user-nav.tsx (1)
1-1
: LGTM! Import path updated correctly.The motion import has been successfully migrated to
motion/react
with no changes to the component's animation behavior.platforms/blabsy/src/lib/hooks/useInfiniteScroll.tsx (1)
4-4
: LGTM! Hook import migrated successfully.The motion import path has been updated to
motion/react
while preserving the hook's functionality and motion component usage.platforms/blabsy/src/components/sidebar/mobile-sidebar.tsx (1)
7-7
: LGTM! Type import migrated correctly.The
Variants
type import has been updated tomotion/react
, maintaining type compatibility with the variant definition used in the component.platforms/blabsy/src/components/tweet/tweet-status.tsx (1)
1-1
: LGTM! Import path updated correctly.The motion import has been migrated to
motion/react
with no changes to the component's animation behavior or structure.platforms/blabsy/src/components/tweet/tweet-share.tsx (1)
4-4
: Import migration looks correct.The migration from
framer-motion
tomotion/react
is consistent with the broader PR objective to fix builds across multiple frontends.platforms/cerberus/tsconfig.json (1)
5-7
: Formatting improvements look good.The reformatting of
lib
,include
, andexclude
arrays to multi-line format improves readability and follows standard JSON formatting conventions. No semantic changes.Also applies to: 21-27
platforms/blabsy/src/components/tweet/tweet-actions.tsx (1)
5-5
: Type imports correctly updated.Both runtime and type imports (
Variants
) have been consistently migrated fromframer-motion
tomotion/react
, ensuring type safety is maintained throughout the migration.Also applies to: 26-26
platforms/blabsy/package.json (2)
25-25
: motion package replacement verifiedConfirmed
[email protected]
is the intended framer-motion alternative and noframer-motion
imports remain inplatforms/blabsy
.
40-41
: Provide Firebase config and re-verify build
TS 5.0.4 and @types/[email protected] compile without errors, but the Next.js build fails due to missing Firebase config. Set the required FIREBASE_* environment variables and rerunpnpm run build
to confirm no type or build errors.platforms/cerberus/package.json (1)
30-31
: LGTM!The addition of the
web3-adapter
workspace dependency correctly reflects the refactoring to externalize the Web3 adapter functionality into a separate package.platforms/eVoting/tsconfig.json (1)
25-25
: LGTM!The addition of
baseUrl: "."
is essential for the path alias"@/*": ["src/*"]
to function correctly. This likely resolves module resolution failures during build.platforms/group-charter-manager/package.json (1)
24-56
: LGTM!The added Radix UI components (
react-separator
,react-toggle
,react-tooltip
) andzustand
state management library appropriately support the UI refactoring mentioned in the PR summary.platforms/blabsy/src/components/tweet/tweet.tsx (1)
2-2
: LGTM!The migration from
framer-motion
tomotion/react
for animation primitives is consistent with the broader codebase migration and maintains the same API surface.Also applies to: 18-18
platforms/blabsy/src/pages/user/[id]/media.tsx (1)
1-1
: LGTM!The import update from
framer-motion
tomotion/react
aligns with the migration pattern applied across the blabsy platform.platforms/blabsy/tsconfig.json (1)
4-42
: LGTM!The formatting changes improve readability without affecting build behavior or TypeScript configuration semantics.
platforms/blabsy/src/lib/utils.ts (1)
2-2
: Confirm motion package dependency
Themotion
package (^12.0.0
) is declared in platforms/blabsy/package.json.platforms/blabsy/src/components/modal/image-modal.tsx (1)
4-4
: Confirm motion/react migration across workspaceEnsure the package for motion/react is installed in this package and remaining framer-motion imports are removed to avoid bundling both.
Would you like a repo scan script to list any lingering
framer-motion
imports?infrastructure/control-panel/package.json (1)
23-23
: Adapter switch to Node: verify removal and runtimeConfirm
@sveltejs/adapter-static
is removed from this workspace to avoid conflicts, and that your deployment/start process runs the Node adapter output (e.g.,node build/index.js
if applicable).infrastructure/control-panel/svelte.config.js (1)
1-10
: Node adapter: confirm SSR/prerender assumptionsWith
@sveltejs/adapter-node
, ensure no routes/assets rely on static prerender. If any pages were previously prerendered, explicitly configurekit.prerender
as needed to prevent surprises at runtime.platforms/blabsy/src/components/input/image-preview.tsx (1)
1-2
: Confirm motion/react dependency and clean-upMake sure
motion
is added in the relevant package andframer-motion
is removed to prevent dual bundles.platforms/blabsy/src/components/user/user-edit-profile.tsx (1)
137-160
: Solid: safer file-handling flowEdits to
editImage
improve readability and validation. Looks good.package.json (1)
25-36
: Validate onlyBuiltDependencies across OS/CIChanges here can skip builds for native modules not listed. Confirm all workspaces still install on Linux/macOS/Windows (especially
sqlite3
which compiles).If helpful, I can provide a script to scan for native modules that declare build steps and compare against this list.
infrastructure/control-panel/src/lib/services/cacheService.ts (1)
35-38
: Good server-only dynamic import to keep lowdb out of client bundlesThe guarded dynamic imports are the right approach for build-time and SSR.
platforms/blabsy/src/components/chat/chat-window.tsx (1)
354-357
: Good guard against null senderId when resolving userDataPrevents undefined index lookups for system messages.
platforms/cerberus/src/web3adapter/watchers/subscriber.ts (1)
9-9
: Import migration approved Theweb3-adapter
dependency is declared (workspace:*
) in platforms/cerberus/package.json.platforms/blabsy/src/pages/tweet/[id].tsx (1)
3-3
: Migration fromframer-motion
tomotion/react
verified
Package.json declaresmotion
@^12.0.0 and no remainingframer-motion
imports found.platforms/blabsy/src/components/input/input-form.tsx (1)
3-3
: LGTM! Clean migration to motion/react.The import path updates from
framer-motion
tomotion/react
are consistent with the PR-wide migration pattern. The public API usage remains unchanged, ensuring no behavioral impact.Also applies to: 16-16
{/* Charter Signing Status */} | ||
{group.charter && ( | ||
<CharterSigningStatus | ||
groupId={group.id} | ||
charterContent={group.charter} | ||
<CharterSigningStatus | ||
groupId={group.id} | ||
charterContent={group.charter} | ||
/> |
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.
Sidebar signing list now stays stale after someone signs
<CharterSigningStatus>
owns its own fetch cycle (keyed on groupId
/charterContent
), so the local setSigningStatus
updates you trigger when a member signs no longer propagate to the sidebar card. After signing, the CTA flips to “Charter Signed”, but the members list still shows the user as “Not signed yet” until you hard-refresh. Please wire the component back into the same state updates (e.g. pass the updated signingStatus
down, expose a refresh callback, or force a re-mount via a refresh token) so the sidebar stays in sync.
🤖 Prompt for AI Agents
In platforms/group-charter-manager/src/app/charter/[id]/page.tsx around lines
421 to 426, the CharterSigningStatus component fetches its own state so local
setSigningStatus updates don't update the sidebar; change the usage to accept
external state or a refresh hook: pass the current signingStatus (from parent
state) as a prop and also pass an onRefresh callback (or a refreshToken prop you
increment) so when a member signs the parent updates signingStatus and calls the
callback or increments the token to force CharterSigningStatus to re-read or
re-mount and display the updated members list.
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: 9
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
platforms/group-charter-manager/src/app/charter/[id]/page.tsx (3)
146-154
: Remove debug logging from production code.This debug
console.log
should be removed or gated behind a development environment check, as it may expose sensitive user and group identifiers in production browser consoles.Apply this diff to remove the debug logging:
- // Debug logging - console.log('Charter Detail Debug:', { - user: user?.id, - groupOwner: group?.owner, - groupAdmins: group?.admins, - userIsOwner: group?.owner === user?.id, - userIsAdmin: group?.admins?.includes(user?.id || ''), - canEdit, - isEditing - }); -Alternatively, gate it behind a development check:
- // Debug logging - console.log('Charter Detail Debug:', { - user: user?.id, - groupOwner: group?.owner, - groupAdmins: group?.admins, - userIsOwner: group?.owner === user?.id, - userIsAdmin: group?.admins?.includes(user?.id || ''), - canEdit, - isEditing - }); + if (process.env.NODE_ENV === 'development') { + console.log('Charter Detail Debug:', { + user: user?.id, + groupOwner: group?.owner, + groupAdmins: group?.admins, + userIsOwner: group?.owner === user?.id, + userIsAdmin: group?.admins?.includes(user?.id || ''), + canEdit, + isEditing + }); + }
279-293
: Simplify the inline IIFE pattern.The immediately-invoked function expression (IIFE) used to compute
currentUser
inline adds unnecessary complexity. This pattern is repeated for both the "Sign Charter" and "Charter Signed" buttons, making the code harder to read and maintain.Consider extracting the
currentUser
computation once before the button rendering logic:) : ( <> + {/* Compute current user signing status once */} + {(() => { + const currentUser = signingStatus?.participants.find((p: any) => p.id === user?.id); + const hasUserSigned = currentUser?.hasSigned; + + return ( + <> {/* Edit Charter Button (only for admins) */} {showEditButton && ( <Button onClick={handleEditStart} className="gradient-primary text-white px-6 py-3 rounded-2xl font-medium hover:shadow-xl transition-all duration-300" > <Edit className="mr-2" size={18} /> Edit Charter </Button> )} {/* Sign Charter Button (only if current user hasn't signed) */} - {group.charter && signingStatus && !signingStatusLoading && ( - (() => { - const currentUser = signingStatus.participants.find((p: any) => p.id === user?.id); - return currentUser && !currentUser.hasSigned; - })() && ( + {group.charter && signingStatus && !signingStatusLoading && currentUser && !hasUserSigned && ( <Button onClick={() => setShowSigningInterface(true)} variant="outline" className="bg-green-600 text-white px-6 py-3 rounded-2xl font-medium hover:bg-green-700 transition-all duration-300 shadow-lg" > <CheckCircle className="mr-2" size={18} /> Sign Charter </Button> - ) )} {/* Disabled button for users who have already signed */} - {group.charter && signingStatus && !signingStatusLoading && ( - (() => { - const currentUser = signingStatus.participants.find((p: any) => p.id === user?.id); - return currentUser && currentUser.hasSigned; - })() && ( + {group.charter && signingStatus && !signingStatusLoading && currentUser && hasUserSigned && ( <Button disabled variant="outline" className="bg-green-50 text-green-600 border-green-600 cursor-not-allowed px-6 py-3 rounded-2xl font-medium" > <CheckCircle className="mr-2" size={18} /> Charter Signed </Button> - ) )} + </> + ); + })()} </> )}Alternatively, use
useMemo
to compute the current user once and avoid nesting:const currentUserSigningStatus = useMemo(() => { if (!signingStatus || signingStatusLoading) return null; return signingStatus.participants.find((p: any) => p.id === user?.id); }, [signingStatus, signingStatusLoading, user?.id]); const hasUserSigned = currentUserSigningStatus?.hasSigned;Then simplify the button conditions:
{/* Sign Charter Button */} {group.charter && currentUserSigningStatus && !hasUserSigned && ( <Button>Sign Charter</Button> )} {/* Charter Signed Button */} {group.charter && currentUserSigningStatus && hasUserSigned && ( <Button disabled>Charter Signed</Button> )}
447-460
: Replaceany
types with proper TypeScript types.The use of
any
types in thesetSigningStatus
updater defeats TypeScript's type safety. You should use proper typing based on theSigningStatus
interface already used in the component.First, ensure the
SigningStatus
interface is properly defined (if not already). Based on the usage, it should look something like:interface Participant { id: string; name?: string; ename?: string; hasSigned: boolean; isAdmin?: boolean; isOwner?: boolean; } interface SigningStatus { participants: Participant[]; }Then apply this diff to use proper types:
onSigningStatusUpdate={(participantId, hasSigned) => { // Immediately update the local signing status if (signingStatus) { - setSigningStatus((prev: any) => { + setSigningStatus((prev: SigningStatus | null) => { if (!prev) return prev; - const updatedParticipants = prev.participants.map((participant: any) => + const updatedParticipants = prev.participants.map((participant) => participant.id === participantId ? { ...participant, hasSigned } : participant ); return { ...prev, participants: updatedParticipants }; }); } }}platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (2)
3-3
: Client component must not use Reactuse()
; fix params handling
use()
is not supported in Client Components. Also,params
should not be a Promise here. Use the prop directly.Apply this diff:
-import { useState, useEffect, use } from "react"; +import { useState, useEffect } from "react"; @@ -export default function EditCharter({ - params, -}: { - params: Promise<{ id: string }>; -}) { - const { id } = use(params); +export default function EditCharter({ + params, +}: { + params: { id: string }; +}) { + const { id } = params;Also applies to: 90-96
41-57
: Form schema will always fail: required base fields aren’t in the form
editCharterSchema
extendsinsertCharterSchema
which requiresid
,createdAt
,updatedAt
. These aren’t registered fields, so zodResolver will reject submissions.Minimal fix: make base fields optional for the edit schema.
-const editCharterSchema = insertCharterSchema.extend({ +const editCharterSchema = insertCharterSchema.partial().extend({ name: z.string().optional(), description: z.string().optional(), groupId: z.string().optional(), isActive: z.boolean().optional(), autoApprove: z.boolean().optional(), allowPosts: z.boolean().optional(), guidelines: z .array(z.string()) .min(1, "At least one guideline is required"), });platforms/blabsy/src/components/aside/aside-trends.tsx (1)
14-18
: Remove unused variants export.The
variants
object is exported but never used within this component. Lines 42-44 define the same animation properties inline, making this export dead code.Apply this diff to remove the unused export:
-export const variants = { - initial: { opacity: 0 }, - animate: { opacity: 1 }, - transition: { duration: 0.8 } -}; - type AsideTrendsProps = {
♻️ Duplicate comments (2)
platforms/blabsy/src/components/tweet/tweet-actions.tsx (1)
5-5
: Same motion/react migration as other components.This file follows the same pattern as
platforms/blabsy/src/components/input/input-options.tsx
. Please refer to the verification comment on that file regarding theframer-motion
tomotion/react
migration.platforms/cerberus/src/controllers/WebhookController.ts (1)
7-7
: Same web3-adapter migration as other cerberus files.This file follows the same pattern as
platforms/cerberus/src/web3adapter/watchers/subscriber.ts
. Please refer to the verification comment on that file regarding theweb3-adapter
package migration.
🧹 Nitpick comments (19)
platforms/group-charter-manager/src/components/auth/login-screen.tsx (1)
74-82
: Improve type safety for window property access.The type assertions
(window as any)
bypass TypeScript's type safety, which can mask potential runtime errors. Additionally,navigator.vendor
is deprecated and unreliable across browsers.Consider using proper type declarations:
const getAppStoreLink = () => { - const userAgent = navigator.userAgent || navigator.vendor || (window as any).opera; + const userAgent = navigator.userAgent || ''; 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(userAgent) && !('MSStream' in window)) { return "https://apps.apple.com/in/app/eid-for-w3ds/id6747748667" } return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; };Using
'MSStream' in window
is type-safe and achieves the same IE11 detection without type assertions.platforms/eVoting/src/app/(app)/[id]/page.tsx (5)
387-388
: Avoidany
type annotations—define proper interfaces.Multiple inline functions use
any
type annotations (e.g.,(result: any, index: number)
,(r: any)
), which defeats TypeScript's type safety. Consider defining proper interfaces forblindVoteResults.optionResults
items.Example interface:
interface BlindVoteOptionResult { optionText: string; voteCount: number; isTied?: boolean; }Then update the map:
-blindVoteResults.optionResults.map((result: any, index: number) => { - const isWinner = result.voteCount === Math.max(...blindVoteResults.optionResults.map((r: any) => r.voteCount)); +blindVoteResults.optionResults.map((result: BlindVoteOptionResult, index: number) => { + const isWinner = result.voteCount === Math.max(...blindVoteResults.optionResults.map((r: BlindVoteOptionResult) => r.voteCount));
469-479
: Define interface for poll results to improve type safety.Similar to the blind vote results, the public poll results use
any
annotations extensively. Define a proper interface for result objects based on the voting mode.Example:
interface PollResult { option: string; votes?: number; totalPoints?: number; averagePoints?: string; isWinner?: boolean; isTied?: boolean; percentage?: number; }
569-569
: Type vote data structures properly.The vote data processing uses
any
for items in reduce and find operations. Since vote data has different structures based on mode (normal/point/rank), consider using discriminated unions or generics.Example:
interface VoteDataNormal { mode: "normal"; data: string[]; } interface VoteDataPoint { mode: "point"; data: { option: string; points: number }[]; } interface VoteDataRank { mode: "rank"; data: { option: string; points: number }[]; } type VoteData = VoteDataNormal | VoteDataPoint | VoteDataRank;
1286-1287
: Define interface for voter details.The voter details mapping uses
any
type. Define a proper interface based on the expected voter data structure.Example:
interface VoterDetail { firstName?: string; lastName?: string; email?: string; profileImageUrl?: string; optionId: string; }Then update:
-resultsData.voterDetails.map((voter: any, index: number) => ( +resultsData.voterDetails.map((voter: VoterDetail, index: number) => (
438-438
: Remove unnecessaryas string
casts onvisibility
.visibility
is already typed as"public" | "private"
, so useselectedPoll.visibility !== "private"
directly (lines 438, 555, 1276).platforms/group-charter-manager/src/app/page.tsx (2)
219-295
: Consider extracting group card rendering into a separate component.The group card rendering logic (lines 219-295) has deep nesting (5-6 levels) which can make the code harder to maintain and test. Consider extracting this into a dedicated
GroupCard
component that accepts agroup
object anduser
as props.This refactor would improve code organization and make the Dashboard component more focused on orchestration rather than rendering details.
Example structure:
// components/group-card.tsx interface GroupCardProps { group: Group; userId: string | undefined; } export function GroupCard({ group, userId }: GroupCardProps) { const hasCharter = group.charter && group.charter.trim() !== ''; const isOwner = group.owner === userId; const isAdmin = group.admins?.includes(userId || ''); const hasSigned = group.hasSigned || false; return ( <Card className={...}> {/* Card content here */} </Card> ); }Then in the Dashboard:
{groups.map((group) => ( <GroupCard key={group.id} group={group} userId={user?.id} /> ))}
238-238
: Consider internationalization for user-facing text.Multiple hardcoded English strings are present in the component (e.g., "Charter signed", "Please sign the charter", "No charter found", "members"). If the application needs to support multiple languages, consider using an internationalization library.
This is a minor concern and can be addressed in a future PR if i18n is planned for the application.
Also applies to: 242-242, 246-246, 273-273
platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (3)
121-176
: Eliminate debug logs, shadowing, and redundant setTimeout/setValue; rely on a single resetCurrent effect logs sensitive data, shadows
guidelines
, and re-sets values via a timeout. This is brittle and noisy.Apply this diff:
- if (charter) { - const charterData = charter as Charter; - const guidelines = charterData.guidelines || []; - - console.log("Charter data loaded:", charterData); - console.log("Charter name:", charterData.name); - console.log("Charter description:", charterData.description); - console.log("Charter guidelines:", guidelines); - console.log("Charter groupId:", charterData.groupId); + if (charter) { + const charterData = charter as Charter; + const charterGuidelines = charterData.guidelines || []; @@ - setGuidelines(guidelines.length > 0 ? guidelines : [""]); + setGuidelines(charterGuidelines.length > 0 ? charterGuidelines : [""]); @@ - const formValues = { - name: charterData.name || "", - description: charterData.description || "", - guidelines: guidelines, - groupId: charterData.groupId || undefined, - isActive: - charterData.isActive !== undefined ? charterData.isActive : true, - autoApprove: - charterData.autoApprove !== undefined - ? charterData.autoApprove - : false, - allowPosts: - charterData.allowPosts !== undefined - ? charterData.allowPosts - : true, - }; - - console.log("Form values to set:", formValues); - - // Use reset to populate all form fields at once - form.reset(formValues); - - // Also manually set values to ensure they stick - setTimeout(() => { - form.setValue("name", charterData.name || ""); - form.setValue("description", charterData.description || ""); - form.setValue("guidelines", guidelines); - form.setValue("groupId", charterData.groupId || undefined); - form.setValue( - "isActive", - charterData.isActive !== undefined ? charterData.isActive : true - ); - form.setValue( - "autoApprove", - charterData.autoApprove !== undefined - ? charterData.autoApprove - : false - ); - form.setValue( - "allowPosts", - charterData.allowPosts !== undefined ? charterData.allowPosts : true - ); - }, 100); + form.reset({ + name: charterData.name || "", + description: charterData.description || "", + guidelines: charterGuidelines, + groupId: charterData.groupId || undefined, + isActive: charterData.isActive ?? true, + autoApprove: charterData.autoApprove ?? false, + allowPosts: charterData.allowPosts ?? true, + });
200-217
: Avoid dual source of truth for guidelines; use RHF’s Field ArrayManaging guidelines in both component state and form state risks drift. Prefer
useFieldArray
so the form is the single source of truth.If you want, I can provide a minimal
useFieldArray
refactor for add/update/remove.
100-105
: Placeholders will force “Not Found”; confirm temporaryWith
charter: null
and emptygroups
, the page always shows the Not Found state. Confirm this is intentional for build-unblock, and track wiring data fetch next.I can draft the fetch + loading wiring for your data layer.
infrastructure/control-panel/src/lib/services/cacheService.ts (2)
21-21
: Restore type safety with type‑only imports; keep runtime imports server‑only.Use type‑only imports to avoid bundling while keeping strong types.
Apply:
- private db: any | null = null; + private db: Low<CacheData> | null = null;Add at top of file (type‑only, erased at build):
import type { Low } from 'lowdb'; import type { JSONFile } from 'lowdb/node';Also applies to: 35-38
31-54
: Make init idempotent and concurrency‑safe; stabilize cache path.Concurrent callers can race the isInitialized check; also consider a stable absolute path for the cache file.
Example:
class CacheService { + private initPromise: Promise<void> | null = null; @@ private async init() { - if (this.isInitialized) return; + if (this.isInitialized) return; + if (this.initPromise) return this.initPromise; - try { + this.initPromise = (async () => { + try { // Dynamically import lowdb only on server const { Low } = await import('lowdb'); const { JSONFile } = await import('lowdb/node'); // Initialize LowDB with JSON file adapter - const adapter = new JSONFile<CacheData>(CACHE_FILE); + const adapter = new JSONFile<CacheData>(CACHE_FILE); this.db = new Low(adapter, defaultData); @@ - this.isInitialized = true; - } catch (error) { - console.error('Failed to initialize cache service:', error); - } + this.isInitialized = true; + } catch (error) { + console.error('Failed to initialize cache service:', error); + } finally { + this.initPromise = null; + } + })(); + return this.initPromise; }Optionally, define an absolute cache path:
// replace CACHE_FILE with: import path from 'node:path'; const CACHE_FILE = path.resolve(process.cwd(), 'evault-cache.json');platforms/blabsy/src/components/modal/image-modal.tsx (1)
107-107
: Type safety degradation withas any
cast.Casting to
any
removes type safety. If thebackdrop.exit
property doesn't match the expected type inmotion/react
, consider either:
- Updating the
backdrop
variants definition to match the new library's type requirements- Using a more specific type assertion if possible
Check the backdrop variants definition and verify the correct type:
#!/bin/bash # Find the backdrop variants definition rg -n -A5 -B2 'backdrop.*=|export.*backdrop' platforms/blabsy/src/components/modal/platforms/blabsy/src/components/input/image-preview.tsx (2)
1-2
: LGTM on motion migration.The import changes from
framer-motion
tomotion/react
are correctly applied.Note: The explicit
React
import on Line 1 may be unnecessary if using React 17+ with the new JSX transform, but it doesn't cause issues.
23-32
: Consider restoring type annotation for better type safety.The removal of
MotionProps
type annotation reduces type checking. While the code works, explicit typing helps catch errors at compile time.If
motion/react
exports compatible types, consider:-const variants = { +const variants: Variants = { initial: { opacity: 0, scale: 0.5 }, animate: { opacity: 1, scale: 1, transition: { duration: 0.3 } }, exit: { opacity: 0, scale: 0.5 }, transition: { type: 'spring' as const, duration: 0.5 } };platforms/eVoting/src/app/(auth)/login/page.tsx (1)
70-79
: SSR guard improves build safety.The added
navigator
andwindow
checks prevent SSR errors during Next.js builds. This is a necessary fix for the build issues.Optional type safety improvement:
The
as any
casts work but reduce type safety. Consider using more specific types:const getAppStoreLink = () => { if (typeof navigator === 'undefined') { return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; } const userAgent = navigator.userAgent || navigator.vendor || (typeof window !== 'undefined' && (window as Window & { opera?: string }).opera); if (/android/i.test(userAgent)) { return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; } const isIOS = /iPad|iPhone|iPod/.test(userAgent) && typeof window !== 'undefined' && !(window as Window & { MSStream?: unknown }).MSStream; if (isIOS) { return "https://apps.apple.com/in/app/eid-for-w3ds/id6747748667"; } return "https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet"; };platforms/blabsy/src/components/aside/aside-trends.tsx (2)
14-18
: Consider type consistency across the codebase.Other components in the same platform still use the
Variants
type annotation for their variants objects (e.g.,input.tsx
,more-settings.tsx
,tweet-actions.tsx
). If theVariants
type is available frommotion/react
, consider maintaining consistency.If
Variants
type is available:import { motion, type Variants } from 'motion/react'; export const variants: Variants = { initial: { opacity: 0 }, animate: { opacity: 1 }, transition: { duration: 0.8 } };However, since the variants are unused (see previous comment), removing them entirely is the preferred solution.
2-2
: Remove redundant React import. With React 18.2 and JSX set to “preserve,” the automatic runtime coversimport React
; drop it and confirm your build still passes.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (101)
infrastructure/control-panel/package.json
(2 hunks)infrastructure/control-panel/src/lib/services/cacheService.ts
(2 hunks)infrastructure/control-panel/svelte.config.js
(1 hunks)infrastructure/control-panel/vite.config.ts
(1 hunks)mappings/.gitignore
(1 hunks)metastate.compose.yml
(1 hunks)package.json
(1 hunks)platforms/blabsy/package.json
(3 hunks)platforms/blabsy/src/components/aside/aside-trends.tsx
(4 hunks)platforms/blabsy/src/components/aside/suggestions.tsx
(1 hunks)platforms/blabsy/src/components/chat/chat-window.tsx
(7 hunks)platforms/blabsy/src/components/input/image-preview.tsx
(5 hunks)platforms/blabsy/src/components/input/input-form.tsx
(2 hunks)platforms/blabsy/src/components/input/input-options.tsx
(1 hunks)platforms/blabsy/src/components/input/input.tsx
(2 hunks)platforms/blabsy/src/components/layout/user-follow-layout.tsx
(1 hunks)platforms/blabsy/src/components/layout/user-home-layout.tsx
(1 hunks)platforms/blabsy/src/components/login/login-main.tsx
(3 hunks)platforms/blabsy/src/components/modal/image-modal.tsx
(3 hunks)platforms/blabsy/src/components/modal/modal.tsx
(1 hunks)platforms/blabsy/src/components/sidebar/mobile-sidebar.tsx
(1 hunks)platforms/blabsy/src/components/sidebar/more-settings.tsx
(2 hunks)platforms/blabsy/src/components/sidebar/sidebar-profile.tsx
(1 hunks)platforms/blabsy/src/components/tweet/number-stats.tsx
(1 hunks)platforms/blabsy/src/components/tweet/tweet-actions.tsx
(2 hunks)platforms/blabsy/src/components/tweet/tweet-share.tsx
(1 hunks)platforms/blabsy/src/components/tweet/tweet-status.tsx
(1 hunks)platforms/blabsy/src/components/tweet/tweet.tsx
(2 hunks)platforms/blabsy/src/components/ui/custom-icon.tsx
(10 hunks)platforms/blabsy/src/components/ui/loading.tsx
(2 hunks)platforms/blabsy/src/components/user/user-cards.tsx
(1 hunks)platforms/blabsy/src/components/user/user-edit-profile.tsx
(2 hunks)platforms/blabsy/src/components/user/user-header.tsx
(1 hunks)platforms/blabsy/src/components/user/user-nav.tsx
(1 hunks)platforms/blabsy/src/components/user/user-share.tsx
(1 hunks)platforms/blabsy/src/components/view/view-tweet.tsx
(1 hunks)platforms/blabsy/src/lib/context/window-context.tsx
(2 hunks)platforms/blabsy/src/lib/hooks/useInfiniteScroll.tsx
(1 hunks)platforms/blabsy/src/lib/utils.ts
(1 hunks)platforms/blabsy/src/pages/bookmarks.tsx
(1 hunks)platforms/blabsy/src/pages/home.tsx
(1 hunks)platforms/blabsy/src/pages/people.tsx
(1 hunks)platforms/blabsy/src/pages/tweet/[id].tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/index.tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/likes.tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/media.tsx
(1 hunks)platforms/blabsy/src/pages/user/[id]/with_replies.tsx
(1 hunks)platforms/blabsy/tsconfig.json
(2 hunks)platforms/cerberus/package.json
(2 hunks)platforms/cerberus/src/controllers/WebhookController.ts
(1 hunks)platforms/cerberus/src/web3adapter/watchers/subscriber.ts
(1 hunks)platforms/cerberus/tsconfig.json
(2 hunks)platforms/eVoting/next.config.ts
(1 hunks)platforms/eVoting/src/app/(app)/[id]/page.tsx
(46 hunks)platforms/eVoting/src/app/(auth)/login/page.tsx
(2 hunks)platforms/eVoting/src/app/(auth)/logout/page.tsx
(0 hunks)platforms/eVoting/src/app/(auth)/register/page.tsx
(0 hunks)platforms/eVoting/src/components/poll-card.tsx
(0 hunks)platforms/eVoting/src/hooks/use-toast.ts
(1 hunks)platforms/eVoting/src/lib/apiClient.ts
(2 hunks)platforms/eVoting/tsconfig.json
(2 hunks)platforms/group-charter-manager/package.json
(3 hunks)platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx
(7 hunks)platforms/group-charter-manager/src/app/charter/[id]/page.tsx
(7 hunks)platforms/group-charter-manager/src/app/page.tsx
(5 hunks)platforms/group-charter-manager/src/components/auth/login-screen.tsx
(4 hunks)platforms/group-charter-manager/src/components/charter-signing-status.tsx
(2 hunks)platforms/group-charter-manager/src/components/layout/navbar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/accordion.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/alert.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/aspect-ratio.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/avatar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/breadcrumb.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/calendar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/carousel.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/chart.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/checkbox.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/collapsible.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/context-menu.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/drawer.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/hover-card.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/input-otp.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/menubar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/navigation-menu.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/pagination.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/progress.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/radio-group.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/resizable.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/scroll-area.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/select.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/sidebar.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/slider.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/table.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/tabs.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/textarea.tsx
(0 hunks)platforms/group-charter-manager/src/components/ui/toggle-group.tsx
(0 hunks)platforms/group-charter-manager/src/components/wysiwyg-editor.tsx
(2 hunks)platforms/pictique/src/routes/(protected)/group/[id]/+page.ts
(1 hunks)platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts
(1 hunks)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts
(1 hunks)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts
(1 hunks)
💤 Files with no reviewable changes (32)
- platforms/group-charter-manager/src/components/ui/slider.tsx
- platforms/eVoting/src/app/(auth)/register/page.tsx
- platforms/group-charter-manager/src/components/ui/alert.tsx
- platforms/group-charter-manager/src/components/ui/toggle-group.tsx
- platforms/group-charter-manager/src/components/ui/accordion.tsx
- platforms/group-charter-manager/src/components/ui/textarea.tsx
- platforms/group-charter-manager/src/components/ui/hover-card.tsx
- platforms/group-charter-manager/src/components/ui/avatar.tsx
- platforms/group-charter-manager/src/components/ui/table.tsx
- platforms/group-charter-manager/src/components/ui/drawer.tsx
- platforms/eVoting/src/components/poll-card.tsx
- platforms/group-charter-manager/src/components/ui/collapsible.tsx
- platforms/group-charter-manager/src/components/ui/checkbox.tsx
- platforms/group-charter-manager/src/components/ui/breadcrumb.tsx
- platforms/group-charter-manager/src/components/ui/scroll-area.tsx
- platforms/group-charter-manager/src/components/ui/chart.tsx
- platforms/group-charter-manager/src/components/ui/aspect-ratio.tsx
- platforms/group-charter-manager/src/components/ui/calendar.tsx
- platforms/group-charter-manager/src/components/layout/navbar.tsx
- platforms/eVoting/src/app/(auth)/logout/page.tsx
- platforms/group-charter-manager/src/components/ui/progress.tsx
- platforms/group-charter-manager/src/components/ui/sidebar.tsx
- platforms/group-charter-manager/src/components/ui/tabs.tsx
- platforms/group-charter-manager/src/components/ui/navigation-menu.tsx
- platforms/group-charter-manager/src/components/ui/menubar.tsx
- platforms/group-charter-manager/src/components/ui/carousel.tsx
- platforms/group-charter-manager/src/components/ui/radio-group.tsx
- platforms/group-charter-manager/src/components/ui/select.tsx
- platforms/group-charter-manager/src/components/ui/input-otp.tsx
- platforms/group-charter-manager/src/components/ui/context-menu.tsx
- platforms/group-charter-manager/src/components/ui/resizable.tsx
- platforms/group-charter-manager/src/components/ui/pagination.tsx
🧰 Additional context used
🧬 Code graph analysis (11)
platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
prerender
(1-1)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
prerender
(1-1)
platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
prerender
(1-1)
platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
platforms/eVoting/src/lib/pollApi.ts (1)
pollApi
(102-199)
platforms/blabsy/src/components/login/login-main.tsx (1)
platforms/pictique/src/declaration.d.ts (1)
QRCode
(3-6)
platforms/group-charter-manager/src/app/charter/[id]/page.tsx (1)
platforms/group-charter-manager/src/components/charter-signing-status.tsx (1)
CharterSigningStatus
(31-141)
platforms/group-charter-manager/src/components/auth/login-screen.tsx (1)
platforms/group-charter-manager/src/lib/utils/mobile-detection.ts (1)
isMobileDevice
(1-6)
platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (1)
platforms/dreamSync/shared/schema.ts (1)
groups
(120-134)
platforms/blabsy/src/components/modal/image-modal.tsx (1)
platforms/blabsy/src/components/modal/modal.tsx (1)
backdrop
(34-34)
platforms/blabsy/src/components/aside/aside-trends.tsx (5)
platforms/blabsy/src/components/input/input.tsx (1)
variants
(38-41)platforms/blabsy/src/components/sidebar/more-settings.tsx (1)
variants
(13-21)platforms/blabsy/src/components/tweet/tweet-actions.tsx (1)
variants
(30-38)platforms/blabsy/src/components/tweet/tweet.tsx (1)
variants
(30-34)platforms/blabsy/src/components/user/user-header.tsx (1)
variants
(11-15)
platforms/pictique/src/routes/(protected)/group/[id]/members/+page.ts (3)
platforms/pictique/src/routes/(protected)/group/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/messages/[id]/+page.ts (1)
prerender
(1-1)platforms/pictique/src/routes/(protected)/profile/[id]/+page.ts (1)
prerender
(1-1)
🪛 ast-grep (0.39.6)
platforms/blabsy/src/components/chat/chat-window.tsx
[warning] 105-105: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 GitHub Actions: Check Code
package.json
[error] 1-1: Failed to add workspace 'rest-express' from 'platforms/dreamSync/package.json'; it already exists at 'platforms/marketplace/package.json'.
🪛 GitHub Actions: Check Format
package.json
[error] 1-1: Turbo: Failed to add workspace 'rest-express' from 'platforms/marketplace/package.json': workspace already exists at 'platforms/dreamSync/package.json'. Command 'pnpm check-format' (turbo run check-format) failed with exit code 1.
🪛 GitHub Actions: Check Lint
package.json
[error] 1-1: Turbo repo: Failed to add workspace 'rest-express' from 'platforms/dreamSync/package.json', it already exists at 'platforms/marketplace/package.json'. Command 'turbo run check-lint' exited with code 1.
🔇 Additional comments (47)
platforms/eVoting/src/hooks/use-toast.ts (1)
158-158
: LGTM!The explicit
boolean
type annotation improves type safety and aligns with TypeScript best practices. This change likely resolves strict mode compilation errors mentioned in the PR objectives.platforms/group-charter-manager/src/components/wysiwyg-editor.tsx (1)
33-33
: Type assertion correctly fixes TypeScript compilation.The
as string
assertion is appropriate here. Withasync: false
configured on line 11,marked.parse()
always returns a string, but TypeScript cannot automatically narrow the union typestring | Promise<string>
.platforms/blabsy/src/components/user/user-edit-profile.tsx (1)
214-214
: LGTM! Type cast resolves TypeScript compilation.The explicit type assertion ensures TypeScript recognizes the
blur()
method is available. Given that this handler is only used withInputField
components (lines 268-274) that render inputs or textareas, the cast is safe.platforms/group-charter-manager/src/components/charter-signing-status.tsx (1)
20-21
: Type safety improvement aligns with build fix objective.Formalizing
isAdmin
andisOwner
as optional fields resolves TypeScript compilation errors. The rendering logic (lines 121-130) already accesses these properties, so declaring them in the interface is essential.platforms/blabsy/src/pages/user/[id]/likes.tsx (1)
1-1
: Verify AnimatePresence API compatibility
- Confirm that
AnimatePresence
imported frommotion/react
supports themode='popLayout'
andmode='wait'
props used across the codebase.- No remaining
framer-motion
imports detected;motion
is listed inpackage.json
andframer-motion
removed.platforms/blabsy/src/components/sidebar/more-settings.tsx (1)
1-1
: Approve migration tomotion/react
Verifiedmotion
v^12.0.0 in dependencies; API remains compatible.platforms/blabsy/src/components/user/user-cards.tsx (1)
2-2
: Confirmmotion/react
API support
motion
v^12.0.0 is installed,framer-motion
removed, and all imports updated across the codebase. Ensure thatAnimatePresence mode="popLayout"
andmotion.div layout="position"
are supported and behave as expected inmotion/react
.platforms/group-charter-manager/src/components/auth/login-screen.tsx (2)
105-118
: LGTM!The header restructuring improves the layout organization, and the use of Next.js
Image
component follows best practices.
172-178
: LGTM!The Image component formatting is correct and follows Next.js best practices.
platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
1246-1266
: LGTM!The vote data object formatting and the signing completion callback logic are clear and properly structured.
platforms/blabsy/src/components/ui/custom-icon.tsx (2)
2-2
: LGTM!The explicit React import is necessary for the
React.ComponentType
type reference on line 14.
14-23
: Usesatisfies
to preserve specific icon keys
Removing the explicitRecord<string,…>
annotation and appending} satisfies Record<string, React.ComponentType<IconProps>>;
keeps
IconName
as"PinIcon" | "AppleIcon" | …
while enforcing the constraint. Ensure your TS version (≥4.9) supportssatisfies
and that the build still succeeds without the original annotation.platforms/group-charter-manager/src/app/page.tsx (1)
186-186
: StatsCard API usage is consistent
All<StatsCard>
components now use thegradient
prop and no instances oftrend
ortrendDirection
remain.platforms/group-charter-manager/src/app/charter/[id]/edit/page.tsx (1)
380-381
: Verify PlatformBadge accepted valuesPassing
group.platform || "unknown"
assumes PlatformBadge supports "unknown". If it doesn’t, render a neutral badge or hide it.platforms/blabsy/src/components/tweet/tweet-status.tsx (1)
1-1
: LGTM!The import migration is correct and consistent with the broader refactor.
platforms/blabsy/src/components/sidebar/mobile-sidebar.tsx (1)
7-7
: LGTM!Type import migration is correct and maintains the same functionality.
platforms/blabsy/src/components/layout/user-home-layout.tsx (1)
2-2
: LGTM!The import change maintains compatibility with the component's animation usage.
platforms/blabsy/src/pages/bookmarks.tsx (1)
2-2
: LGTM!AnimatePresence import migration is correct and preserves the animation behavior.
platforms/blabsy/src/pages/home.tsx (1)
1-1
: LGTM!The import path update is correct and consistent with the migration strategy.
platforms/blabsy/src/pages/user/[id]/media.tsx (1)
1-1
: LGTM!AnimatePresence import correctly migrated to motion/react.
platforms/blabsy/src/pages/people.tsx (1)
2-2
: LGTM!The import migration maintains the animation functionality while addressing the build issues.
platforms/blabsy/src/components/user/user-share.tsx (1)
3-3
: LGTM — motion ^12.0.0 is declared in package.json and no framer-motion imports remain. The migration fromframer-motion
tomotion/react
is clean and consistent.platforms/blabsy/src/pages/tweet/[id].tsx (1)
3-3
: LGTM! Consistent library migration.The import path update from
framer-motion
tomotion/react
is clean and preserves functionality. Themotion
package is the modern successor toframer-motion
with improved performance and tree-shaking.platforms/blabsy/src/components/user/user-header.tsx (1)
3-3
: LGTM! Type and runtime imports migrated consistently.Both the runtime components (
AnimatePresence
,motion
) and theVariants
type are correctly updated to import frommotion/react
, maintaining full compatibility.Also applies to: 9-9
platforms/blabsy/src/components/sidebar/sidebar-profile.tsx (1)
1-1
: LGTM! Import migration complete.The animation imports are correctly updated while preserving existing functionality.
platforms/blabsy/src/components/layout/user-follow-layout.tsx (1)
1-1
: LGTM! Import path updated correctly.The
motion
import is correctly migrated tomotion/react
with no impact on the component's rendering behavior.platforms/blabsy/src/components/tweet/tweet-share.tsx (1)
4-4
: LGTM! Animation imports migrated.The import path change maintains compatibility with the existing Popover animation implementation.
platforms/blabsy/src/components/view/view-tweet.tsx (1)
2-2
: LGTM! Motion component import updated.The migration to
motion/react
maintains compatibility with the existing animation variants and motion.article implementation.platforms/blabsy/src/pages/user/[id]/index.tsx (1)
2-2
: LGTM! AnimatePresence import migrated.The import update preserves the popLayout mode behavior for the tweet list animations.
platforms/blabsy/src/components/tweet/number-stats.tsx (1)
1-1
: Refine migration verification scriptRun this to catch any remaining imports:
rg -n "from ['\"]framer-motion['\"]" -g '*.ts' -g '*.tsx' platforms/blabsy/Then confirm:
- No matches returned
motion
(^12.0.0
) in dependenciesframer-motion
absentmappings/.gitignore (1)
1-2
: LGTM! Standard ignore-all pattern.The .gitignore correctly ignores all files in the mappings directory while preserving itself. This is a common pattern for placeholder or build-output directories.
platforms/eVoting/src/lib/apiClient.ts (1)
1-1
: LGTM! Correct Axios type migration.The change from
AxiosRequestConfig
toInternalAxiosRequestConfig
is the correct type for request interceptors in modern Axios versions. This ensures type safety for the interceptor's config parameter.Also applies to: 14-14
platforms/blabsy/src/components/modal/modal.tsx (1)
1-1
: Import frommotion/react
is valid
motion
is installed, allframer-motion
imports removed, and the./react
export exists.platforms/cerberus/tsconfig.json (1)
5-7
: Formatting-only change; semantics preserved.No functional differences. Keeping lib as ES2020 under commonjs is consistent for Node services.
infrastructure/control-panel/vite.config.ts (1)
6-14
: Good separation of server‑only deps from client bundles.Excluding lowdb/steno in dev and externalizing in build matches the lazy server import in cacheService. LGTM.
package.json (1)
25-34
: Confirm onlyBuiltDependencies entries and CI toolchain
- @parcel/watcher and sqlite3 are correctly listed under onlyBuiltDependencies; verify your CI runners include the Node-gyp toolchain (Python, make/C++ compiler) or pin sqlite3 to a version with prebuilt binaries.
platforms/blabsy/package.json (1)
25-25
: Verify motion package and import paths
All motion imports in platforms/blabsy reference'motion/react'
. Ensure the installed"motion": "^12.0.0"
package actually provides this entry and matching APIs—otherwise switch to the correct package (e.g.framer-motion
or@motionone/react
).platforms/cerberus/src/web3adapter/watchers/subscriber.ts (1)
9-9
: Import 'web3-adapter' configuration validated. Verified the workspace package exists, exports Web3Adapter, and is declared in platforms/cerberus/package.json.metastate.compose.yml (1)
4-8
: DB credential references updated
Noevoting
occurrences remain in environment variables or container names across configuration files.platforms/blabsy/src/components/input/input-options.tsx (1)
2-2
: Motion/react migration is correct. Verifiedmotion
dependency in package.json, noframer-motion
imports remain, and core API compatibility is confirmed.platforms/eVoting/tsconfig.json (1)
25-25
: LGTM!Adding
baseUrl
enables absolute imports from the project root, which is a standard TypeScript configuration pattern that improves module resolution clarity.infrastructure/control-panel/package.json (1)
23-23
: LGTM!The dependency change aligns correctly with the adapter swap in
svelte.config.js
.platforms/blabsy/src/components/input/input-form.tsx (1)
3-3
: LGTM!The migration from
framer-motion
tomotion/react
is correctly applied for both runtime and type imports. No logic changes detected.Also applies to: 16-16
platforms/blabsy/src/components/modal/image-modal.tsx (1)
4-4
: LGTM!The migration from
framer-motion
tomotion/react
is correctly applied for both runtime and type imports.Also applies to: 11-11
infrastructure/control-panel/svelte.config.js (1)
1-9
: Verify deployment environment supports Node.js runtime
Switching from@sveltejs/adapter-static
to@sveltejs/adapter-node
replaces static output with a Node.js server—ensure your Dockerfile, CI/CD pipelines, and hosting platform are configured to run a Node.js application. No static-hosting references were detected in deployment configs; please confirm manually.platforms/blabsy/src/components/aside/aside-trends.tsx (2)
42-44
: LGTM: Inline animation props are clear and maintainable.The inline animation properties are straightforward and make the component's animation behavior explicit at the usage site.
4-4
: Confirm 'motion' dependency installation — Motion One usesnpm install motion
andimport { motion } from 'motion/react'
.
"@types/react": "18.2.79", | ||
"@types/react-dom": "18.2.25", |
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
Potential Next.js 12 + TypeScript 5 incompatibility.
Next 12.3 historically targeted TS 4.x; TS 5.x may cause typecheck/build issues. If build fails, pin TS to 4.9.x for blabsy or upgrade Next.
Also applies to: 59-59
🌐 Web query:
Does Next.js 12.3 officially support TypeScript 5.x?
💡 Result:
No. Next.js 12.3 (released Sep 8, 2022) predates TypeScript 5.0 (released Mar 16, 2023) and Next.js’ docs for the v12 era reference TypeScript v4.x (minimum recommended v4.5.2), so Next.js 12.3 does not officially target/support TypeScript 5.x. [1][2][3]
Sources:
- Next.js 12.3 release notes (Sep 8, 2022). [1]
- Next.js TypeScript docs (mentions minimum/recommended TS v4.5.2). [2]
- TypeScript 5.0 announcement (Mar 16, 2023). [3]
🏁 Script executed:
#!/usr/bin/env bash
rg -nC2 '"typescript"' platforms/blabsy/package.json
Length of output: 132
Pin TypeScript to 4.9.x or upgrade Next.js
platforms/blabsy/package.json:59 uses "typescript": "5.0.4", but Next.js 12.3 only supports TS 4.x. Build may break—pin TS to ^4.9.x or upgrade Next.js to v13+.
🤖 Prompt for AI Agents
In platforms/blabsy/package.json around lines 40–41 (and specifically the
typescript entry at ~line 59), the repo currently uses TypeScript 5.0.4 which is
incompatible with Next.js 12.3; either pin TypeScript to a 4.9.x range or
upgrade Next.js to v13+. To fix, change the "typescript" entry to a 4.9.x
version (e.g., "^4.9.5") in package.json, run your package manager
(npm/yarn/pnpm install) to update lockfiles, and verify the project builds;
alternatively, upgrade Next.js to v13+ if you prefer to keep TS 5.x, update any
breaking changes, reinstall, and run the build/tests.
const Icon = Icons[iconName]; | ||
|
||
return <Icon className={className ?? 'h-6 w-6'} />; |
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.
Add defensive handling for invalid icon names.
If an invalid iconName
is passed, Icons[iconName]
will be undefined
, causing a runtime error when attempting to render <Icon ... />
. With the weakened type safety from line 14, this becomes more likely.
Consider adding a fallback:
export function CustomIcon({
iconName,
className
}: CustomIconProps) {
const Icon = Icons[iconName];
+
+ if (!Icon) {
+ console.warn(`Icon "${iconName}" not found`);
+ return null;
+ }
return <Icon className={className ?? 'h-6 w-6'} />;
}
📝 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 Icon = Icons[iconName]; | |
return <Icon className={className ?? 'h-6 w-6'} />; | |
export function CustomIcon({ | |
iconName, | |
className | |
}: CustomIconProps) { | |
const Icon = Icons[iconName]; | |
if (!Icon) { | |
console.warn(`Icon "${iconName}" not found`); | |
return null; | |
} | |
return <Icon className={className ?? 'h-6 w-6'} />; | |
} |
🤖 Prompt for AI Agents
platforms/blabsy/src/components/ui/custom-icon.tsx lines 29-31: Icons[iconName]
can be undefined and currently will throw when rendered; change to safely
resolve the component and render a fallback when missing — retrieve const Icon =
Icons[iconName] ?? Icons['Placeholder'] ?? null, if Icon is null return null (or
render a built-in fallback SVG component) and optionally log a warning including
the invalid iconName; preserve the className default and ensure proper typing so
the component never tries to render undefined.
"typeorm": "^0.3.20", | ||
"uuid": "^9.0.1" | ||
"uuid": "^9.0.1", | ||
"web3-adapter": "workspace:*" |
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 workspace package exists.
The web3-adapter
dependency uses workspace:*
, which requires the package to exist in the monorepo workspace. Ensure the package is properly defined.
Run the following script to verify the web3-adapter package exists:
🏁 Script executed:
#!/bin/bash
# Check if web3-adapter package exists in workspace
fd -t f 'package.json' | xargs rg -l '"name":\s*"web3-adapter"'
Length of output: 75
Remove duplicate 'web3-adapter' workspace package definitions
Found two packages named 'web3-adapter' at services/web3-adapter/package.json and infrastructure/web3-adapter/package.json; workspace package names must be unique.
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.
@coodos this looks concerning 👀
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.
Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!
"@radix-ui/react-dropdown-menu": "^2.1.7", | ||
"@radix-ui/react-label": "^2.1.3", | ||
"@radix-ui/react-popover": "^1.1.7", | ||
"@radix-ui/react-separator": "^1.1.0", |
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 that new dependencies are utilized.
Four new dependencies were added:
@radix-ui/react-separator
@radix-ui/react-toggle
@radix-ui/react-tooltip
zustand
Given the PR removes many UI components, ensure these packages are actually imported and used in the codebase to avoid adding unused dependencies.
Run the following script to verify usage:
Also applies to: 28-29, 56-56
🏁 Script executed:
#!/bin/bash
# Check usage of newly added dependencies
echo "Checking for @radix-ui/react-separator usage..."
rg -l "@radix-ui/react-separator" --type=ts --type=tsx platforms/group-charter-manager/ 2>/dev/null || echo "Not found"
echo -e "\nChecking for @radix-ui/react-toggle usage..."
rg -l "@radix-ui/react-toggle" --type=ts --type=tsx platforms/group-charter-manager/ 2>/dev/null || echo "Not found"
echo -e "\nChecking for @radix-ui/react-tooltip usage..."
rg -l "@radix-ui/react-tooltip" --type=ts --type=tsx platforms/group-charter-manager/ 2>/dev/null || echo "Not found"
echo -e "\nChecking for zustand usage..."
rg -l "from ['\"]zustand['\"]" --type=ts --type=tsx platforms/group-charter-manager/ 2>/dev/null || echo "Not found"
Length of output: 211
Remove unused dependencies
@radix-ui/react-separator
, @radix-ui/react-toggle
, @radix-ui/react-tooltip
and zustand
aren’t imported or used anywhere in platforms/group-charter-manager; remove them from package.json.
🤖 Prompt for AI Agents
In platforms/group-charter-manager/package.json around line 24, the package.json
lists unused dependencies (@radix-ui/react-separator, @radix-ui/react-toggle,
@radix-ui/react-tooltip, zustand); remove these entries from dependencies (or
devDependencies) and run yarn/npm install to update lockfile, then run a
repo-wide search to confirm they are not imported anywhere before committing.
<span className="mb-1 block font-bold text-gray-600">The {isMobileDevice() ? "button" : "code"} is valid for 60 seconds</span> | ||
<span className="block font-light text-gray-600">Please refresh the page if it expires</span | ||
> |
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.
Critical: Unclosed <span>
tag will cause build failure.
Line 157 has an unclosed <span>
tag, which is a JSX syntax error that will prevent the application from building. This directly contradicts the PR's objective to fix build issues.
Apply this diff to fix the syntax error:
<span className="mb-1 block font-bold text-gray-600">The {isMobileDevice() ? "button" : "code"} is valid for 60 seconds</span>
- <span className="block font-light text-gray-600">Please refresh the page if it expires</span
+ <span className="block font-light text-gray-600">Please refresh the page if it expires</span>
>
Committable suggestion skipped: line range outside the PR's diff.
🤖 Prompt for AI Agents
In platforms/group-charter-manager/src/components/auth/login-screen.tsx around
lines 156 to 158, there's an unclosed <span> tag on line 157 causing a JSX
syntax error; close the span properly (ensure the trailing ">" is moved to the
end of the line or add a matching closing tag) so both span elements are
correctly formed and the file compiles.
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: 32
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (6)
platforms/blabsy/src/components/ui/custom-icon.tsx (1)
14-23
: Type annotation breaksIconName
type safety.The explicit
Record<string, React.ComponentType<IconProps>>
annotation causeskeyof typeof Icons
on line 4 to resolve tostring
instead of the specific icon name literals ("PinIcon" | "AppleIcon" | ...
). This defeats the purpose of theIconName
type and allows any string to be passed toCustomIcon
, making runtime errors more likely when an invalid icon name is used.Remove the explicit type annotation to restore type safety:
-const Icons: Record<string, React.ComponentType<IconProps>> = { +const Icons = { PinIcon, AppleIcon, PinOffIcon, GoogleIcon, TwitterIcon, FeatherIcon, SpinnerIcon, TriangleIcon -}; +} as const satisfies Record<string, React.ComponentType<IconProps>>;This preserves both strong typing for
IconName
and ensures all values match the expected component type.infrastructure/web3-adapter/src/logging/transport.js (2)
17-17
: Remove hardcoded credential fallbacks and validate required environment variables.Two security and reliability concerns:
Hardcoded default credentials (
"admin"/"admin"
) on lines 22-24 are a security risk. If these defaults are used in production, they create a trivial authentication bypass.Missing validation for LOKI_URL on line 17: if
process.env.LOKI_URL
is undefined, the transport will receivehost: undefined
, likely causing runtime failures when attempting to connect.Apply this diff to remove unsafe defaults and add validation:
const envPath = path_1.default.resolve(__dirname, "../../../../.env"); dotenv_1.default.config({ path: envPath }); + +// Validate required environment variables +const requiredEnvVars = ['LOKI_URL', 'LOKI_USERNAME', 'LOKI_PASSWORD']; +const missing = requiredEnvVars.filter(v => !process.env[v]); +if (missing.length > 0) { + throw new Error(`Missing required environment variables: ${missing.join(', ')}`); +} + exports.transport = (0, pino_1.transport)({ target: "pino-loki", options: { host: process.env.LOKI_URL, labels: { app: "web3-adapter", }, basicAuth: { - username: process.env.LOKI_USERNAME || "admin", - password: process.env.LOKI_PASSWORD || "admin", + username: process.env.LOKI_USERNAME, + password: process.env.LOKI_PASSWORD, }, }, });Note: Since this is a compiled JavaScript file (generated from TypeScript), apply these changes to the source TypeScript file (
infrastructure/web3-adapter/src/logging/transport.ts
) instead. The AI summary mentions this related file exists in the PR.Also applies to: 22-24
10-13
: infrastructure/web3-adapter/src/logging/transport.js: Reinforce.env
loading and failure handling
- The hard-coded path (
path.resolve(__dirname, "../../../../.env")
) is brittle—there’s no.env
at the repo root. Centralize environment loading at your application entrypoint or derive the path reliably (e.g., fromprocess.cwd()
or a shared constant).- Capture the return value of
dotenv.config({ path: envPath })
and throw or log ifresult.error
is set to avoid silent misconfiguration.platforms/blabsy/src/components/aside/aside-trends.tsx (1)
14-18
: Remove unused variants export.The
variants
object is exported but never used in the component. The component uses inline animation props on themotion.div
(lines 42-44) instead. This is dead code and should be removed.-export const variants = { - initial: { opacity: 0 }, - animate: { opacity: 1 }, - transition: { duration: 0.8 } -}; -infrastructure/web3-adapter/src/db/mapping.db.js (1)
15-17
: Ensure DB directory exists before opening file.Comment says “Ensure the directory exists” but it isn’t implemented; Database open will fail if the folder is missing.
- const fullPath = (0, node_path_1.join)(dbPath, "mappings.db"); - this.db = new sqlite3_1.default.Database(fullPath); + const fullPath = (0, node_path_1.join)(dbPath, "mappings.db"); + try { + // Lazily require fs to avoid top-level import churn here + const fs = require("node:fs"); + fs.mkdirSync(dbPath, { recursive: true }); + } catch (e) { + console.error("Failed to ensure DB directory exists:", e); + } + this.db = new sqlite3_1.default.Database(fullPath);infrastructure/web3-adapter/src/evault/evault.js (1)
305-327
: Critical: withTimeout does not actually time out GraphQL requestsAbortController isn’t wired into GraphQLClient requests, so abort never affects the in-flight operation; no AbortError is thrown. Currently only the cache is removed after timeout while the request continues and may still resolve.
Refactor to use Promise.race and throw a real timeout error:
- async withTimeout(w3id, operation) { - const controller = new AbortController(); - const timeoutId = setTimeout(() => { - controller.abort(); - console.log( - `GraphQL request timeout for ${w3id}, marking endpoint as unhealthy`, - ); - this.removeCachedClient(w3id); - }, CONFIG.GRAPHQL_TIMEOUT); - try { - const result = await operation(); - clearTimeout(timeoutId); - return result; - } catch (error) { - clearTimeout(timeoutId); - if (error instanceof Error && error.name === "AbortError") { - throw new Error( - `Request timeout after ${CONFIG.GRAPHQL_TIMEOUT}ms`, - ); - } - throw error; - } - } + async withTimeout(w3id, operation) { + let timeoutId; + try { + const timeoutPromise = new Promise((_, reject) => { + timeoutId = setTimeout(() => { + console.log( + `GraphQL request timeout for ${w3id}, marking endpoint as unhealthy`, + ); + this.removeCachedClient(w3id); + reject(new Error(`Request timeout after ${CONFIG.GRAPHQL_TIMEOUT}ms`)); + }, CONFIG.GRAPHQL_TIMEOUT); + }); + return await Promise.race([operation(), timeoutPromise]); + } finally { + if (timeoutId) clearTimeout(timeoutId); + } + }
♻️ Duplicate comments (2)
platforms/blabsy/src/components/ui/custom-icon.tsx (1)
25-29
: Add defensive handling for invalid icon names.With the type safety regression introduced on line 14, invalid icon names are now more likely to slip through. If
Icons[iconName]
isundefined
, rendering<Icon ... />
will cause a runtime error.As suggested in the previous review, add a fallback:
export function CustomIcon({ iconName, className }: CustomIconProps) { const Icon = Icons[iconName]; + + if (!Icon) { + console.warn(`Icon "${iconName}" not found`); + return null; + } return <Icon className={className ?? 'h-6 w-6'} />; }platforms/blabsy/src/components/chat/chat-window.tsx (1)
257-259
: Error logging added as requested.The empty catch block has been updated with error logging, addressing the concern from previous reviews.
🧹 Nitpick comments (30)
platforms/blabsy/src/components/login/login-main.tsx (2)
44-56
: SSR fix implemented correctly; consider extracting URL constants.The SSR guard at lines 45-47 successfully addresses the previous review comment. The early return ensures
navigator
andwindow
are only accessed client-side, preventing SSR crashes.However, the app store URLs are repeated as magic strings (lines 46, 50, 53, 55). Consider extracting them as constants for easier maintenance:
+const APP_STORE_URLS = { + GOOGLE_PLAY: 'https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet', + APPLE_APP_STORE: 'https://apps.apple.com/in/app/eid-for-w3ds/id6747748667', +} as const; + const getAppStoreLink = () => { if (typeof window === 'undefined' || typeof navigator === 'undefined') { - return 'https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet'; + return APP_STORE_URLS.GOOGLE_PLAY; } 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'; + return APP_STORE_URLS.GOOGLE_PLAY; } if (/iPad|iPhone|iPod/.test(userAgent) && !(window as any).MSStream) { - return 'https://apps.apple.com/in/app/eid-for-w3ds/id6747748667'; + return APP_STORE_URLS.APPLE_APP_STORE; } - return 'https://play.google.com/store/apps/details?id=foundation.metastate.eid_wallet'; + return APP_STORE_URLS.GOOGLE_PLAY; };
94-144
: Consider extracting repeated UI patterns into reusable components.The mobile (lines 94-118) and desktop (lines 122-144) branches contain similar patterns:
- Instruction text with "eID App" link (lines 94-100 vs 122-129)
- Expiry notice structure (lines 108-118 vs 134-144)
The duplication makes updates error-prone. Consider extracting a shared component:
const LoginInstructions = ({ action, children }: { action: 'button' | 'code'; children?: React.ReactNode; }) => ( <div className='flex flex-col gap-4 items-center'> <div className='text-xs text-gray-500 text-center max-w-xs lg:text-base lg:text-gray-600'> {action === 'button' ? 'Click the button' : 'Scan the QR code'} to {action === 'button' ? 'open' : 'use'} your{' '} <a href={getAppStoreLink()}> <b><u>eID App</u></b> </a>{' '} to login </div> {children} <div className='text-center mt-4'> <p className='text-sm text-gray-500'> <span className='mb-1 block font-bold text-gray-600'> The {action} is valid for 60 seconds </span> <span className='block font-light text-gray-600'> Please refresh the page if it expires </span> </p> </div> </div> );Then use:
<LoginInstructions action="button">...</LoginInstructions>
and<LoginInstructions action="code">...</LoginInstructions>
.platforms/blabsy/src/components/aside/aside-trends.tsx (1)
2-2
: Consider removing unnecessary React import.Modern React (17+) with the new JSX transform does not require an explicit
React
import for JSX. Unless your project is configured with the classic JSX transform, this import can be removed.-import React from 'react';
platforms/eVoting/src/components/ui/form.tsx (1)
45-54
: Tighten the context guard foruseFormField
.Right now we call
getFieldState(fieldContext.name, …)
before verifying thatfieldContext
exists, and the context default of{ } as FormFieldContextValue
means the guard never actually triggers. WhenuseFormField
is consumed outside<FormField>
, we’ll either hit a cryptic react-hook-form error or computeundefined-*
IDs instead of throwing our intended message. Initializing the context withundefined
and checking it beforegetFieldState
keeps the diagnostic clear.-const FormFieldContext = React.createContext<FormFieldContextValue>( - {} as FormFieldContextValue -) +const FormFieldContext = React.createContext<FormFieldContextValue | undefined>( + undefined +) … - const fieldState = getFieldState(fieldContext.name, formState) - - if (!fieldContext) { + if (!fieldContext) { throw new Error("useFormField should be used within <FormField>") } + + const fieldState = getFieldState(fieldContext.name, formState)platforms/blabsy/src/lib/utils/image-utils.ts (2)
6-67
: Consider adding validation for edge cases.The function doesn't validate for empty or malformed
src
values. While the current logic may handle most cases, explicit validation would make the function more robust.Consider adding checks like:
if (!dataPart?.src || typeof dataPart.src !== 'string') { continue; }
1-125
: Request test coverage for this complex logic.The PR indicates "How tested: n/a", but these functions implement non-trivial logic for detecting and combining split base64 URLs. Test coverage would help prevent regressions and validate edge cases (empty arrays, single images, complete vs incomplete base64 URLs, etc.).
Do you want me to help generate unit tests for these functions?
infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte (1)
24-28
: Consider removing commented-out code.The disabled click-outside handler has been left as commented code with an explanation about white screen issues. While the comment provides context, consider either:
- Removing the commented code entirely and keeping only the explanatory comment
- Creating a TODO/issue to track the underlying white screen bug
Apply this diff to clean up the commented code while preserving the context:
-// Disabled click outside behavior to prevent white screen issues -// const handleClickOutside = () => { -// pane?.destroy({ animate: true }); -// isPaneOpen = false; -// }; +// Note: Click-outside behavior is intentionally disabled to prevent white screen issuesinfrastructure/control-panel/src/lib/services/loki.ts (1)
162-162
: Ensure initialization errors instreamLogs
are surfaced
- The fire-and-forget loop catches all errors and retries, so the returned Promise always resolves immediately and hides any failures; consider rejecting on the first error or providing an explicit error callback.
- Confirm that calling the returned cleanup function stops the loop promptly and that the
processedLogIds
trimming logic prevents unbounded memory growth.infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte (2)
274-279
: Encode w3id in query string to avoid malformed URLs.Use URLSearchParams or set search params instead of string interpolation.
- const response = await axios.get( - new URL( - `resolve?w3id=${existingW3id}`, - PUBLIC_REGISTRY_URL, - ).toString(), - ); + const url = new URL("resolve", PUBLIC_REGISTRY_URL); + url.searchParams.set("w3id", existingW3id); + const response = await axios.get(url.toString());
129-145
: Close the SSE connection when done to avoid leaks.When status reaches a terminal state, close EventSource.
eventSource.onmessage = (e) => { const data = JSON.parse(e.data as string); if (!data.status) console.log(data); console.log("STATUS", data); status.set(data.status); reason.set(data.reason); person = data.person; document = data.document; websocketData = data; // Store the full websocket data if (data.status === "resubmission_requested") { DocFront.set(null); DocBack.set(null); SelfiePic.set(null); } verifStep.set(3); + if (["approved", "duplicate", "declined"].includes(data.status)) { + eventSource.close(); + } };infrastructure/web3-adapter/src/db/mapping.db.js (5)
34-35
: Enforce one-to-one mapping at schema level (local_id should be unique).Without a uniqueness constraint on local_id, duplicates are possible. Consider adding a unique index in a migration to enforce integrity. If duplicates may already exist, plan a backfill/cleanup first.
100-102
: Add logging for getLocalId errors (symmetry with getGlobalId).Currently swallowed; makes diagnosis harder.
- } catch (error) { - return null; - } + } catch (error) { + console.error("Error getting local ID:", error); + return null; + }
128-130
: Log getAllMappings errors for observability.Return [] is fine, but add an error log.
- } catch (error) { - return []; - } + } catch (error) { + console.error("Error getting all mappings:", error); + return []; + }
135-140
: close(): try/catch won’t catch async close errors — use callback or promisify.db.close reports errors via callback; current try/catch is ineffective.
- close() { - try { - this.db.close(); - } catch (error) { - console.error("Error closing database connection:", error); - } - } + close() { + this.db.close((err) => { + if (err) { + console.error("Error closing database connection:", err); + } + }); + }
43-45
: Input validation message clarity.Consider specifying which field is missing to speed up debugging; also prefer using a project logger over console.log elsewhere in this method.
infrastructure/web3-adapter/src/evault/evault.js (8)
271-276
: Avoid timer leak on health-check errorsIf fetch throws before the timeout fires, timeout isn’t cleared. Clear it in the catch as well.
- } catch (error) { + } catch (error) { + clearTimeout(timeoutId); console.log( `Health check failed for ${w3id}:`, error instanceof Error ? error.message : "Unknown error", );
93-99
: More robust non-retryable error detectionMatching "401/403/404" in error.message is brittle. Prefer status codes from known error shapes and fall back to a safe regex.
- if (error instanceof Error) { - const isRetryable = !( - error.message.includes("401") || - error.message.includes("403") || - error.message.includes("404") - ); - if (!isRetryable) break; - } + if (error instanceof Error) { + const status = + typeof error.status === "number" + ? error.status + : (error.response && typeof error.response.status === "number" + ? error.response.status + : null); + const isRetryable = + status != null + ? ![401, 403, 404].includes(status) + : !/(^|[^0-9])(401|403|404)([^0-9]|$)/.test(error.message || ""); + if (!isRetryable) break; + }
130-137
: Safer handling of expiresAt from registryUse nullish coalescing and numeric coercion to avoid falsey pitfalls (e.g., 0) and string values.
- const now = Date.now(); - const expiresAt = data.expiresAt || now + 3600000; // Default 1 hour + const now = Date.now(); + const expiresAt = + data && data.expiresAt != null + ? Number(data.expiresAt) + : now + 3600000; // Default 1 hour
166-171
: Prefer URLSearchParams for query buildingAvoid manual string interpolation to ensure proper encoding.
- const response = await fetch( - new URL( - `/resolve?w3id=${enrichedW3id}`, - this.registryUrl, - ).toString(), - ); + const url = new URL("/resolve", this.registryUrl); + url.searchParams.set("w3id", enrichedW3id); + const response = await fetch(url.toString());
191-205
: Defensive: handle missing cached endpointGuard against undefined endpoint before health check to avoid TypeError on replace(). Cheap safety even if caches should be consistent.
- // Check if the cached endpoint is still healthy - if (await this.isEndpointHealthy(w3id, endpoint)) { + // Check if the cached endpoint is still healthy + if (!endpoint) { + console.log(`missing cached endpoint for ${w3id}; removing`); + this.removeCachedClient(w3id); + } else if (await this.isEndpointHealthy(w3id, endpoint)) { console.log( "reusing existing client for w3id:", w3id, "endpoint:", endpoint, ); return client; } else {
407-415
: Add timeout handling to storeReferenceAlign with storeMetaEnvelope by wrapping the request in withTimeout to avoid hangs.
- const response = await client - .request(STORE_META_ENVELOPE, { - input: { - ontology: "reference", - payload: { - _by_reference: referenceId, - }, - acl: ["*"], - }, - }) - .catch(() => null); + const response = await this.withTimeout(w3id, () => + client.request(STORE_META_ENVELOPE, { + input: { + ontology: "reference", + payload: { _by_reference: referenceId }, + acl: ["*"], + }, + }), + ).catch(() => null);
454-457
: Add timeout handling to updateMetaEnvelopeByIdWrap GraphQL request to enforce GRAPHQL_TIMEOUT and consistent unhealthy marking.
- const response = await client.request( - UPDATE_META_ENVELOPE, - variables, - ); + const response = await this.withTimeout(envelope.w3id, () => + client.request(UPDATE_META_ENVELOPE, variables), + );
423-434
: Minor: extra variable passed in fetchMetaEnvelopeYou pass w3id alongside id to FETCH_META_ENVELOPE, but the query only declares $id. Some servers reject unknown variables.
Replace the request variables with: { id } only.
infrastructure/eid-wallet/src/routes/(app)/+layout.svelte (1)
11-13
: SSR safety for browser globals.
page
is fine, but ensure any direct access todocument
/window
remains in client-only contexts. This file is clean, but if lint flags SSR globals, gate them in onMount or behindtypeof window !== "undefined"
.Also applies to: 49-53
infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte (2)
36-41
: Account deletion flow: consider clearing vault/session as well.You clear
user
and PIN, but not vault/session-related state. If intended full reset, also clear any persisted vault/session.
48-92
: Debounce/cleanup for tap-based retry.Rapid tapping sets timeouts; not harmful, but you may store timeout IDs and clear them on unmount to avoid dangling timers.
infrastructure/eid-wallet/src/routes/+layout.svelte (2)
379-386
: SSR safety for computed styles.
getComputedStyle(document.documentElement)
is browser-only. If lint flags SSR, wrap with a browser guard or move insideonMount
.-const safeAreaTop = $derived.by( - () => - Number.parseFloat( - getComputedStyle(document.documentElement).getPropertyValue( - "--safe-top", - ), - ) || 0, -); +$state; +let safeAreaTop = 0; +onMount(() => { + safeAreaTop = + Number.parseFloat( + getComputedStyle(document.documentElement).getPropertyValue( + "--safe-top", + ), + ) || 0; +});Also applies to: 388-388
390-422
: View transition hook: guard browser globals.If lint complains about
document
on SSR, addif (typeof document === "undefined") return;
before using it insideonNavigate
callback.infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte (2)
94-106
: Permissions flow: handle null checks and early return.If
permissions
resolution fails,permissions_nullable
remains null. Add a guard before scanning to avoid unexpected states.- permissions_nullable = permissions; + permissions_nullable = permissions; + if (!permissions) return;
814-817
: Redirect URL construction: guard against malformed input.Ensure
signingData.redirect
exists and is a path (or valid https) before concatenation; otherwise you can create invalid URLs.- const redirectUrl = signingData.redirect.startsWith("http") - ? signingData.redirect - : `${signingData.platform_url}${signingData.redirect}`; + const redirectUrl = + signingData.redirect && signingData.redirect.startsWith("http") + ? signingData.redirect + : new URL(signingData.redirect || "", signingData.platform_url).toString();Also applies to: 821-826
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
⛔ Files ignored due to path filters (1)
pnpm-lock.yaml
is excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (107)
infrastructure/control-panel/package.json
(1 hunks)infrastructure/control-panel/src/lib/components/EVaultList.svelte
(3 hunks)infrastructure/control-panel/src/lib/fragments/TableCardHeader/TableCardHeader.svelte
(1 hunks)infrastructure/control-panel/src/lib/services/cacheService.ts
(1 hunks)infrastructure/control-panel/src/lib/services/evaultService.ts
(1 hunks)infrastructure/control-panel/src/lib/services/loki.ts
(7 hunks)infrastructure/control-panel/src/lib/services/registry.ts
(3 hunks)infrastructure/control-panel/src/lib/ui/Table/Table.svelte
(3 hunks)infrastructure/control-panel/src/routes/api/evaults/+server.ts
(3 hunks)infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts
(3 hunks)infrastructure/control-panel/src/routes/api/events/+server.ts
(5 hunks)infrastructure/eid-wallet/src/lib/crypto/HardwareKeyManager.ts
(3 hunks)infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts
(5 hunks)infrastructure/eid-wallet/src/lib/crypto/SoftwareKeyManager.ts
(11 hunks)infrastructure/eid-wallet/src/lib/crypto/index.ts
(1 hunks)infrastructure/eid-wallet/src/lib/crypto/types.ts
(2 hunks)infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte
(1 hunks)infrastructure/eid-wallet/src/lib/global/controllers/evault.ts
(4 hunks)infrastructure/eid-wallet/src/lib/services/NotificationService.ts
(1 hunks)infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(app)/+layout.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte
(1 hunks)infrastructure/eid-wallet/src/routes/(auth)/verify/store.ts
(1 hunks)infrastructure/eid-wallet/src/routes/+layout.svelte
(1 hunks)infrastructure/web3-adapter/src/db/index.d.ts
(1 hunks)infrastructure/web3-adapter/src/db/index.js
(1 hunks)infrastructure/web3-adapter/src/db/mapping.db.d.ts
(1 hunks)infrastructure/web3-adapter/src/db/mapping.db.js
(7 hunks)infrastructure/web3-adapter/src/evault/evault.d.ts
(2 hunks)infrastructure/web3-adapter/src/evault/evault.js
(18 hunks)infrastructure/web3-adapter/src/evault/evault.ts
(9 hunks)infrastructure/web3-adapter/src/index.d.ts
(4 hunks)infrastructure/web3-adapter/src/index.js
(11 hunks)infrastructure/web3-adapter/src/index.ts
(3 hunks)infrastructure/web3-adapter/src/logging/index.d.ts
(1 hunks)infrastructure/web3-adapter/src/logging/index.js
(1 hunks)infrastructure/web3-adapter/src/logging/logger.d.ts
(1 hunks)infrastructure/web3-adapter/src/logging/logger.js
(1 hunks)infrastructure/web3-adapter/src/logging/transport.d.ts
(1 hunks)infrastructure/web3-adapter/src/logging/transport.js
(2 hunks)infrastructure/web3-adapter/src/logging/transport.ts
(1 hunks)infrastructure/web3-adapter/src/mapper/mapper.d.ts
(1 hunks)infrastructure/web3-adapter/src/mapper/mapper.js
(11 hunks)infrastructure/web3-adapter/src/mapper/mapper.ts
(5 hunks)infrastructure/web3-adapter/src/mapper/mapper.types.d.ts
(1 hunks)infrastructure/web3-adapter/src/mapper/mapper.types.js
(1 hunks)mappings/.gitignore
(1 hunks)platforms/blabsy/next.config.js
(1 hunks)platforms/blabsy/package.json
(3 hunks)platforms/blabsy/src/components/aside/aside-trends.tsx
(4 hunks)platforms/blabsy/src/components/chat/add-members.tsx
(4 hunks)platforms/blabsy/src/components/chat/chat-list.tsx
(2 hunks)platforms/blabsy/src/components/chat/chat-window.tsx
(8 hunks)platforms/blabsy/src/components/chat/group-settings.tsx
(10 hunks)platforms/blabsy/src/components/input/image-preview.tsx
(3 hunks)platforms/blabsy/src/components/login/login-main.tsx
(3 hunks)platforms/blabsy/src/components/modal/image-modal.tsx
(2 hunks)platforms/blabsy/src/components/sidebar/more-settings.tsx
(3 hunks)platforms/blabsy/src/components/ui/custom-icon.tsx
(10 hunks)platforms/blabsy/src/components/ui/loading.tsx
(2 hunks)platforms/blabsy/src/components/user/user-edit-profile.tsx
(1 hunks)platforms/blabsy/src/components/user/user-follow.tsx
(2 hunks)platforms/blabsy/src/lib/context/auth-context.tsx
(1 hunks)platforms/blabsy/src/lib/context/chat-context.tsx
(1 hunks)platforms/blabsy/src/lib/context/window-context.tsx
(2 hunks)platforms/blabsy/src/lib/firebase/utils.ts
(8 hunks)platforms/blabsy/src/lib/utils/image-utils.ts
(3 hunks)platforms/dreamSync/package.json
(2 hunks)platforms/eVoting/next.config.ts
(1 hunks)platforms/eVoting/package.json
(2 hunks)platforms/eVoting/src/components/ui/accordion.tsx
(1 hunks)platforms/eVoting/src/components/ui/alert-dialog.tsx
(1 hunks)platforms/eVoting/src/components/ui/alert.tsx
(1 hunks)platforms/eVoting/src/components/ui/aspect-ratio.tsx
(1 hunks)platforms/eVoting/src/components/ui/avatar.tsx
(1 hunks)platforms/eVoting/src/components/ui/breadcrumb.tsx
(1 hunks)platforms/eVoting/src/components/ui/calendar.tsx
(1 hunks)platforms/eVoting/src/components/ui/carousel.tsx
(2 hunks)platforms/eVoting/src/components/ui/chart.tsx
(1 hunks)platforms/eVoting/src/components/ui/checkbox.tsx
(1 hunks)platforms/eVoting/src/components/ui/collapsible.tsx
(1 hunks)platforms/eVoting/src/components/ui/command.tsx
(1 hunks)platforms/eVoting/src/components/ui/context-menu.tsx
(1 hunks)platforms/eVoting/src/components/ui/drawer.tsx
(2 hunks)platforms/eVoting/src/components/ui/dropdown-menu.tsx
(1 hunks)platforms/eVoting/src/components/ui/form.tsx
(2 hunks)platforms/eVoting/src/components/ui/hover-card.tsx
(1 hunks)platforms/eVoting/src/components/ui/input-otp.tsx
(1 hunks)platforms/eVoting/src/components/ui/menubar.tsx
(1 hunks)platforms/eVoting/src/components/ui/navigation-menu.tsx
(1 hunks)platforms/eVoting/src/components/ui/pagination.tsx
(1 hunks)platforms/eVoting/src/components/ui/popover.tsx
(1 hunks)platforms/eVoting/src/components/ui/progress.tsx
(1 hunks)platforms/eVoting/src/components/ui/resizable.tsx
(1 hunks)platforms/eVoting/src/components/ui/scroll-area.tsx
(1 hunks)platforms/eVoting/src/components/ui/separator.tsx
(1 hunks)platforms/eVoting/src/components/ui/sheet.tsx
(1 hunks)platforms/eVoting/src/components/ui/sidebar.tsx
(2 hunks)platforms/eVoting/src/components/ui/skeleton.tsx
(1 hunks)platforms/eVoting/src/components/ui/slider.tsx
(1 hunks)platforms/eVoting/src/components/ui/switch.tsx
(1 hunks)platforms/eVoting/src/components/ui/table.tsx
(1 hunks)platforms/eVoting/src/components/ui/tabs.tsx
(1 hunks)
⛔ Files not processed due to max files limit (6)
- platforms/eVoting/src/components/ui/textarea.tsx
- platforms/eVoting/src/components/ui/toast.tsx
- platforms/eVoting/src/components/ui/toaster.tsx
- platforms/eVoting/src/components/ui/toggle-group.tsx
- platforms/eVoting/src/components/ui/toggle.tsx
- platforms/eVoting/src/components/ui/tooltip.tsx
✅ Files skipped from review due to trivial changes (49)
- platforms/blabsy/src/components/chat/chat-list.tsx
- infrastructure/control-panel/src/lib/services/evaultService.ts
- infrastructure/control-panel/src/routes/api/evaults/[namespace]/[pod]/logs/+server.ts
- infrastructure/web3-adapter/src/mapper/mapper.d.ts
- platforms/eVoting/src/components/ui/dropdown-menu.tsx
- infrastructure/web3-adapter/src/logging/logger.js
- infrastructure/web3-adapter/src/logging/transport.d.ts
- infrastructure/control-panel/src/lib/services/registry.ts
- infrastructure/web3-adapter/src/logging/index.d.ts
- infrastructure/web3-adapter/src/index.ts
- platforms/eVoting/src/components/ui/aspect-ratio.tsx
- infrastructure/web3-adapter/src/logging/transport.ts
- platforms/eVoting/src/components/ui/avatar.tsx
- infrastructure/control-panel/src/routes/api/events/+server.ts
- platforms/blabsy/src/components/chat/add-members.tsx
- infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte
- infrastructure/eid-wallet/src/lib/crypto/index.ts
- infrastructure/eid-wallet/src/lib/global/controllers/evault.ts
- platforms/eVoting/src/components/ui/sidebar.tsx
- platforms/eVoting/src/components/ui/accordion.tsx
- platforms/eVoting/src/components/ui/input-otp.tsx
- platforms/blabsy/next.config.js
- infrastructure/control-panel/src/routes/api/evaults/+server.ts
- platforms/eVoting/src/components/ui/resizable.tsx
- platforms/eVoting/src/components/ui/table.tsx
- infrastructure/eid-wallet/src/routes/(auth)/verify/store.ts
- platforms/eVoting/src/components/ui/navigation-menu.tsx
- infrastructure/eid-wallet/src/lib/fragments/IdentityCard/IdentityCard.svelte
- infrastructure/web3-adapter/src/evault/evault.ts
- infrastructure/control-panel/src/lib/fragments/TableCardHeader/TableCardHeader.svelte
- infrastructure/web3-adapter/src/mapper/mapper.ts
- infrastructure/eid-wallet/src/lib/crypto/KeyManagerFactory.ts
- platforms/eVoting/src/components/ui/context-menu.tsx
- infrastructure/web3-adapter/src/evault/evault.d.ts
- platforms/eVoting/src/components/ui/scroll-area.tsx
- infrastructure/web3-adapter/src/mapper/mapper.types.d.ts
- platforms/blabsy/src/lib/firebase/utils.ts
- platforms/eVoting/src/components/ui/sheet.tsx
- infrastructure/web3-adapter/src/logging/index.js
- infrastructure/web3-adapter/src/logging/logger.d.ts
- platforms/eVoting/src/components/ui/progress.tsx
- platforms/eVoting/src/components/ui/hover-card.tsx
- infrastructure/eid-wallet/src/lib/crypto/types.ts
- platforms/eVoting/src/components/ui/checkbox.tsx
- platforms/eVoting/src/components/ui/collapsible.tsx
- platforms/eVoting/src/components/ui/menubar.tsx
- infrastructure/web3-adapter/src/index.js
- infrastructure/web3-adapter/src/index.d.ts
- infrastructure/web3-adapter/src/mapper/mapper.js
🚧 Files skipped from review as they are similar to previous changes (5)
- platforms/blabsy/src/components/user/user-edit-profile.tsx
- mappings/.gitignore
- platforms/blabsy/package.json
- infrastructure/control-panel/package.json
- platforms/blabsy/src/lib/context/window-context.tsx
🧰 Additional context used
🧬 Code graph analysis (14)
platforms/eVoting/next.config.ts (1)
platforms/blabsy/next.config.js (1)
nextConfig
(2-11)
platforms/blabsy/src/components/aside/aside-trends.tsx (5)
platforms/blabsy/src/components/sidebar/more-settings.tsx (1)
variants
(11-19)platforms/blabsy/src/components/input/input.tsx (1)
variants
(38-41)platforms/blabsy/src/components/tweet/tweet-actions.tsx (1)
variants
(30-38)platforms/blabsy/src/components/user/user-header.tsx (1)
variants
(11-15)platforms/blabsy/src/components/tweet/tweet.tsx (1)
variants
(30-34)
platforms/blabsy/src/lib/context/auth-context.tsx (1)
platforms/pictique/src/lib/stores/users.ts (1)
User
(4-11)
platforms/blabsy/src/components/modal/image-modal.tsx (1)
platforms/blabsy/src/components/modal/modal.tsx (1)
backdrop
(34-34)
platforms/blabsy/src/components/login/login-main.tsx (1)
platforms/blabsy/src/lib/utils/mobile-detection.ts (1)
getDeepLinkUrl
(11-13)
platforms/eVoting/src/components/ui/command.tsx (1)
platforms/eVoting/src/components/ui/collapsible.tsx (3)
Collapsible
(11-11)CollapsibleTrigger
(11-11)CollapsibleContent
(11-11)
infrastructure/eid-wallet/src/lib/services/NotificationService.ts (4)
infrastructure/evault-provisioner/src/services/NotificationService.ts (3)
DeviceRegistration
(5-11)NotificationPayload
(13-17)NotificationService
(25-138)infrastructure/evault-provisioner/test-notification.js (2)
response
(35-39)response
(50-50)infrastructure/evault-provisioner/src/controllers/NotificationController.ts (1)
sendNotification
(94-126)infrastructure/eid-wallet/src/lib/global/controllers/evault.ts (2)
vault
(255-344)vault
(346-359)
platforms/blabsy/src/components/input/image-preview.tsx (3)
platforms/blabsy/src/components/sidebar/more-settings.tsx (1)
variants
(11-19)platforms/blabsy/src/components/input/input.tsx (1)
variants
(38-41)platforms/blabsy/src/components/tweet/tweet-actions.tsx (1)
variants
(30-38)
infrastructure/control-panel/src/lib/services/loki.ts (1)
infrastructure/control-panel/src/routes/api/events/+server.ts (1)
start
(7-158)
infrastructure/eid-wallet/src/lib/crypto/SoftwareKeyManager.ts (1)
infrastructure/eid-wallet/src/lib/crypto/types.ts (3)
KeyManager
(5-39)KeyManagerError
(63-72)KeyManagerErrorCodes
(74-81)
infrastructure/eid-wallet/src/lib/crypto/HardwareKeyManager.ts (1)
infrastructure/eid-wallet/src/lib/crypto/types.ts (3)
KeyManager
(5-39)KeyManagerError
(63-72)KeyManagerErrorCodes
(74-81)
infrastructure/web3-adapter/src/evault/evault.js (2)
infrastructure/web3-adapter/src/index.js (7)
attempt
(193-193)response
(198-200)endpoint
(201-201)client
(205-205)result
(217-223)uuid_1
(76-76)STORE_META_ENVELOPE
(206-216)infrastructure/web3-adapter/src/evault/evault.ts (1)
EVaultClient
(127-629)
infrastructure/control-panel/src/lib/services/cacheService.ts (1)
infrastructure/control-panel/src/routes/api/evaults/+server.ts (1)
EVault
(8-22)
platforms/blabsy/src/components/chat/chat-window.tsx (1)
platforms/blabsy/src/lib/types/chat.ts (1)
getChatType
(34-39)
🪛 ast-grep (0.39.6)
platforms/eVoting/src/components/ui/chart.tsx
[warning] 80-80: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
platforms/blabsy/src/components/chat/chat-window.tsx
[warning] 49-49: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
[warning] 114-114: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🪛 GitHub Actions: Check Lint
infrastructure/eid-wallet/src/lib/services/NotificationService.ts
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/lib/crypto/SoftwareKeyManager.ts
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/lib/crypto/HardwareKeyManager.ts
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/routes/(app)/+layout.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/routes/+layout.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte
[error] 1-1: Command failed: pnpm run check-lint for eid-wallet exited with code 1.
🔇 Additional comments (53)
platforms/blabsy/src/components/user/user-follow.tsx (1)
15-31
: Whitespace tweak looks good.Extra separation around the query setup and early return reads cleaner without affecting behavior.
platforms/eVoting/src/components/ui/skeleton.tsx (1)
7-11
: Formatting aligns with house style.Indentation adjustment keeps the component readable without altering behavior. All good.
platforms/eVoting/next.config.ts (1)
3-3
: Glad to see the safety rails back on.Dropping the ignore flags restores the default TypeScript/ESLint enforcement so real build failures will surface again. ✅
platforms/eVoting/src/components/ui/slider.tsx (1)
6-22
: Formatting-only change looks goodIndentation/style tweaks keep the Slider API and behavior intact. Nothing to fix here.
platforms/eVoting/src/components/ui/switch.tsx (1)
10-21
: Formatting update looks solidReindentation and className formatting preserve behavior while matching project style. No further action needed.
infrastructure/web3-adapter/src/mapper/mapper.types.js (1)
3-3
: Source map directive looks good.No behavioral change; keeping the source map hint here is fine.
platforms/eVoting/src/components/ui/alert.tsx (1)
7-59
: LGTM! Formatting changes look good.The indentation and formatting adjustments are consistent throughout the file and don't alter any component behavior or API signatures.
platforms/blabsy/src/components/ui/loading.tsx (1)
2-2
: LGTM! Clean refactor to FC pattern.The conversion from function declaration to
FC<LoadingProps>
is a valid modernization that improves type safety and consistency. The component logic and behavior remain unchanged.Also applies to: 10-19
platforms/blabsy/src/components/sidebar/more-settings.tsx (1)
1-1
: LGTM! Migration correctly implemented.The imports have been successfully migrated from
framer-motion
tomotion/react
. The usage ofmotion
,AnimatePresence
, andVariants
throughout the component remains fully compatible with the motion v12.x API. This change aligns with the PR objective to fix build issues for Blabsy.Based on learnings: Motion v12.x is stable and the migration pattern used here is correct. No gesture callbacks are present in this component, so the v12 gesture signature changes do not apply.
Also applies to: 9-9
platforms/blabsy/src/lib/context/auth-context.tsx (1)
100-103
: Approved: Logging format improvement, but verify relevance to build fix.The multi-line console.error format improves debugging by separating the error object as a distinct argument, which typically renders better in browser consoles.
However, this cosmetic change appears unrelated to the stated PR objective of fixing build failures. Please confirm whether this was an incidental formatting update or if it somehow addresses the build issues mentioned in #359.
For consistency, consider applying the same formatting to the similar error handler at line 115:
- (error) => { - console.error('[DEBUG] Error in bookmarks listener:', error); - // Don't throw here, just log the error - } + (error) => { + console.error( + '[DEBUG] Error in bookmarks listener:', + error + ); + // Don't throw here, just log the error + }platforms/eVoting/src/components/ui/pagination.tsx (2)
7-107
: Formatting improvements look good.The indentation and spacing adjustments throughout the file improve readability without affecting functionality.
52-52
: Verify pagination active variant change
Theoutline
variant is defined in buttonVariants and alloutline-solid
references are gone. Confirm the visual update for active pagination links aligns with design requirements.platforms/blabsy/src/components/ui/custom-icon.tsx (2)
2-2
: LGTM!The explicit React import aligns with modern React best practices and ensures compatibility across different build configurations.
31-31
: LGTM!Removing explicit return type annotations from the icon functions is acceptable. TypeScript correctly infers
JSX.Element
from the JSX return statements, and this aligns with the typing patterns seen across the codebase in this PR.Also applies to: 61-61, 75-75, 100-100, 131-131, 141-141, 151-151, 173-173
platforms/blabsy/src/components/login/login-main.tsx (1)
165-176
: LGTM: Clickable logo with proper security attributes.Wrapping the W3DS logo in an anchor improves navigation. The
rel='noopener noreferrer'
attributes correctly mitigate security risks when opening external links in new tabs.infrastructure/web3-adapter/src/logging/transport.js (1)
1-27
: Note: This is a compiled file – apply changes to the TypeScript source.This
.js
file is compiled from TypeScript (indicated by the source map reference on line 27 and the__importDefault
boilerplate). Any direct edits to this file will be overwritten on the next TypeScript compilation.Please apply the suggested changes to the source TypeScript file:
infrastructure/web3-adapter/src/logging/transport.ts
(mentioned in the AI summary as a related file in this PR).platforms/blabsy/src/components/aside/aside-trends.tsx (3)
24-24
: LGTM!Removing the explicit return type is fine as TypeScript can infer the return type from the function body. The change reduces verbosity without sacrificing type safety.
42-44
: LGTM!Using inline animation props is a cleaner and more explicit approach compared to spreading variants. The values are correct and this pattern is easier to understand and maintain.
4-4
: Verifymotion/react
import path exists for installedmotion
package.
Ensure yourmotion
(v12.x) dependency defines anexports["./react"]
entry in itsnode_modules/motion/package.json
(or consult the official docs) so thatimport { motion } from 'motion/react'
is valid.platforms/eVoting/src/components/ui/calendar.tsx (2)
10-68
: LGTM! Formatting improvements enhance readability.The formatting changes throughout the file improve code consistency and readability. The component structure, props, classNames mappings, and functionality remain unchanged.
26-29
: Approve button variant changeThe
outline
variant is defined inbuttonVariants
(replacing the invalidoutline-solid
), resolving the build error and applying the intended border styling to the navigation buttons.platforms/blabsy/src/components/modal/image-modal.tsx (2)
106-106
: Replaceany
cast with proper Motion exit prop type
- Import and use Motion prop types from 'framer-motion':
import type { HTMLMotionProps } from 'framer-motion'; exit={tweet ? (backdrop.exit as HTMLMotionProps<'div'>['exit']) : undefined}- Verify the generic (
'div'
) matches your motion component (e.g."img"
formotion.img
).
4-4
: Import and version compatibility confirmedProject uses [email protected]; importing from
motion/react
is correct and no gesture callbacks were found that require signature updates.platforms/blabsy/src/components/chat/chat-window.tsx (1)
384-386
: LGTM: Defensive null handling for userData.The defensive handling prevents potential runtime errors when
message.senderId
is absent, derivinguserData
asnull
instead of directly indexing. This is a good safety improvement.platforms/eVoting/src/components/ui/carousel.tsx (2)
1-260
: LGTM! Well-structured carousel component.The implementation follows React best practices:
- Proper context pattern for sharing state between components
- Correct use of
useCallback
to prevent unnecessary re-renders- Effect cleanup properly handles event listener removal
- Forward refs enable parent component control
- Accessibility attributes (
role
,aria-roledescription
,sr-only
) ensure screen reader compatibility- TypeScript types are comprehensive and well-defined
198-198
: Using “outline” is correct
ThebuttonVariants
definition doesn’t include “outline-solid”, so switching to the valid “outline” variant resolves the build error.platforms/blabsy/src/components/input/image-preview.tsx (2)
1-2
: Migration to motion/react looks good.The switch from
framer-motion
tomotion/react
is appropriate and aligns with the stable Motion v12.x releases. Since this component doesn't use gesture callbacks, the v12 signature changes don't affect it. Based on learnings.Optional note: The
React
import on line 1 might be redundant with modern JSX transforms (hooks are imported separately), but it's harmless and ensures compatibility across different build configurations.
23-32
: Verify inconsistent transition behavior.The new top-level
transition
property (line 31) creates conflicting transition configurations:
- The
animate
state definestransition: { duration: 0.3 }
(likely using default 'tween' type)- The top-level
transition: { type: 'spring', duration: 0.5 }
applies toinitial
andexit
statesThis means
animate
uses a 0.3s tween whileexit
/initial
use a 0.5s spring, which may be unintentional. Other files in this codebase (e.g.,more-settings.tsx
,tweet-actions.tsx
) define transitions inside each state object rather than mixing state-specific and default transitions.Consider aligning with the codebase pattern by moving all transitions inside their respective state objects:
const variants = { initial: { opacity: 0, scale: 0.5 }, animate: { opacity: 1, scale: 1, - transition: { duration: 0.3 } + transition: { type: 'spring', duration: 0.5 } }, - exit: { opacity: 0, scale: 0.5 }, - transition: { type: 'spring' as const, duration: 0.5 } + exit: { opacity: 0, scale: 0.5, transition: { type: 'spring', duration: 0.5 } } };Or confirm whether the different transition behaviors are intentional for this component's UX.
platforms/blabsy/src/lib/utils/image-utils.ts (1)
73-125
: LGTM! Better detection logic than the primary function.The alternative implementation correctly checks both
startsWith('data:')
AND!includes(',')
at line 92, making it more accurate at detecting incomplete base64 URLs compared to the primary function.infrastructure/eid-wallet/src/lib/services/NotificationService.ts (6)
23-38
: LGTM! Singleton pattern implemented correctly.The singleton implementation follows best practices and ensures a single instance of the service across the application.
162-195
: Implementation is correct, but consider logging cleanup.The unregister logic is sound, but console.log statements on lines 184 and 192 should be reviewed as part of the lint failure resolution.
352-361
: Clarify FCM token implementation status.The method always returns
undefined
with a comment indicating this is a placeholder. Since theregisterDevice
method uses this for mobile platforms (lines 80-82), clarify whether push notifications are intentionally disabled or if this is pending implementation. If pending, consider adding a TODO comment or tracking issue.
120-157
: Replace console.log calls and verify icon asset path
- Remove or replace console.log statements (≈lines 122, 126, 137, 153) with your app’s logging utility or guard to satisfy lint rules.
- Confirm that
"icons/32x32.png"
is correctly bundled/served at runtime (file lives insrc-tauri/icons/32x32.png
but may need config).
365-378
: No action needed for dynamic import
@tauri-apps/plugin-store
is declared in dependencies (^2.2.0
) and Vite auto-bundles static dynamic imports, so the current implementation will build correctly.
84-102
: No action needed forregistrationTime
serialization. The provisioner’s controller overrides the payload’sregistrationTime
with its ownnew Date()
, so format alignment is irrelevant.Likely an incorrect or invalid review comment.
platforms/eVoting/package.json (1)
13-59
: Peer dependency compatibility verifiedAll newly added packages declare support for React 19, so React 19.1.0 satisfies their peer ranges with no conflicts.
platforms/eVoting/src/components/ui/alert-dialog.tsx (2)
13-117
: LGTM on formatting adjustments.The indentation and structure changes throughout the file improve consistency without affecting functionality.
Also applies to: 119-139
118-118
: Approve replacingoutline-solid
with validoutline
ThebuttonVariants
definition includesoutline
but notoutline-solid
, so this change is correct and fixes the build error.infrastructure/eid-wallet/src/lib/ui/Drawer/Drawer.svelte (1)
52-60
: LGTM: Clean separation of initialization and state management.The split between initialization ($effect at lines 31-49) and state management (this $effect) properly handles the lifecycle. The guard
if (!pane) return;
correctly prevents premature execution before initialization completes.infrastructure/control-panel/src/lib/services/loki.ts (3)
44-44
: LGTM: Unquoted property name is valid JavaScript.The removal of quotes from the
Authorization
property name is a valid JavaScript simplification with no functional impact.
72-72
: LGTM: Formatting improvements enhance readability.The added empty lines and multi-line formatting improve code readability without changing functionality.
Also applies to: 95-95, 105-105, 121-121, 127-127, 133-133, 135-135, 143-143, 152-152, 170-170
83-85
: LGTM: Multi-line formatting improves readability.Converting single-line statements to multi-line format enhances readability, especially for chained operations and Promise constructors.
Also applies to: 96-97, 153-154, 157-157
infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte (1)
110-116
: Typo check: verificaitonId vs verificationId.Ensure the store exports “verificaitonId” intentionally; otherwise, rename consistently to avoid confusion.
Do you want me to generate a rename diff across eid-wallet to standardize on verificationId?
Also applies to: 295-303
infrastructure/web3-adapter/src/db/mapping.db.js (1)
73-79
: LGTM: Parameterized getGlobalId query.Safe and clear.
infrastructure/web3-adapter/src/db/index.d.ts (1)
2-2
: LGTM: Source map reference only.No API changes.
infrastructure/web3-adapter/src/db/index.js (2)
2-36
: Formatting-only changes to helpers.Behavior preserved.
39-39
: LGTM: Source map line.No functional impact.
infrastructure/web3-adapter/src/db/mapping.db.d.ts (2)
30-35
: LGTM: Type formatting only.Public surface unchanged.
41-41
: LGTM: Source map reference.No issues.
infrastructure/web3-adapter/src/evault/evault.js (2)
71-78
: Dispose idempotency looks goodEarly return and clearing all caches, including lastHealthCheck and tokenInfo, makes dispose safe and idempotent.
375-380
: clearCache behavior is fineLog + full cache clear is consistent with the rest of the class.
infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte (1)
63-73
: Polling via setInterval: good cleanup.Watcher is simple and cleared on destroy. LGTM.
Also applies to: 75-79
infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte (1)
1444-1490
: UI/logic separation: good states and messaging.Success and request drawers are well-structured; state resets are consistent.
Consider tests/e2e around QR → sign → success path.
Also applies to: 1691-1692
await this.db.write(); | ||
} | ||
} | ||
private db: any | null = 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
Type safety lost with any
type.
Typing db
as any
eliminates compile-time type checking for all database operations. While necessary due to dynamic imports, this increases the risk of runtime errors from typos or incorrect property access.
Solution: Use proper typing with dynamic imports:
+import type { Low } from 'lowdb';
+
class CacheService {
- private db: any | null = null;
+ private db: Low<CacheData> | null = null;
TypeScript supports type-only imports that don't affect runtime behavior. The type import provides compile-time safety while the dynamic import handles the actual module loading.
📝 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.
private db: any | null = null; | |
import type { Low } from 'lowdb'; | |
class CacheService { | |
private db: Low<CacheData> | null = null; | |
// …rest of class… | |
} |
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/lib/services/cacheService.ts around line 21,
the field is declared as `private db: any | null = null;` which loses type
safety; replace `any` with a proper type-only import for the runtime module
(e.g., `import type { SomeDbType } from 'the-db-package'` or `import type * as
DB from 'the-db-package'` and declare `private db: SomeDbType | null = null` or
`private db: typeof DB | null = null`), then keep the dynamic import for actual
loading at runtime (e.g., `const mod = await import('the-db-package')`),
assigning to `this.db` while preserving the compile-time type from the type-only
import.
constructor() { | ||
// Only initialize on the server side | ||
if (typeof window === 'undefined') { | ||
this.init(); | ||
} | ||
} |
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.
Critical: Fire-and-forget initialization in constructor.
The constructor calls this.init()
without awaiting it (line 27). Since constructors cannot be async, this means the initialization promise is not awaited, creating a race condition where instance methods can be called before this.db
is fully initialized.
Impact: If any method is called immediately after construction (e.g., getCacheStatus()
), it will access this.db
while it's still null
, returning incorrect default values even if a valid cache file exists.
Solution: Remove the constructor initialization and rely on lazy initialization in each method:
constructor() {
- // Only initialize on the server side
- if (typeof window === 'undefined') {
- this.init();
- }
+ // Initialization happens lazily on first access
}
Each method already calls await this.init()
, so the constructor call is both unnecessary and problematic.
📝 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.
constructor() { | |
// Only initialize on the server side | |
if (typeof window === 'undefined') { | |
this.init(); | |
} | |
} | |
constructor() { | |
// Initialization happens lazily on first access | |
} |
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/lib/services/cacheService.ts around lines 24
to 29, the constructor currently fire-and-forgets this.init() causing a race
where methods may access this.db before initialization; remove the constructor
call to this.init() so initialization is only performed lazily by each method
(they already await this.init()), ensuring the constructor does not trigger an
unawaited async start and preventing null db reads.
private async init() { | ||
if (this.isInitialized) return; | ||
|
||
try { | ||
// Dynamically import lowdb only on server | ||
const { Low } = await import('lowdb'); | ||
const { JSONFile } = await import('lowdb/node'); | ||
|
||
// Initialize LowDB with JSON file adapter | ||
const adapter = new JSONFile<CacheData>(CACHE_FILE); | ||
this.db = new Low(adapter, defaultData); | ||
|
||
// Load existing data or create default | ||
await this.db.read(); | ||
if (!this.db.data) { | ||
this.db.data = defaultData; | ||
await this.db.write(); | ||
} | ||
|
||
this.isInitialized = true; | ||
} catch (error) { | ||
console.error('Failed to initialize cache service:', 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.
Race condition in lazy initialization.
Multiple concurrent calls to init()
can race between checking and setting isInitialized
(lines 32-33, 50). If two async operations call methods that trigger init()
simultaneously, both could see isInitialized === false
and proceed to initialize concurrently.
Impact: While unlikely to cause corruption (LowDB handles file writes), this creates unnecessary overhead and could log duplicate error messages.
Solution: Use a promise to coordinate initialization:
class CacheService {
private db: any | null = null;
- private isInitialized = false;
+ private initPromise: Promise<void> | null = null;
private async init() {
- if (this.isInitialized) return;
+ if (this.initPromise) return this.initPromise;
+ this.initPromise = (async () => {
try {
// Dynamically import lowdb only on server
const { Low } = await import('lowdb');
const { JSONFile } = await import('lowdb/node');
// Initialize LowDB with JSON file adapter
const adapter = new JSONFile<CacheData>(CACHE_FILE);
this.db = new Low(adapter, defaultData);
// Load existing data or create default
await this.db.read();
if (!this.db.data) {
this.db.data = defaultData;
await this.db.write();
}
- this.isInitialized = true;
} catch (error) {
console.error('Failed to initialize cache service:', error);
+ this.initPromise = null; // Allow retry on failure
+ throw error;
}
+ })();
+
+ return this.initPromise;
}
📝 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.
private async init() { | |
if (this.isInitialized) return; | |
try { | |
// Dynamically import lowdb only on server | |
const { Low } = await import('lowdb'); | |
const { JSONFile } = await import('lowdb/node'); | |
// Initialize LowDB with JSON file adapter | |
const adapter = new JSONFile<CacheData>(CACHE_FILE); | |
this.db = new Low(adapter, defaultData); | |
// Load existing data or create default | |
await this.db.read(); | |
if (!this.db.data) { | |
this.db.data = defaultData; | |
await this.db.write(); | |
} | |
this.isInitialized = true; | |
} catch (error) { | |
console.error('Failed to initialize cache service:', error); | |
} | |
} | |
class CacheService { | |
private db: any | null = null; | |
private initPromise: Promise<void> | null = null; | |
private async init() { | |
if (this.initPromise) return this.initPromise; | |
this.initPromise = (async () => { | |
try { | |
// Dynamically import lowdb only on server | |
const { Low } = await import('lowdb'); | |
const { JSONFile } = await import('lowdb/node'); | |
// Initialize LowDB with JSON file adapter | |
const adapter = new JSONFile<CacheData>(CACHE_FILE); | |
this.db = new Low(adapter, defaultData); | |
// Load existing data or create default | |
await this.db.read(); | |
if (!this.db.data) { | |
this.db.data = defaultData; | |
await this.db.write(); | |
} | |
} catch (error) { | |
console.error('Failed to initialize cache service:', error); | |
this.initPromise = null; // Allow retry on failure | |
throw error; | |
} | |
})(); | |
return this.initPromise; | |
} | |
} |
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/lib/services/cacheService.ts around lines 31
to 54, multiple concurrent calls to init() can race on the isInitialized flag;
change init to use a single shared initialization promise (e.g.,
this.initPromise) so the first caller sets this.initPromise = (async () => {
...actual init logic... })(), subsequent callers simply await this.initPromise;
inside the initPromise set isInitialized = true on success and clear/reset
this.initPromise on failure (rethrow the error after cleanup) so failed attempts
can be retried and duplicate initialization is prevented.
getCacheStatus(): { lastUpdated: number; isStale: boolean; itemCount: number } { | ||
if (typeof window !== 'undefined') { | ||
// In browser, get from localStorage | ||
try { | ||
const cached = localStorage.getItem('evault-cache'); | ||
if (cached) { | ||
const data = JSON.parse(cached); | ||
return { | ||
lastUpdated: data.lastUpdated || 0, | ||
isStale: data.isStale || false, | ||
itemCount: data.evaults?.length || 0 | ||
}; | ||
} | ||
} catch (error) { | ||
console.log('No localStorage cache available'); | ||
} | ||
return { lastUpdated: 0, isStale: true, itemCount: 0 }; | ||
} | ||
|
||
if (!this.db?.data) { | ||
return { lastUpdated: 0, isStale: true, itemCount: 0 }; | ||
} | ||
|
||
return { | ||
lastUpdated: this.db.data.lastUpdated, | ||
isStale: this.db.data.isStale, | ||
itemCount: this.db.data.evaults.length | ||
}; | ||
} |
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.
Synchronous method accesses asynchronously-initialized state.
getCacheStatus()
is synchronous but directly accesses this.db
(lines 148-156), which may still be null
if called before initialization completes. This is especially problematic when combined with the fire-and-forget constructor initialization.
Impact: Returns incorrect status ({ lastUpdated: 0, isStale: true, itemCount: 0 }
) even when a valid cache exists, misleading users about cache state.
Solution: Make the method async and await initialization:
- getCacheStatus(): { lastUpdated: number; isStale: boolean; itemCount: number } {
+ async getCacheStatus(): Promise<{ lastUpdated: number; isStale: boolean; itemCount: number }> {
if (typeof window !== 'undefined') {
// In browser, get from localStorage
try {
const cached = localStorage.getItem('evault-cache');
if (cached) {
const data = JSON.parse(cached);
return {
lastUpdated: data.lastUpdated || 0,
isStale: data.isStale || false,
itemCount: data.evaults?.length || 0
};
}
} catch (error) {
console.log('No localStorage cache available');
}
return { lastUpdated: 0, isStale: true, itemCount: 0 };
}
+ await this.init();
if (!this.db?.data) {
return { lastUpdated: 0, isStale: true, itemCount: 0 };
}
return {
lastUpdated: this.db.data.lastUpdated,
isStale: this.db.data.isStale,
itemCount: this.db.data.evaults.length
};
}
Note: This requires updating all call sites to await the result.
📝 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.
getCacheStatus(): { lastUpdated: number; isStale: boolean; itemCount: number } { | |
if (typeof window !== 'undefined') { | |
// In browser, get from localStorage | |
try { | |
const cached = localStorage.getItem('evault-cache'); | |
if (cached) { | |
const data = JSON.parse(cached); | |
return { | |
lastUpdated: data.lastUpdated || 0, | |
isStale: data.isStale || false, | |
itemCount: data.evaults?.length || 0 | |
}; | |
} | |
} catch (error) { | |
console.log('No localStorage cache available'); | |
} | |
return { lastUpdated: 0, isStale: true, itemCount: 0 }; | |
} | |
if (!this.db?.data) { | |
return { lastUpdated: 0, isStale: true, itemCount: 0 }; | |
} | |
return { | |
lastUpdated: this.db.data.lastUpdated, | |
isStale: this.db.data.isStale, | |
itemCount: this.db.data.evaults.length | |
}; | |
} | |
async getCacheStatus(): Promise<{ lastUpdated: number; isStale: boolean; itemCount: number }> { | |
if (typeof window !== 'undefined') { | |
// In browser, get from localStorage | |
try { | |
const cached = localStorage.getItem('evault-cache'); | |
if (cached) { | |
const data = JSON.parse(cached); | |
return { | |
lastUpdated: data.lastUpdated || 0, | |
isStale: data.isStale || false, | |
itemCount: data.evaults?.length || 0 | |
}; | |
} | |
} catch (error) { | |
console.log('No localStorage cache available'); | |
} | |
return { lastUpdated: 0, isStale: true, itemCount: 0 }; | |
} | |
// Ensure DB is initialized before accessing it | |
await this.init(); | |
if (!this.db?.data) { | |
return { lastUpdated: 0, isStale: true, itemCount: 0 }; | |
} | |
return { | |
lastUpdated: this.db.data.lastUpdated, | |
isStale: this.db.data.isStale, | |
itemCount: this.db.data.evaults.length | |
}; | |
} |
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/lib/services/cacheService.ts around lines
129 to 157: getCacheStatus is synchronous but reads this.db which is initialized
asynchronously, so it can return stale/empty state if called before init; change
the method to async, await the service initialization (e.g., await
this.initPromise or call an available init method) before accessing this.db,
then return the same shape after the await; update the signature to return a
Promise<{ lastUpdated: number; isStale: boolean; itemCount: number }> and adjust
all call sites to await the result (or handle the returned Promise).
return await hwExists(keyId); | ||
} catch (error) { | ||
console.error('Hardware key exists check failed:', error); | ||
console.error("Hardware key exists check failed:", 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.
🛠️ Refactor suggestion | 🟠 Major
🧩 Analysis chain
Remove/gate console logs and avoid logging key material.
console.* likely breaks lint (“no-console”) and some logs expose sensitive material (e.g., public key, generation result). Remove logs or guard behind a debug logger, and never print keys or cryptographic artifacts.
Apply this minimal diff to pass lint and avoid leaks:
- console.error("Hardware key exists check failed:", error);
+ /* istanbul ignore next */ // avoid console in production
+ // use a project logger if available
+ // logger?.error("Hardware key exists check failed", { error });
- console.log(`Hardware key generated for ${keyId}:`, result);
+ // logger?.debug(`Hardware key generated for ${keyId}`);
- console.error("Hardware key generation failed:", error);
+ // logger?.error("Hardware key generation failed", { error });
- console.log(
- `Hardware public key retrieved for ${keyId}:`,
- publicKey,
- );
+ // logger?.debug(`Hardware public key retrieved for ${keyId}`);
- console.error("Hardware public key retrieval failed:", error);
+ // logger?.error("Hardware public key retrieval failed", { error });
- console.log(`Hardware signature created for ${keyId}`);
+ // logger?.debug(`Hardware signature created for ${keyId}`);
- console.error("Hardware signing failed:", error);
+ // logger?.error("Hardware signing failed", { error });
- console.log(
- `Hardware signature verification for ${keyId}:`,
- isValid,
- );
+ // logger?.debug(`Hardware signature verification for ${keyId}: ${isValid}`);
- console.error("Hardware signature verification failed:", error);
+ // logger?.error("Hardware signature verification failed", { error });
If the codebase lacks a logger, consider a lightweight wrapper (that no-ops in prod) to replace console calls.
Run this to confirm remaining console usages in eid-wallet:
Also applies to: 35-35, 38-38, 50-53, 56-56, 68-68, 71-71, 87-90, 93-93
🏁 Script executed:
#!/bin/bash
rg -n -C1 -g 'infrastructure/eid-wallet/**' -P '\bconsole\.' --no-ignore-vcs
Length of output: 98351
Remove or guard console statements in production code
- Eliminate all
console.*
calls insrc/lib/crypto
,src/lib/services
,src/routes
and other production modules. - Replace with a logger abstraction (e.g.
logger.debug/error
) that’s no-op in production or gated by environment. - Permit
console.*
only in test fixtures and story files (e.g.*.stories.ts
,test-deep-link.html
).
🤖 Prompt for AI Agents
in infrastructure/eid-wallet/src/lib/crypto/HardwareKeyManager.ts around line
23, remove the direct console.error call and replace it with the project logger
abstraction (e.g. logger.error or logger.debug) or guard it behind an
environment check so no console.* calls remain in production modules; import or
reference the existing logger used across src/lib/crypto (or create a thin
wrapper if none), use it to log the error with the same message and error
object, and scan src/lib/crypto, src/lib/services, src/routes for any other
console.* occurrences and replace them similarly (allow console only in test
fixtures and story files).
participants: string[], | ||
name?: string | ||
) => Promise<string>; | ||
createNewChat: (participants: string[], name?: string) => Promise<string>; |
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.
Type signature doesn't match implementation.
The type declares createNewChat
with two parameters (participants: string[], name?: string)
, but the implementation at lines 149-153 accepts a third optional parameter description?: string
. This type mismatch breaks type safety for consumers.
Apply this diff to align the type with the implementation:
- createNewChat: (participants: string[], name?: string) => Promise<string>;
+ createNewChat: (participants: string[], name?: string, description?: string) => Promise<string>;
📝 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.
createNewChat: (participants: string[], name?: string) => Promise<string>; | |
createNewChat: (participants: string[], name?: string, description?: string) => Promise<string>; |
🤖 Prompt for AI Agents
In platforms/blabsy/src/lib/context/chat-context.tsx around line 35, the
declared type for createNewChat lists two parameters (participants: string[],
name?: string) but the implementation accepts a third optional description?:
string; update the type signature to include the third optional parameter
(participants: string[], name?: string, description?: string) so it matches the
implementation and preserves type safety for callers.
if (dataPart.src.startsWith('data:')) { | ||
console.warn(`Incomplete base64 image at index ${i}, skipping`); | ||
console.warn( | ||
`Incomplete base64 image at index ${i}, skipping` | ||
); |
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.
False positive warning for complete base64 URLs.
The condition only checks dataPart.src.startsWith('data:')
without verifying if the URL is actually incomplete (missing a comma). A complete base64 URL like data:image/png;base64,ABC123
would incorrectly trigger this warning.
Apply this diff to fix the logic:
if (dataPart.src.startsWith('data:')) {
+ // Only warn if the base64 URL is actually incomplete (no comma)
+ if (!dataPart.src.includes(',')) {
console.warn(
`Incomplete base64 image at index ${i}, skipping`
);
+ } else {
+ result.push(dataPart);
+ }
} else {
result.push(dataPart);
}
📝 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.
if (dataPart.src.startsWith('data:')) { | |
console.warn(`Incomplete base64 image at index ${i}, skipping`); | |
console.warn( | |
`Incomplete base64 image at index ${i}, skipping` | |
); | |
if (dataPart.src.startsWith('data:')) { | |
// Only warn if the base64 URL is actually incomplete (no comma) | |
if (!dataPart.src.includes(',')) { | |
console.warn( | |
`Incomplete base64 image at index ${i}, skipping` | |
); | |
} else { | |
result.push(dataPart); | |
} | |
} else { | |
result.push(dataPart); | |
} |
🤖 Prompt for AI Agents
In platforms/blabsy/src/lib/utils/image-utils.ts around lines 52 to 55, the code
warns on any string that starts with "data:" even if it is a complete base64
data URL; change the check to detect truly incomplete data URLs by verifying the
presence of the comma that separates the metadata from the data (e.g., ensure
dataPart.src contains a ',' after the media/type section, or use a regex like
/^data:[^,]+,/); only emit the warning and skip when that comma is missing
(indexOf(',') === -1 or regex test fails).
const Breadcrumb = React.forwardRef< | ||
HTMLElement, | ||
React.ComponentPropsWithoutRef<"nav"> & { | ||
separator?: React.ReactNode | ||
} | ||
HTMLElement, | ||
React.ComponentPropsWithoutRef<"nav"> & { | ||
separator?: React.ReactNode | ||
} | ||
>(({ ...props }, ref) => <nav ref={ref} aria-label="breadcrumb" {...props} />) |
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.
Stop forwarding separator
to <nav>
separator
stays in props
, so it ends up as an unknown DOM attribute on <nav>
(rendered as [object Object]
when a ReactNode is supplied) and never reaches the separator elements. The customizable separator feature is therefore broken and produces invalid markup. Please destructure separator
(and wire it into whatever context/prop it’s supposed to drive) instead of spreading it straight onto the DOM node.
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/ui/breadcrumb.tsx around lines 7 to 12, the
forwarded props currently include separator which is being spread onto the <nav>
element creating an invalid DOM attribute and preventing the separator from
reaching the separator elements; destructure separator from the component props
(e.g. ({ separator, ...props }, ref)) so it is not spread onto the DOM, then
pass that separator explicitly to the component(s) that render separators (or
provide it via the appropriate context/prop expected by the breadcrumb
item/rendering logic) so the customizable separator is used correctly.
const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger | ||
|
||
const CommandInput = React.forwardRef< | ||
React.ElementRef<typeof CommandPrimitive.Input>, | ||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input> | ||
>(({ className, ...props }, ref) => ( | ||
<div className="flex items-center border-b px-3" cmdk-input-wrapper=""> | ||
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" /> | ||
<CommandPrimitive.Input | ||
ref={ref} | ||
className={cn( | ||
"flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-hidden placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50", | ||
className | ||
)} | ||
{...props} | ||
/> | ||
</div> | ||
)) | ||
const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent |
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.
Fix Radix component aliases
@radix-ui/react-collapsible
exposes Trigger
and Content
, not CollapsibleTrigger
/CollapsibleContent
. As written, those properties are undefined
, so any consumer import will crash at runtime. Alias the actual exports instead.
-const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger
-
-const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent
+const CollapsibleTrigger = CollapsiblePrimitive.Trigger
+
+const CollapsibleContent = CollapsiblePrimitive.Content
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/ui/command.tsx around lines 7 to 9, the
aliases use non-existent properties CollapsibleTrigger/CollapsibleContent from
@radix-ui/react-collapsible; change the aliases to reference the real exports
Trigger and Content instead (e.g., const CollapsibleTrigger =
CollapsiblePrimitive.Trigger and const CollapsibleContent =
CollapsiblePrimitive.Content) so imports are defined at runtime.
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: 27
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (8)
infrastructure/web3-adapter/src/logging/transport.js (2)
10-13
: Replace hardcoded path traversal with a robust environment file resolution.The hardcoded relative path
"../../../../.env"
is fragile and will break if:
- The file structure changes
- The code is bundled differently
__dirname
resolves differently in various runtime contexts (e.g., when transpiled, bundled, or executed from a different location)Consider using a package like
find-up
ordotenv-flow
to locate the.env
file reliably, or set an explicit environment variable pointing to the configuration directory:-const dotenv_1 = __importDefault(require("dotenv")); -const path_1 = __importDefault(require("path")); -const envPath = path_1.default.resolve(__dirname, "../../../../.env"); -dotenv_1.default.config({ path: envPath }); +const dotenv_1 = __importDefault(require("dotenv")); +// Use explicit env var or find-up package +const envPath = process.env.ENV_PATH || require('find-up').sync('.env'); +if (envPath) { + dotenv_1.default.config({ path: envPath }); +}
14-26
: Add validation for required environment variables and remove insecure defaults.Two security and reliability concerns:
Insecure default credentials: The fallback values
"admin"/"admin"
for Loki authentication are insecure and should not be used in any environment, including development.Missing validation: There's no check to ensure that
LOKI_URL
is set. If it's undefined, the Loki transport will fail silently or produce unhelpful errors at runtime.Apply this diff to add validation and remove insecure defaults:
dotenv_1.default.config({ path: envPath }); + +// Validate required environment variables +const requiredVars = ['LOKI_URL', 'LOKI_USERNAME', 'LOKI_PASSWORD']; +const missing = requiredVars.filter(v => !process.env[v]); +if (missing.length > 0) { + throw new Error(`Missing required environment variables: ${missing.join(', ')}`); +} + exports.transport = (0, pino_1.transport)({ target: "pino-loki", options: { host: process.env.LOKI_URL, labels: { app: "web3-adapter", }, basicAuth: { - username: process.env.LOKI_USERNAME || "admin", - password: process.env.LOKI_PASSWORD || "admin", + username: process.env.LOKI_USERNAME, + password: process.env.LOKI_PASSWORD, }, }, });platforms/blabsy/src/components/aside/aside-trends.tsx (1)
14-18
: Remove the unusedvariants
export.The
variants
object is no longer used since themotion.div
at lines 42-44 now uses inline animation props instead of spreading this object. This export is dead code.Apply this diff to remove the unused export:
-export const variants = { - initial: { opacity: 0 }, - animate: { opacity: 1 }, - transition: { duration: 0.8 } -}; -platforms/blabsy/src/components/chat/chat-window.tsx (1)
285-302
: Fallback operator change may cause breaking behavior.The fallback logic was changed from nullish coalescing (
??
) to logical OR (||
) at multiple locations. This changes the fallback behavior:
??
only falls back onnull
orundefined
||
falls back on any falsy value (empty string""
,0
,false
, etc.)If
otherUser.name
orotherUser.username
can be an empty string, this change will unexpectedly trigger the fallback even when the property exists.Verify whether these fields can be empty strings. If so, revert to
??
to preserve the original behavior:alt={ - otherUser.name || - otherUser.username || + otherUser.name ?? + otherUser.username ?? 'User' }<p className='font-medium'> {getChatType(currentChat) === 'direct' ? otherUser?.name || - otherUser?.username || + otherUser?.username ?? otherParticipant : currentChat.name} </p>platforms/eVoting/src/app/(app)/[id]/page.tsx (1)
715-715
: Remove remainingany
type annotation.Both reduce callbacks still use
any
for thepoints
parameter. SincevoteData.data
is cast toRecord<string, number>
at lines 696 and 877, these should be typed asnumber
.Apply this diff:
-Total: {Object.values(voteData.data).reduce((sum: number, points: any) => sum + points, 0)} points +Total: {Object.values(voteData.data).reduce((sum: number, points: number) => sum + points, 0)} pointsAlso applies to: 896-896
platforms/blabsy/src/lib/context/auth-context.tsx (1)
21-31
: Context contract mismatch:user
can be null at runtime but is typed non‑null.Provider renders after sign‑out with
user
null, yet the context type requiresUser
and code usesuser!
. This risks consumer crashes.Option A (recommended): Make
user
nullable in the context and remove the non‑null assertion.type AuthContext = { - user: User; + user: User | null; error: Error | null; loading: boolean; isAdmin: boolean; randomSeed: string; userBookmarks: Bookmark[] | null; signOut: () => Promise<void>; signInWithGoogle: () => Promise<void>; signInWithCustomToken: (token: string) => Promise<void>; };const value: AuthContext = { - user: user!, + user, error, loading, isAdmin,Option B: Keep
user
non‑null but don’t render the Provider until a user exists (gate UI accordingly).Also applies to: 155-157
infrastructure/web3-adapter/src/logging/transport.ts (1)
12-20
: Validate required env and avoid default admin/admin credentials.
- Fail fast if LOKI_URL is missing.
- Only set basicAuth when both username and password are provided; do not default to admin/admin.
Example refactor outside the changed lines:
const { LOKI_URL, LOKI_USERNAME, LOKI_PASSWORD } = process.env; if (!LOKI_URL) { throw new Error("LOKI_URL is required for web3-adapter logging transport"); } const basicAuth = LOKI_USERNAME && LOKI_PASSWORD ? { username: LOKI_USERNAME, password: LOKI_PASSWORD } : undefined; export const transport = pinoTransport<LokiOptions>({ target: "pino-loki", options: { host: LOKI_URL, labels: { app: "web3-adapter" }, ...(basicAuth ? { basicAuth } as Partial<LokiOptions> : {}), }, });infrastructure/eid-wallet/src/lib/crypto/SoftwareKeyManager.ts (1)
62-72
: Security: private keys persisted in localStorage (extractable).Storing extractable private keys in localStorage is high risk (XSS/extension exfiltration, no OS protection). Prefer:
- Generate non-extractable keys (extractable: false) and persist CryptoKey in IndexedDB.
- Or use platform-bound keys (WebAuthn/Passkeys or hardware-backed store).
If localStorage must be used, at minimum encrypt at rest with a user secret and implement origin-hardening/XSS defenses.
♻️ Duplicate comments (34)
platforms/blabsy/src/lib/context/chat-context.tsx (1)
35-35
: Type signature still doesn't match implementation.This formatting change didn't address the previously flagged type safety issue. The type declares
createNewChat
with two parameters(participants: string[], name?: string)
, but the implementation at lines 149-153 accepts a third optional parameterdescription?: string
.Apply this diff to align the type with the implementation:
- createNewChat: (participants: string[], name?: string) => Promise<string>; + createNewChat: (participants: string[], name?: string, description?: string) => Promise<string>;platforms/blabsy/src/lib/utils/image-utils.ts (1)
52-58
: False positive warning for complete base64 URLs (unresolved from previous review).The previously identified issue remains unfixed: the condition checks
dataPart.src.startsWith('data:')
without verifying the URL is incomplete. A complete base64 URL likedata:image/png;base64,ABC123
incorrectly triggers the warning and gets skipped.Apply this diff to fix the logic:
if (dataPart.src.startsWith('data:')) { + // Only warn if the base64 URL is actually incomplete (no comma) + if (!dataPart.src.includes(',')) { console.warn( `Incomplete base64 image at index ${i}, skipping` ); + } else { + result.push(dataPart); + } } else { result.push(dataPart); }platforms/blabsy/src/components/chat/chat-window.tsx (2)
49-56
: Critical XSS vulnerability remains unaddressed.As flagged in previous reviews,
displayText
(derived from user input) is injected as raw HTML without sanitization. The anchor-tag regex does not prevent script injection—attackers can inject<img src=x onerror=alert(1)>
,<script>
, or other malicious HTML/JS.Install DOMPurify and apply the sanitization fix previously suggested:
pnpm add dompurify pnpm add -D @types/dompurify+import DOMPurify from 'dompurify'; + function MessageItem({ ... <div className='text-sm font-medium text-gray-600 dark:text-gray-400 whitespace-pre-wrap text-left'> <div dangerouslySetInnerHTML={{ - __html: displayText.replace( + __html: DOMPurify.sanitize(displayText.replace( /<a href="([^"]+)">([^<]+)<\/a>/g, '<a href="$1" class="text-blue-600 hover:text-blue-800 underline">$2</a>' - ) + )) }} />
114-120
: Critical XSS vulnerability remains unaddressed.Same issue as system messages.
displayText
is injected as raw HTML without sanitization, enabling XSS attacks.Apply the same DOMPurify sanitization here:
<div className='break-words whitespace-pre-wrap' dangerouslySetInnerHTML={{ - __html: displayText.replace( + __html: DOMPurify.sanitize(displayText.replace( /<a href="([^"]+)">([^<]+)<\/a>/g, '<a href="$1" class="text-blue-600 hover:text-blue-800 underline">$2</a>' - ) + )) }} />infrastructure/web3-adapter/src/db/mapping.db.js (1)
53-57
: TOCTOU race condition remains unaddressed.The check-then-insert pattern at lines 48-52 followed by the INSERT at lines 53-57 is still non-atomic and can result in duplicate rows under concurrent calls. This issue was previously flagged.
infrastructure/web3-adapter/src/evault/evault.js (1)
387-388
: Avoid logging potentially sensitive payloads.The full envelope payload is logged, which may contain PII. This issue was previously flagged. Log only non-sensitive identifiers such as
envelope.w3id
andenvelope.schemaId
.platforms/eVoting/src/components/ui/command.tsx (1)
7-9
: Fix Radix component aliases – critical runtime crash.The prior review comment remains unaddressed:
@radix-ui/react-collapsible
exposesTrigger
andContent
, notCollapsibleTrigger
/CollapsibleContent
. These properties areundefined
at runtime, so any consumer import will crash. Alias the actual exports instead.Apply this diff:
-const CollapsibleTrigger = CollapsiblePrimitive.CollapsibleTrigger +const CollapsibleTrigger = CollapsiblePrimitive.Trigger -const CollapsibleContent = CollapsiblePrimitive.CollapsibleContent +const CollapsibleContent = CollapsiblePrimitive.Contentplatforms/blabsy/src/components/ui/custom-icon.tsx (1)
25-28
: Defensive handling for invalid icon names still needed.The concern raised in the previous review remains unaddressed: if an invalid
iconName
is passed,Icons[iconName]
will beundefined
, causing a runtime error when attempting to render<Icon ... />
. With the weakened type safety from line 14, this risk is elevated.platforms/blabsy/package.json (1)
40-41
: Next 12.3 + TypeScript 5.0.4 are incompatible; pin TS to 4.9.x or upgrade Next
This combo has known build/typecheck issues. Keep TS 5 only if you upgrade Next to 13+; otherwise pin TS to 4.9.x.Apply this diff to keep Next 12.3 and restore compatibility:
- "typescript": "5.0.4" + "typescript": "^4.9.5"Note: Your updated @types/react/dom versions are fine with TS 4.9. No further changes required.
Also applies to: 59-59
infrastructure/control-panel/src/lib/services/cacheService.ts (4)
21-21
: Type safety: replace any with Low.Still untyped; brings avoidable runtime risk. Type-only import keeps runtime tree-shaking intact.
Apply this diff:
- private db: any | null = null; + private db: Low<CacheData> | null = null;Add this import at the top of the file:
import type { Low } from 'lowdb';
24-29
: Remove fire-and-forget init() in constructor (race).Constructors can’t be awaited; this creates a race where methods may observe null db.
Apply this diff to drop the eager call:
- constructor() { - // Only initialize on the server side - if (typeof window === 'undefined') { - this.init(); - } - } + constructor() {}
21-22
: Harden lazy init: coordinate with a shared promise and don’t swallow errors.Boolean guard is racy under concurrent calls; errors are logged but not surfaced.
Apply this diff:
- private db: any | null = null; - private isInitialized = false; + private db: Low<CacheData> | null = null; + private initPromise: Promise<void> | null = null; - private async init() { - if (this.isInitialized) return; - - try { - // Dynamically import lowdb only on server - const { Low } = await import('lowdb'); - const { JSONFile } = await import('lowdb/node'); - - // Initialize LowDB with JSON file adapter - const adapter = new JSONFile<CacheData>(CACHE_FILE); - this.db = new Low(adapter, defaultData); - - // Load existing data or create default - await this.db.read(); - if (!this.db.data) { - this.db.data = defaultData; - await this.db.write(); - } - - this.isInitialized = true; - } catch (error) { - console.error('Failed to initialize cache service:', error); - } - } + private async init() { + if (this.initPromise) return this.initPromise; + this.initPromise = (async () => { + try { + // Dynamically import lowdb only on server + const { Low } = await import('lowdb'); + const { JSONFile } = await import('lowdb/node'); + + // Initialize LowDB with JSON file adapter + const adapter = new JSONFile<CacheData>(CACHE_FILE); + this.db = new Low<CacheData>(adapter, defaultData); + + // Load existing data or create default + await this.db.read(); + if (!this.db.data) { + // Avoid aliasing module-scope defaultData + this.db.data = { evaults: [], lastUpdated: 0, isStale: true }; + await this.db.write(); + } + } catch (error) { + console.error('Failed to initialize cache service:', error); + this.initPromise = null; // allow retry + throw error; + } + })(); + return this.initPromise; + }Also applies to: 31-54
129-157
: Make getCacheStatus async and await init().Synchronous method reads async-initialized state; returns stale defaults if called early.
Apply this diff:
- getCacheStatus(): { lastUpdated: number; isStale: boolean; itemCount: number } { + async getCacheStatus(): Promise<{ lastUpdated: number; isStale: boolean; itemCount: number }> { if (typeof window !== 'undefined') { // In browser, get from localStorage try { const cached = localStorage.getItem('evault-cache'); if (cached) { const data = JSON.parse(cached); return { lastUpdated: data.lastUpdated || 0, isStale: data.isStale || false, itemCount: data.evaults?.length || 0 }; } } catch (error) { console.log('No localStorage cache available'); } return { lastUpdated: 0, isStale: true, itemCount: 0 }; } + await this.init(); if (!this.db?.data) { return { lastUpdated: 0, isStale: true, itemCount: 0 }; } return { lastUpdated: this.db.data.lastUpdated, isStale: this.db.data.isStale, itemCount: this.db.data.evaults.length }; }Note: Update call sites to await this method.
infrastructure/eid-wallet/src/lib/services/NotificationService.ts (2)
200-247
: Extract ensureDeviceRegistration() and remove verbose loggingThis method is long and deeply nested. Extract the registration fallback into a helper and trim logs. This mirrors a prior suggestion.
Example:
private async ensureDeviceRegistration(): Promise<DeviceRegistration | null> { const existing = this.getDeviceRegistration(); if (existing) return existing; const vault = await this.getVaultEname().catch(() => null); if (!vault?.ename) return null; const ok = await this.registerDevice(vault.ename); return ok ? this.getDeviceRegistration() : null; } async checkAndShowNotifications(): Promise<void> { try { const registration = await this.ensureDeviceRegistration(); if (!registration) return; // fetch + display... } catch (e) { console.error("Error checking notifications:", e); } }Also drop console.log occurrences in this method to satisfy lint.
Also applies to: 264-283
43-61
: Remove console.log to satisfy lint; keep only warn/errorThese logs likely trip eslint no-console. Keep error logging; drop the info logs.
- console.log("Notification permission already granted:", isGranted); ... - console.log("Permission request result:", permission);To verify remaining console.log in this file:
#!/bin/bash # Count and show all console.log occurrences in this file rg -n "console\.log\(" infrastructure/eid-wallet/src/lib/services/NotificationService.ts -n -C1infrastructure/eid-wallet/src/routes/+layout.svelte (4)
49-67
: Duplicate: Listener leak - store and dispose deep-link unlisten function.This issue was previously flagged. The
onOpenUrl
returns an unlisten function (promise) that must be stored and cleaned up inonDestroy
to prevent listener leaks.
98-362
: Duplicate: Open redirect/scheme hardening for deep links.This issue was previously flagged. The deep-link handling accepts arbitrary redirect URLs which can enable open-redirects or unsafe schemes. Validation is required before storing or using any redirect parameter.
372-377
: Incomplete cleanup - missing unlisten for onOpenUrl.The
onDestroy
cleanup removes theglobalDeepLinkHandler
but doesn't dispose of theonOpenUrl
listener created at line 62. This creates a resource leak.As noted in the duplicate comment at lines 49-67, you need to store the unlisten function and call it in
onDestroy
:+let unlistenDeepLink: (() => void) | undefined; + onMount(async () => { // ... try { // ... - await onOpenUrl((urls) => { + unlistenDeepLink = await onOpenUrl((urls) => { if (urls && urls.length > 0) { handleDeepLink(urls[0]); } }); } catch (error) { console.error("Failed to initialize deep link listener:", error); } }); onDestroy(() => { if (typeof globalDeepLinkHandler !== "undefined") { window.removeEventListener("deepLinkReceived", globalDeepLinkHandler); } + if (unlistenDeepLink) { + unlistenDeepLink(); + } });
145-208
: Unvalidated redirect parameter enables open redirects.Lines 145-208 (and similar patterns in lines 224-287 for "sign", lines 294-355 for "reveal") accept a
redirect
parameter from the deep link and store it without validation. An attacker could craft a deep link likew3ds://auth?session=x&platform=y&redirect=https://evil.com
to redirect users to malicious sites after authentication.Before storing any redirect URL:
- Parse it as a URL object
- Enforce
url.protocol === 'https:'
- Validate
url.hostname
against an allowlist- Strip
url.hash
to prevent fragment-based attacksif (action === "auth") { const sessionId = params.get("session"); const platform = params.get("platform"); const redirect = params.get("redirect"); if (sessionId && platform && redirect) { + // Validate redirect URL + try { + const redirectUrl = new URL(redirect); + const allowedHosts = new Set(['example.com', 'trusted-domain.com']); // Configure this + + if (redirectUrl.protocol !== 'https:') { + console.error('Blocked redirect with non-https scheme:', redirectUrl.protocol); + return; + } + + if (!allowedHosts.has(redirectUrl.hostname)) { + console.error('Blocked redirect to untrusted host:', redirectUrl.hostname); + return; + } + + // Strip hash/fragment + redirectUrl.hash = ''; + + // Use the validated URL + const validatedRedirect = redirectUrl.toString(); + + const deepLinkData = { + type: "auth", + session: sessionId, + platform: platform, + redirect: validatedRedirect, + }; + } catch (error) { + console.error('Invalid redirect URL:', error); + return; + } - const deepLinkData = { - type: "auth", - session: sessionId, - platform: platform, - redirect: redirect, - };Apply this validation to all redirect parameters in the "auth" and "sign" flows.
infrastructure/eid-wallet/src/routes/(auth)/verify/+page.svelte (2)
2-28
: Duplicate: Console. violations causing lint failures.*As previously flagged, this file contains numerous raw
console.log
,console.error
, andconsole.warn
statements (lines 126, 131-132, 159, 162, 175, 178, 194, 197, 213, 216) that violate lint rules. These must be replaced with a logger utility or wrapped in development guards.
148-166
: Duplicate: Hardware key detection generates test key - use type check instead.As previously flagged, the hardware key detection (lines 148-166) generates a test key which can succeed via software fallback, yielding a false positive for hardware support and polluting the keystore. The detection should instead check the manager type or use a non-mutating API.
infrastructure/eid-wallet/src/routes/(app)/+layout.svelte (1)
16-16
: Duplicate: Context type mismatch - allow undefined in globalState provider.As previously flagged, the
getContext
call assumes a non-optional provider but the setter may have stored a provider that returns undefined. The type should be() => GlobalState | undefined
.infrastructure/eid-wallet/src/routes/(auth)/onboarding/+page.svelte (1)
107-113
: Guard global state context to avoid runtime crash when missing.Provider may be absent; handle undefined safely.
- globalState = getContext<() => GlobalState>("globalState")(); + const getGlobalState = getContext<() => GlobalState | undefined>("globalState"); + const gs = getGlobalState?.(); + if (!gs) { + // optionally redirect or show error UI + await goto("/login"); + return; + } + globalState = gs;infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte (1)
41-41
: Guard global state context (may be undefined).Align with provider possibly absent to avoid runtime errors.
-const globalState = getContext<() => GlobalState>("globalState")(); +const getGlobalState = getContext<() => GlobalState | undefined>("globalState"); +const globalState = getGlobalState?.(); +if (!globalState) { + // optionally navigate or show fallback + goto("/login"); +}infrastructure/eid-wallet/src/lib/crypto/HardwareKeyManager.ts (1)
23-23
: Remove console. and avoid logging crypto material (public keys, results).*These break lint and leak sensitive artifacts. Replace with a logger or delete. Do not print keys/signature state.
@@ - console.error("Hardware key exists check failed:", error); + // logger?.error("Hardware key exists check failed", { error }); @@ - console.log(`Hardware key generated for ${keyId}:`, result); + // logger?.debug(`Hardware key generated for ${keyId}`); @@ - console.error("Hardware key generation failed:", error); + // logger?.error("Hardware key generation failed", { error }); @@ - console.log( - `Hardware public key retrieved for ${keyId}:`, - publicKey, - ); + // logger?.debug(`Hardware public key retrieved for ${keyId}`); @@ - console.error("Hardware public key retrieval failed:", error); + // logger?.error("Hardware public key retrieval failed", { error }); @@ - console.log(`Hardware signature created for ${keyId}`); + // logger?.debug(`Hardware signature created for ${keyId}`); @@ - console.error("Hardware signing failed:", error); + // logger?.error("Hardware signing failed", { error }); @@ - console.log( - `Hardware signature verification for ${keyId}:`, - isValid, - ); + // logger?.debug(`Hardware signature verification for ${keyId}: ${isValid}`); @@ - console.error("Hardware signature verification failed:", error); + // logger?.error("Hardware signature verification failed", { error });Optionally centralize a logger; at minimum, remove console to pass lint.
Also applies to: 35-35, 38-38, 50-53, 56-56, 68-68, 71-71, 87-90, 93-93
infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte (1)
8-13
: Remove unused icon imports (lint error).-import { - Key01Icon, - LanguageSquareIcon, - Link02Icon, - PinCodeIcon, - Shield01Icon, -} from "@hugeicons/core-free-icons"; +import { + LanguageSquareIcon, + PinCodeIcon, + Shield01Icon, +} from "@hugeicons/core-free-icons";infrastructure/eid-wallet/src/routes/(app)/scan-qr/+page.svelte (5)
466-471
: Security/correctness: send the actual public key, not eName.Using eName as publicKey breaks verification and is a flaw.
- const signedPayload = { - sessionId: signingSessionId, - signature: signature, - publicKey: vault?.ename || "unknown_public_key", // Use eName as public key - message: messageToSign, - }; + const signedPayload = { + sessionId: signingSessionId, + signature, + publicKey, // actual crypto public key + w3id: vault?.ename ?? null, // optional identity + message: messageToSign, + };
1116-1141
: Event listener cleanup bug: remove with same function refs.Inline arrows in add/remove don’t match; handlers leak and duplicate.
- // Listen for the new global deep link event - window.addEventListener("deepLinkReceived", (event) => { - console.log("Scan page received deepLinkReceived event:", event); - handleDeepLinkReceived(event as CustomEvent); - }); + // Listen for the new global deep link event + const onDeepLinkReceived = (event: Event) => + handleDeepLinkReceived(event as CustomEvent); + window.addEventListener("deepLinkReceived", onDeepLinkReceived); @@ - window.addEventListener("deepLinkAuth", (event) => - handleAuthEvent(event as CustomEvent), - ); - window.addEventListener("deepLinkSign", (event) => - handleSignEvent(event as CustomEvent), - ); + const onDeepLinkAuth = (event: Event) => + handleAuthEvent(event as CustomEvent); + const onDeepLinkSign = (event: Event) => + handleSignEvent(event as CustomEvent); + window.addEventListener("deepLinkAuth", onDeepLinkAuth); + window.addEventListener("deepLinkSign", onDeepLinkSign); @@ - onDestroy(() => { - window.removeEventListener("deepLinkReceived", (event) => - handleDeepLinkReceived(event as CustomEvent), - ); - window.removeEventListener("deepLinkAuth", (event) => - handleAuthEvent(event as CustomEvent), - ); - window.removeEventListener("deepLinkSign", (event) => - handleSignEvent(event as CustomEvent), - ); - }); + onDestroy(() => { + window.removeEventListener("deepLinkReceived", onDeepLinkReceived); + window.removeEventListener("deepLinkAuth", onDeepLinkAuth); + window.removeEventListener("deepLinkSign", onDeepLinkSign); + });
285-294
: Harden URL parsing; avoid throws on invalid redirect.-function handleAuthRequest(content: string) { - const url = new URL(content); - platform = url.searchParams.get("platform"); - const redirectUrl = new URL(url.searchParams.get("redirect") || ""); - redirect = url.searchParams.get("redirect"); - session = url.searchParams.get("session"); - hostname = redirectUrl.hostname; +function handleAuthRequest(content: string) { + let url: URL; + try { + url = new URL(content); + } catch { + return; + } + platform = url.searchParams.get("platform") ?? undefined; + redirect = url.searchParams.get("redirect"); + session = url.searchParams.get("session"); + let redirectUrl: URL | null = null; + try { + redirectUrl = redirect ? new URL(redirect) : null; + } catch { + redirectUrl = null; + } + hostname = redirectUrl?.hostname ?? "unknown"; isSigningRequest = false; codeScannedDrawerOpen = true; }
202-211
: Redirect hardening: enforce HTTPS (optionally allowlist).- // Check if URL is valid - try { - new URL(data.redirect); - console.log("Redirect URL is valid"); + // Check if URL is valid and HTTPS + try { + const u = new URL(data.redirect); + if (u.protocol !== "https:") { + throw new Error("Non-HTTPS redirect blocked"); + } + // Optional: host allowlist + // const allowed = ["example.com"]; + // if (!allowed.includes(u.hostname)) throw new Error("Unapproved host"); } catch (urlError) {Also applies to: 213-259
542-549
: Validate platformUrl to avoid SSRF-like fetches from QR data.- // Fetch poll details from the platform - const pollResponse = await fetch(`${platformUrl}/api/polls/${pollId}`); + // Fetch poll details from the platform (validated base) + let base = ""; + try { + const u = new URL(platformUrl || ""); + if (u.protocol !== "https:") throw new Error("Invalid platform URL"); + base = u.origin; + } catch { + throw new Error("Invalid platform URL"); + } + const pollResponse = await fetch(`${base}/api/polls/${pollId}`);infrastructure/eid-wallet/src/lib/crypto/SoftwareKeyManager.ts (3)
21-21
: Replace console. with the centralized logger; avoid logging sensitive material.*Console calls likely violate lint rules and risk leaking operational/sensitive info (key presence, signatures, verification outcomes).
- Replace all console.* with the project logger at appropriate levels.
- Remove logs that expose key lifecycle, signatures, or verification outcomes in production.
Also applies to: 34-35, 73-76, 104-105, 157-160, 215-218, 221-221, 242-242
1-2
: Fix ESLint “no-undef” for browser globals.Declare browser env so localStorage/atob/btoa/crypto/TextEncoder are recognized by ESLint. This also addresses the failing lint job.
Apply:
+/* eslint-env browser */ import type { KeyManager, SoftwareKeyPair } from "./types"; import { KeyManagerError, KeyManagerErrorCodes } from "./types";
Based on pipeline failures
99-103
: Wrong multibase prefix with hex; return raw hex (or truly encode base58btc).You compute hex then prefix with 'z' (base58btc), which is inconsistent and breaks interop. Prefer returning pure hex (as downstream typically expects), or actually encode base58btc.
Apply minimal fix (return pure hex):
- // Add multibase prefix (assuming 'z' for base58btc, but we'll use hex for simplicity) - return `z${publicKeyHex}`; + // Return pure hex to align with downstream hex parsers + return publicKeyHex;If unsure, verify consumers expect hex:
#!/bin/bash rg -n -C2 -P '\bhexToUint8Array\s*\(|multibase|base58' infrastructure
🧹 Nitpick comments (21)
platforms/blabsy/src/components/aside/aside-trends.tsx (1)
2-2
: Consider removing the React import.With React 17+ and the new JSX transform, explicitly importing React is typically unnecessary unless you're directly using React APIs in the component.
Apply this diff if the project uses React 17+ with the new JSX transform:
-import React from 'react';
platforms/blabsy/src/components/login/login-main.tsx (1)
108-118
: Consider extracting duplicated expiry message.The expiry text block is duplicated between mobile and desktop sections. While not critical, extracting it to a shared component or constant would align with DRY principles and make future updates easier.
Example:
const ExpiryMessage = () => ( <div className='text-center mt-4'> <p className='text-sm text-gray-500'> <span className='mb-1 block font-bold text-gray-600'> The {isMobileDevice() ? 'button' : 'code'} is valid for 60 seconds </span> <span className='block font-light text-gray-600'> Please refresh the page if it expires </span> </p> </div> );Also applies to: 134-144
platforms/eVoting/src/components/ui/sidebar.tsx (1)
81-94
: RefactorsetOpen
to avoid stale callback recreations.Including
open
in the dependency array defeats the memoization benefit ofuseCallback
. The callback will be recreated every timeopen
changes, potentially causing unnecessary re-renders of child components that receive it as a prop.Consider using a ref to track the latest
open
value:+ const openRef = React.useRef(open) + React.useEffect(() => { + openRef.current = open + }, [open]) + const setOpen = React.useCallback( (value: boolean | ((value: boolean) => boolean)) => { - const openState = typeof value === "function" ? value(open) : value + const openState = typeof value === "function" ? value(openRef.current) : value if (setOpenProp) { setOpenProp(openState) } else { _setOpen(openState) } // This sets the cookie to keep the sidebar state. document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}` }, - [setOpenProp, open] + [setOpenProp] )platforms/eVoting/src/app/(app)/[id]/page.tsx (2)
438-438
: Consider removing unnecessary visibility type casts.The code casts
selectedPoll.visibility
tostring
in multiple places. If thePoll
type already definesvisibility
as a string (which it should), these casts are redundant. Ifvisibility
is not properly typed in thePoll
interface, consider fixing the type definition at the source instead of using assertions.You can verify the Poll type definition and remove these casts if unnecessary:
-{selectedPoll.visibility === "private" ? ( +{(selectedPoll.visibility as string) !== "private" ? (should be:
-{(selectedPoll.visibility as string) !== "private" ? ( +{selectedPoll.visibility !== "private" ? (Also applies to: 555-555, 1276-1276
568-568
: Consider using discriminated unions for VoteData.The code uses type assertions (e.g.,
as PointVoteData[]
,as string[]
,as Record<string, number>
) after checking the mode string. While this works, a discriminated union type would provide compile-time type safety and eliminate the need for assertions.Example discriminated union approach:
type NormalVoteData = { mode: "normal"; data: string[]; }; type PointVoteData = { mode: "point"; data: Record<string, number>; }; type RankVoteData = { mode: "rank"; data: Array<{option: string; points: number}>; }; type VoteData = NormalVoteData | PointVoteData | RankVoteData;This would allow TypeScript to narrow the type automatically after checking the
mode
property, eliminating the need for type assertions.Also applies to: 603-603, 607-607, 617-617, 621-621, 680-680, 696-696, 861-861, 877-877
platforms/eVoting/src/components/ui/carousel.tsx (1)
86-97
: Consider adding keyboard support for vertical orientation.The keyboard handler only supports
ArrowLeft
andArrowRight
, but the carousel can be vertically oriented. For better UX, consider handlingArrowUp
andArrowDown
whenorientation === "vertical"
.Apply this diff to add vertical keyboard support:
const handleKeyDown = React.useCallback( (event: React.KeyboardEvent<HTMLDivElement>) => { - if (event.key === "ArrowLeft") { + if (event.key === "ArrowLeft" || (orientation === "vertical" && event.key === "ArrowUp")) { event.preventDefault() scrollPrev() - } else if (event.key === "ArrowRight") { + } else if (event.key === "ArrowRight" || (orientation === "vertical" && event.key === "ArrowDown")) { event.preventDefault() scrollNext() } }, - [scrollPrev, scrollNext] + [scrollPrev, scrollNext, orientation] )infrastructure/control-panel/package.json (1)
23-23
: Add a start script and pin Node engine
- Under scripts, add
"start": "node build/index.js"
.- Add an
"engines": { "node": ">=18" }
field.- (Optional) switch the existing
preview
script tosvelte-kit preview
for SSR preview.platforms/blabsy/src/lib/context/auth-context.tsx (3)
92-99
: Guard against missinguser.id
before subscribing to Firestore.If the user document doesn't store an
id
field,id
will beundefined
, anddoc(usersCollection, id)
will throw. Add a defensive check (and optionally fall back) to prevent runtime errors.Apply this within the effect:
const { id } = user; - const unsubscribeUser = onSnapshot( + if (!id) { + console.error('[DEBUG] Missing user.id; skipping user listener'); + return; + } + const unsubscribeUser = onSnapshot( doc(usersCollection, id), (doc) => { setUser(doc.data() as User); },Additionally, consider ensuring
id
is set when loading the user:// In manageUser(), after fetching userSnapshot: const userData = userSnapshot.data(); setUser({ id: uid, ...userData }); // ensure id is present
86-87
: Return the unsubscribe fromonAuthStateChanged
to avoid a listener leak.Current effect doesn’t clean up the auth listener on unmount.
- onAuthStateChanged(auth, handleUserAuth); + const unsubscribe = onAuthStateChanged(auth, handleUserAuth); + return unsubscribe;
49-51
: Remove debugconsole.log(uid)
or guard it.Avoid noisy logs and potential PII leakage in production.
- console.log(uid);
platforms/eVoting/package.json (1)
1-5
: Add engines to pin Node/PNPM versions for reproducible builds.Prevents CI/environment drift (Next 15/Tailwind 4 often require modern Node). Suggest:
Apply this diff:
{ "name": "evoting", "version": "0.1.0", "private": true, + "engines": { + "node": ">=20.10.0", + "pnpm": ">=9.0.0" + }, "scripts": {infrastructure/control-panel/src/lib/services/cacheService.ts (2)
10-11
: Resolve cache path and ensure directory exists.Relative './evault-cache.json' depends on cwd and may fail if parent dir missing. Prefer a fixed data dir and mkdir -p.
Apply this diff:
-// Cache file path (will be created in the project root) -const CACHE_FILE = './evault-cache.json'; +// Cache file path (under configurable data dir) +const DATA_DIR = process.env.CACHE_DIR ?? '.data'; +const CACHE_FILE = `${DATA_DIR}/evault-cache.json`;Add these imports at top:
import { existsSync, mkdirSync } from 'node:fs';Ensure directory exists in init before creating the adapter:
- // Initialize LowDB with JSON file adapter + // Ensure data directory exists, then init LowDB + if (!existsSync(DATA_DIR)) mkdirSync(DATA_DIR, { recursive: true }); const adapter = new JSONFile<CacheData>(CACHE_FILE);Operational note: If you ever scale to multiple Node processes/containers, a single JSON file is not safe for concurrent writes. Use a process-safe store (SQLite/Postgres/KV) or a per-process cache with external invalidation.
Also applies to: 39-41
77-88
: Respect manual stale flag in isCacheStale().Currently only time-based. Consider combining with isStale for correctness.
Apply this diff:
- await this.init(); - const lastUpdated = this.db?.data?.lastUpdated || 0; - const now = Date.now(); - const fiveMinutes = 5 * 60 * 1000; // 5 minutes in milliseconds - - return now - lastUpdated > fiveMinutes; + await this.init(); + const d = this.db?.data; + if (!d) return true; + const now = Date.now(); + const fiveMinutes = 5 * 60 * 1000; // 5 minutes + return d.isStale || now - d.lastUpdated > fiveMinutes;infrastructure/eid-wallet/src/lib/services/NotificationService.ts (3)
72-77
: Don’t block device registration on notification permissionRegistration can proceed even if user declines notifications. Only local notifications require permission.
- const hasPermission = await this.requestPermissions(); - if (!hasPermission) { - throw new Error("Notification permissions not granted"); - } + // Best-effort request; do not block device registration + await this.requestPermissions().catch(() => false);
292-299
: Remove debug logging in testNotificationLeave this helper, but drop console.log to pass lint.
- console.log("🧪 Testing notification...");
318-328
: Prefer crypto.randomUUID(); consider persisting deviceIdAvoid adding a uuid dependency; use crypto.randomUUID, and optionally persist the generated ID in Tauri Store to keep it stable across runs.
- // Fallback to generating a UUID - const { v4: uuidv4 } = await import("uuid"); - return uuidv4(); + // Fallback: prefer built-in crypto.randomUUID() + if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") { + return crypto.randomUUID(); + } + const { v4: uuidv4 } = await import("uuid"); + return uuidv4();If you want persistence, save/read a stored deviceId via @tauri-apps/plugin-store.
infrastructure/eid-wallet/src/routes/(app)/main/+page.svelte (1)
55-55
: Remove console.log to pass lint.- console.log("status current", profileCreationStatus); + // logger?.debug("status current", profileCreationStatus);infrastructure/eid-wallet/src/routes/(app)/settings/+page.svelte (2)
16-16
: Guard global state context to avoid runtime when missing.-const globalState = getContext<() => GlobalState>("globalState")(); +const getGlobalState = getContext<() => GlobalState | undefined>("globalState"); +const globalState = getGlobalState?.(); +if (!globalState) { + goto("/onboarding"); +}
80-83
: Remove console. in UI code (lint).*- } catch (error) { - console.error("Failed to retry eVault profile setup:", error); + } catch (error) { + // logger?.error("Failed to retry eVault profile setup", { error }); retryMessage = "❌ Failed to setup eVault profile. Check console for details.";infrastructure/eid-wallet/src/lib/crypto/SoftwareKeyManager.ts (2)
30-36
: Narrow the return type for generate.The method returns fixed literals ("key-exists" | "key-generated"). Tighten typing for clarity and safety.
Proposed update in types.ts (outside this hunk):
// types.ts export type KeyGenerationResult = "key-exists" | "key-generated"; export interface KeyManager { generate(keyId: string): Promise<KeyGenerationResult>; }Then keep this implementation returning those literals.
17-19
: Avoid shadowing class property name “storageKey”.Local variable named storageKey shadows the class field, hurting readability.
Apply:
-const storageKey = this.getStorageKey(keyId); -const stored = localStorage.getItem(storageKey); +const itemKey = this.getStorageKey(keyId); +const stored = localStorage.getItem(itemKey);-const storageKey = this.getStorageKey(keyId); -localStorage.setItem(storageKey, JSON.stringify(keyPairData)); +const itemKey = this.getStorageKey(keyId); +localStorage.setItem(itemKey, JSON.stringify(keyPairData));-const storageKey = this.getStorageKey(keyId); -const stored = localStorage.getItem(storageKey); +const itemKey = this.getStorageKey(keyId); +const stored = localStorage.getItem(itemKey);Also applies to: 70-71, 235-237
this.db.data = defaultData; | ||
await this.db.write(); | ||
} |
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.
Avoid mutating module-scope defaultData (shared reference).
Assigning defaultData directly aliases it; later mutations (e.g., markStale) modify the template.
Apply this diff:
- this.db.data = defaultData;
+ this.db.data = { evaults: [], lastUpdated: 0, isStale: true };
await this.db.write();
📝 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.
this.db.data = defaultData; | |
await this.db.write(); | |
} | |
this.db.data = { evaults: [], lastUpdated: 0, isStale: true }; | |
await this.db.write(); | |
} |
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/lib/services/cacheService.ts around lines 46
to 48, the code assigns the module-scoped defaultData directly to this.db.data
which creates a shared reference and allows later mutations to alter the
template; instead, assign a deep copy of defaultData (for example using
structuredClone(defaultData) or a deep-clone utility like
lodash.clonedeep/JSON.parse(JSON.stringify(defaultData)) depending on
environment) so this.db.data is an independent object before calling await
this.db.write().
await this.init(); | ||
if (this.db) { | ||
this.db.data = defaultData; | ||
await this.db.write(); | ||
} |
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.
Clear with a fresh object, not defaultData.
Prevents aliasing and ensures a true reset.
Apply this diff:
- if (this.db) {
- this.db.data = defaultData;
- await this.db.write();
- }
+ if (this.db) {
+ this.db.data = { evaults: [], lastUpdated: 0, isStale: true };
+ await this.db.write();
+ }
📝 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.
await this.init(); | |
if (this.db) { | |
this.db.data = defaultData; | |
await this.db.write(); | |
} | |
await this.init(); | |
if (this.db) { | |
this.db.data = { evaults: [], lastUpdated: 0, isStale: true }; | |
await this.db.write(); | |
} |
🤖 Prompt for AI Agents
in infrastructure/control-panel/src/lib/services/cacheService.ts around lines
170 to 174, the reset assigns this.db.data = defaultData which aliases the
shared defaultData object; change it to assign a fresh copy to avoid aliasing
and ensure a true reset — create a deep copy (prefer
structuredClone(defaultData) if available, otherwise use
JSON.parse(JSON.stringify(defaultData)) or another deep-clone util) and assign
that to this.db.data, then await this.db.write().
constructor() { | ||
// Get the provisioner endpoint from environment or use default | ||
this.provisionerEndpoint = PUBLIC_PROVISIONER_URL; | ||
} |
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
Fail-fast or fallback for PUBLIC_PROVISIONER_URL; normalize base URL
Currently you set provisionerEndpoint directly. If the env var is missing/empty or has a trailing slash, network calls will fail or build breaks on some targets.
Apply:
- constructor() {
- // Get the provisioner endpoint from environment or use default
- this.provisionerEndpoint = PUBLIC_PROVISIONER_URL;
- }
+ constructor() {
+ // Validate and normalize base URL
+ const base = (PUBLIC_PROVISIONER_URL || "").trim();
+ if (!base) {
+ throw new Error("Missing PUBLIC_PROVISIONER_URL");
+ }
+ this.provisionerEndpoint = base.replace(/\/+$/, "");
+ }
📝 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.
constructor() { | |
// Get the provisioner endpoint from environment or use default | |
this.provisionerEndpoint = PUBLIC_PROVISIONER_URL; | |
} | |
constructor() { | |
// Validate and normalize base URL | |
const base = (PUBLIC_PROVISIONER_URL || "").trim(); | |
if (!base) { | |
throw new Error("Missing PUBLIC_PROVISIONER_URL"); | |
} | |
this.provisionerEndpoint = base.replace(/\/+$/, ""); | |
} |
🤖 Prompt for AI Agents
in infrastructure/eid-wallet/src/lib/services/NotificationService.ts around
lines 28-31, you currently assign PUBLIC_PROVISIONER_URL directly to
provisionerEndpoint; validate and normalize it instead: if the env var is
missing or empty, either throw an explicit error (fail-fast) or fall back to a
known default constant, and strip any trailing slash(s) from the URL so network
calls compose correctly; also ensure the resulting value is a valid absolute URL
(e.g., via a simple regex or URL constructor) before assigning to
this.provisionerEndpoint.
// Send registration to provisioner | ||
const response = await fetch( | ||
`${this.provisionerEndpoint}/api/devices/register`, | ||
{ | ||
method: "POST", | ||
headers: { | ||
"Content-Type": "application/json", | ||
}, | ||
body: JSON.stringify(registration), | ||
}, | ||
); | ||
|
||
if (response.ok) { | ||
this.deviceRegistration = registration; |
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
Add timeouts to external fetch to avoid hangs
Network calls lack timeouts; a stalled provisioner will hang the UI.
- // Send registration to provisioner
- const response = await fetch(
- `${this.provisionerEndpoint}/api/devices/register`,
- {
- method: "POST",
- headers: {
- "Content-Type": "application/json",
- },
- body: JSON.stringify(registration),
- },
- );
+ // Send registration to provisioner (with timeout)
+ const controller = new AbortController();
+ const timeout = setTimeout(() => controller.abort(), 10000);
+ const response = await fetch(`${this.provisionerEndpoint}/api/devices/register`, {
+ method: "POST",
+ headers: { "Content-Type": "application/json" },
+ body: JSON.stringify(registration),
+ signal: controller.signal,
+ }).finally(() => clearTimeout(timeout));
Repeat for other fetches in this file. Prefer extracting a small helper (fetchWithTimeout) to DRY.
Also applies to: 100-111
🤖 Prompt for AI Agents
in infrastructure/eid-wallet/src/lib/services/NotificationService.ts around
lines 92-105 (and also 100-111), network fetch calls have no timeout and can
hang the UI; create a small helper fetchWithTimeout(url, options, timeoutMs)
that uses AbortController to cancel the request after a configurable timeout
(e.g., 10_000 ms) and rejects with a clear timeout error, then replace the raw
fetch calls in these ranges with fetchWithTimeout using the same url/options and
the chosen timeout; ensure callers handle the timeout error path similarly to
other network errors and reuse the helper for other fetches in this file to DRY.
async sendLocalNotification(payload: NotificationPayload): Promise<void> { | ||
try { | ||
console.log("Attempting to send local notification:", payload); | ||
|
||
// Check permissions first | ||
const hasPermission = await isPermissionGranted(); | ||
console.log("Has notification permission:", hasPermission); | ||
|
||
if (!hasPermission) { | ||
console.warn("No notification permission, requesting..."); | ||
const granted = await this.requestPermissions(); | ||
if (!granted) { | ||
console.error("Failed to get notification permission"); | ||
return; | ||
} | ||
} | ||
|
||
console.log("Sending notification with payload:", { | ||
title: payload.title, | ||
body: payload.body, | ||
icon: "icons/32x32.png", | ||
sound: "default", | ||
data: payload.data, | ||
}); | ||
|
||
await sendNotification({ | ||
title: payload.title, | ||
body: payload.body, | ||
icon: "icons/32x32.png", | ||
sound: "default", | ||
data: payload.data, | ||
}); | ||
|
||
console.log("Notification sent successfully!"); | ||
} catch (error) { | ||
console.error("Failed to send local notification:", 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.
🧩 Analysis chain
Remove debug logs; verify plugin-notification options
Trim console.log to pass lint. Keep warn/error. Also verify sendNotification options (icon, sound, data) match plugin API.
- console.log("Attempting to send local notification:", payload);
...
- console.log("Has notification permission:", hasPermission);
...
- console.log("Sending notification with payload:", {
- title: payload.title,
- body: payload.body,
- icon: "icons/32x32.png",
- sound: "default",
- data: payload.data,
- });
...
- console.log("Notification sent successfully!");
To confirm option support:
🌐 Web query:
@tauri-apps/plugin-notification sendNotification options: which fields are supported (title, body, icon, sound, data) and their types?
💡 Result:
Short answer — yes. sendNotification accepts:
- title: string. [1]
- body: string (optional). [1]
- icon: string (path or resource name; Android requires res/drawable). [2]
- sound: string (resource name or file path; platform-specific behavior). [2]
- extra (aka data/payload): Record<string, unknown> (arbitrary key/value object). [2]
Sources: Tauri notification JS reference (Options list) and plugin docs. [1] https://v2.tauri.app/reference/javascript/notification/ (Options) — [2] https://tauri.app/plugin/notification/ (Usage & sound/icon details).
Trim debug logs and align sendNotification payload
- Remove all
console.log
calls in sendLocalNotification (retain console.warn/error). - Rename the
data
property in sendNotification’s options toextra
(plugin expectsextra: Record<string, unknown>
).
🤖 Prompt for AI Agents
in infrastructure/eid-wallet/src/lib/services/NotificationService.ts around
lines 120 to 157, remove all console.log calls inside sendLocalNotification but
keep the existing console.warn and console.error; next, change the
sendNotification call (and any constructed options passed to it) to replace the
data property with extra and pass payload.data as extra: Record<string, unknown>
so the plugin receives extra instead of data; ensure any local object literals
used for logging or sending are updated accordingly and no leftover references
to data remain.
}; | ||
|
||
const Icons = { | ||
const Icons: Record<string, React.ComponentType<IconProps>> = { |
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.
Type annotation weakens IconName
type safety.
By explicitly typing Icons
as Record<string, React.ComponentType<IconProps>>
, the expression keyof typeof Icons
on line 4 resolves to string
instead of a union of the specific icon names ('PinIcon' | 'AppleIcon' | ...
). This means any string can be passed as iconName
without TypeScript catching invalid values at compile time.
Remove the explicit type annotation to restore type safety:
-const Icons: Record<string, React.ComponentType<IconProps>> = {
+const Icons = {
PinIcon,
AppleIcon,
PinOffIcon,
GoogleIcon,
TwitterIcon,
FeatherIcon,
SpinnerIcon,
TriangleIcon
-};
+} as const satisfies Record<string, React.ComponentType<IconProps>>;
This preserves the structural constraint while allowing TypeScript to infer the specific keys.
📝 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 Icons: Record<string, React.ComponentType<IconProps>> = { | |
const Icons = { | |
PinIcon, | |
AppleIcon, | |
PinOffIcon, | |
GoogleIcon, | |
TwitterIcon, | |
FeatherIcon, | |
SpinnerIcon, | |
TriangleIcon | |
} as const satisfies Record<string, React.ComponentType<IconProps>>; |
🤖 Prompt for AI Agents
In platforms/blabsy/src/components/ui/custom-icon.tsx around line 14, the
explicit type annotation Record<string, React.ComponentType<IconProps>> causes
keyof typeof Icons to collapse to string, losing the specific icon-name union;
remove the explicit annotation and let TypeScript infer the object literal type
(or alternatively use a const assertion) so the keys are inferred as the
specific icon names, preserving compile-time validation of valid iconName
values.
"@radix-ui/react-accordion": "^1.2.12", | ||
"@radix-ui/react-alert-dialog": "^1.1.14", | ||
"@radix-ui/react-aspect-ratio": "^1.1.7", | ||
"@radix-ui/react-avatar": "^1.1.10", | ||
"@radix-ui/react-checkbox": "^1.3.3", | ||
"@radix-ui/react-collapsible": "^1.1.12", | ||
"@radix-ui/react-context-menu": "^2.2.16", | ||
"@radix-ui/react-dialog": "^1.1.14", | ||
"@radix-ui/react-dropdown-menu": "^2.1.15", | ||
"@radix-ui/react-hover-card": "^1.1.15", | ||
"@radix-ui/react-label": "^2.1.3", | ||
"@radix-ui/react-menubar": "^1.1.16", | ||
"@radix-ui/react-navigation-menu": "^1.2.14", | ||
"@radix-ui/react-popover": "^1.1.14", | ||
"@radix-ui/react-progress": "^1.1.7", | ||
"@radix-ui/react-radio-group": "^1.2.4", | ||
"@radix-ui/react-scroll-area": "^1.2.10", | ||
"@radix-ui/react-select": "^2.2.6", | ||
"@radix-ui/react-separator": "^1.1.7", | ||
"@radix-ui/react-slider": "^1.3.6", | ||
"@radix-ui/react-slot": "^1.2.0", | ||
"@radix-ui/react-switch": "^1.2.5", | ||
"@radix-ui/react-tabs": "^1.1.13", | ||
"@radix-ui/react-toast": "^1.2.4", | ||
"@radix-ui/react-toggle": "^1.1.10", | ||
"@radix-ui/react-toggle-group": "^1.1.11", | ||
"@radix-ui/react-tooltip": "^1.2.8", |
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 peerDeps against React 19/Next 15 and confirm actual usage of new deps.
Large set of UI deps added. With pnpm’s strict peer-deps, any package not declaring React 19/Next 15 support can break install/build. Also, ensure each added dep is really used in platforms/eVoting to avoid bloat.
Run this script to:
- Print peerDependencies for each dep (highlighting React/Next peers).
- Check if each dep is imported anywhere under platforms/eVoting.
If any package shows React/Next peer ranges excluding 19/15, bump to a compatible version or relax pnpm peer rules for that package.
Also applies to: 44-46, 51-51, 54-55, 58-58
🏁 Script executed:
#!/bin/bash
set -euo pipefail
APP_DIR="platforms/eVoting"
cd "$APP_DIR"
echo "== List peerDependencies for each dependency =="
jq -r '.dependencies | to_entries[] | "\(.key)@\(.value)"' package.json | while read -r spec; do
name="${spec%@*}"
ver="${spec#*@}"; ver="${ver#^}"; ver="${ver#~}"
echo "---- $name@$ver ----"
npm view "$name@$ver" peerDependencies --json 2>/dev/null | jq -r '
if . == null then "no peer deps"
else to_entries[] | "\(.key) -> \(.value)"
end
' || echo "no peer deps (or not found)"
done
echo
echo "== Check import usage for each dependency in $APP_DIR =="
jq -r '.dependencies | keys[]' package.json | while read -r name; do
if rg -n -g '!**/node_modules/**' -C1 -e "from ['\"]${name}['\"]" -e "require\\(['\"]${name}['\"]\\)" -e "import\\s+['\"]${name}['\"]" . >/dev/null; then
echo "USED: $name"
else
echo "MISSING_USAGE: $name"
fi
done
Length of output: 13481
Drop unused deps & resolve React peer mismatches in platforms/eVoting/package.json
- Remove unused dependencies:
@hookform/resolvers
,@tailwindcss/typography
,react-dom
,tailwindcss-animate
. [email protected]
and[email protected]
peer-depend on React ≤18; upgrade to versions that declare React 19 support or add peer-dependency overrides.- (Optional) Add an
engines
field to pin Node and pnpm versions for reproducible installs.
🤖 Prompt for AI Agents
platforms/eVoting/package.json lines 13-39: remove the unused dependencies
@hookform/resolvers, @tailwindcss/typography, react-dom, and tailwindcss-animate
from package.json dependencies, and address the React peer mismatch for
[email protected] and [email protected] by either upgrading those
packages to versions that declare React 19 compatibility or adding
peerDependencyOverrides/overrides that map those packages to compatible
releases; optionally add an "engines" field to package.json to pin the Node and
pnpm versions for reproducible installs.
React.useEffect(() => { | ||
if (!api) { | ||
return | ||
} | ||
|
||
onSelect(api) | ||
api.on("reInit", onSelect) | ||
api.on("select", onSelect) | ||
onSelect(api) | ||
api.on("reInit", onSelect) | ||
api.on("select", onSelect) | ||
|
||
return () => { | ||
api?.off("select", onSelect) | ||
} | ||
}, [api, onSelect]) | ||
return () => { | ||
api?.off("select", onSelect) | ||
} | ||
}, [api, onSelect]) |
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
Incomplete event listener cleanup.
The cleanup function removes the "select" listener but not the "reInit" listener that was registered on line 113. This could cause memory leaks or stale event handlers.
Apply this diff to clean up both event listeners:
return () => {
api?.off("select", onSelect)
+ api?.off("reInit", onSelect)
}
📝 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.
React.useEffect(() => { | |
if (!api) { | |
return | |
} | |
onSelect(api) | |
api.on("reInit", onSelect) | |
api.on("select", onSelect) | |
onSelect(api) | |
api.on("reInit", onSelect) | |
api.on("select", onSelect) | |
return () => { | |
api?.off("select", onSelect) | |
} | |
}, [api, onSelect]) | |
return () => { | |
api?.off("select", onSelect) | |
} | |
}, [api, onSelect]) | |
React.useEffect(() => { | |
if (!api) { | |
return | |
} | |
onSelect(api) | |
api.on("reInit", onSelect) | |
api.on("select", onSelect) | |
return () => { | |
api?.off("select", onSelect) | |
api?.off("reInit", onSelect) | |
} | |
}, [api, onSelect]) |
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/ui/carousel.tsx around lines 107 to 119, the
effect registers both "reInit" and "select" listeners on api but the cleanup
only removes "select"; update the cleanup to remove both listeners
(api.off("select", onSelect) and api.off("reInit", onSelect)), using the same
onSelect handler and optional chaining (api?.off(...)) to avoid runtime errors.
<style | ||
dangerouslySetInnerHTML={{ | ||
__html: Object.entries(THEMES) | ||
.map( | ||
([theme, prefix]) => ` | ||
${prefix} [data-chart=${id}] { | ||
${colorConfig | ||
.map(([key, itemConfig]) => { | ||
const color = | ||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || | ||
itemConfig.color | ||
return color ? ` --color-${key}: ${color};` : null | ||
}) | ||
.join("\n")} | ||
.map(([key, itemConfig]) => { | ||
const color = | ||
itemConfig.theme?.[theme as keyof typeof itemConfig.theme] || | ||
itemConfig.color | ||
return color ? ` --color-${key}: ${color};` : null | ||
}) | ||
.join("\n")} | ||
} | ||
` | ||
) | ||
.join("\n"), | ||
}} | ||
/> | ||
) | ||
) | ||
.join("\n"), | ||
}} | ||
/> | ||
) |
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.
Pre-existing dangerouslySetInnerHTML usage flagged by static analysis.
The static analysis tool correctly identifies the use of dangerouslySetInnerHTML
at line 80. While this is pre-existing code (not introduced by this PR), it's worth noting that if config
contains unsanitized user input for color values, there could be a minor XSS risk if malicious values break out of the CSS context.
The current implementation has low risk because:
THEMES
is a const with known valuesid
is sanitized viachartId
- Colors are used in CSS custom property context
However, consider validating color values from config
to ensure they are legitimate CSS color strings if the config can contain user-controlled data.
🧰 Tools
🪛 ast-grep (0.39.6)
[warning] 80-80: Usage of dangerouslySetInnerHTML detected. This bypasses React's built-in XSS protection. Always sanitize HTML content using libraries like DOMPurify before injecting it into the DOM to prevent XSS attacks.
Context: dangerouslySetInnerHTML
Note: [CWE-79] Improper Neutralization of Input During Web Page Generation [REFERENCES]
- https://reactjs.org/docs/dom-elements.html#dangerouslysetinnerhtml
- https://cwe.mitre.org/data/definitions/79.html
(react-unsafe-html-injection)
🤖 Prompt for AI Agents
In platforms/eVoting/src/components/ui/chart.tsx around lines 80 to 100, the use
of dangerouslySetInnerHTML generates CSS from color values in config which could
allow malicious values to break out of the CSS context; validate and sanitize
the color values before injecting them: implement a simple whitelist/validation
function that only accepts known safe CSS color formats (e.g. hex
(#RGB/#RRGGBB/#RRGGBBAA), rgb()/rgba(), hsl()/hsla(), and predefined color
keywords) or normalize values via a safe mapping, replace any invalid or
unrecognized values with a safe fallback color, and ensure the generated CSS
uses only validated values so the dangerouslySetInnerHTML payload cannot be
abused.
const FormFieldContext = React.createContext<FormFieldContextValue>( | ||
{} as FormFieldContextValue | ||
{} as FormFieldContextValue | ||
) |
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.
Fix ineffective context guard in useFormField (prevents runtime error).
FormFieldContext
/FormItemContext
default to a cast {}
so if (!fieldContext)
never triggers. useFormField
then calls getFieldState(fieldContext.name, ...)
where name
can be undefined
, causing crashes if used outside providers. Make contexts nullable and guard before using them.
Apply these diffs:
-const FormFieldContext = React.createContext<FormFieldContextValue>(
- {} as FormFieldContextValue
-)
+const FormFieldContext = React.createContext<FormFieldContextValue | null>(null)
const useFormField = () => {
- const fieldContext = React.useContext(FormFieldContext)
- const itemContext = React.useContext(FormItemContext)
- const { getFieldState, formState } = useFormContext()
-
- const fieldState = getFieldState(fieldContext.name, formState)
-
- if (!fieldContext) {
- throw new Error("useFormField should be used within <FormField>")
- }
-
- const { id } = itemContext
+ const fieldContext = React.useContext(FormFieldContext)
+ const itemContext = React.useContext(FormItemContext)
+ const { getFieldState, formState } = useFormContext()
+
+ if (!fieldContext) {
+ throw new Error("useFormField should be used within <FormField>")
+ }
+ if (!itemContext) {
+ throw new Error("useFormField should be used within <FormItem>")
+ }
+
+ const fieldState = getFieldState(fieldContext.name, formState)
+
+ const { id } = itemContext
-const FormItemContext = React.createContext<FormItemContextValue>(
- {} as FormItemContextValue
-)
+const FormItemContext = React.createContext<FormItemContextValue | null>(null)
Also applies to: 45-65, 71-73
Description of change
fixes build on the following
Issue Number
closes #359
Type of change
How the change has been tested
n/a
Change checklist
Summary by CodeRabbit
New Features
Improvements
Removals
Chores