Skip to content

Conversation

@mdroidian
Copy link
Collaborator

@mdroidian mdroidian commented Sep 26, 2024

Publish dgraph nodes to https://nanopub.net/

Summary by CodeRabbit

  • New Features

    • Introduced comprehensive nanopublication (Nanopub) support with configuration panels, contributor and source management, custom templates, preview, validation, signing, and publishing workflows.
    • Added "Publish as Nanopub" as a new export destination for query results.
    • Added HTML export type alongside existing Markdown export.
    • Added a command palette entry to list and open nodes with defined contributors.
    • Enhanced discourse graph nodes with nanopub metadata and improved title rendering.
  • Improvements

    • Expanded export settings and customization options with typed configuration.
    • Added query condition translators for "has contributor" and "is published as Nanopub".
    • Improved UI handling and display of export and nanopub configurations.
    • Enhanced dynamic additions and cleanup of UI elements appended to page titles.
  • Chores

    • Updated dependencies, adding nanopub signing package.
    • Added initial Tailwind CSS configuration.
    • Extended GitHub Actions workflow to support manual triggers.

@coderabbitai
Copy link

coderabbitai bot commented Jun 9, 2025

Walkthrough

This update introduces comprehensive support for nanopublications ("nanopubs") within the discourse graph system. It adds UI components for configuring, previewing, and publishing nanopubs, integrates contributor and source management, and extends export and query capabilities. Supporting utilities, settings extraction, and type definitions are included, along with new configuration panels and command palette entries.

Changes

File(s) / Group Change Summary
package.json Added dependency: @nanopub/sign@^0.1.4
src/components/Export.tsx Added "Publish as Nanopub" export destination and handler logic.
src/components/QueryEditor.tsx Added hideQueryButton prop to control query button visibility.
src/components/SettingsDialog.tsx Added SelectDialog component for selectable modal dialogs.
src/components/nanopub/ContributorManager.tsx New: Contributor management UI for nanopubs, with roles and ORCID support.
src/components/nanopub/ExportNanopub.tsx New: Dialog for managing and publishing nanopubs from query results.
src/components/nanopub/Nanopub.tsx New: Full-featured nanopub dialog for editing, previewing, signing, and publishing.
src/components/nanopub/NanopubBodySpecification.tsx New: Query editor component for configuring nanopub body specifications.
src/components/nanopub/NanopubMainConfig.tsx New: Main config UI for managing nanopub contributors in Roam.
src/components/nanopub/NanopubNodeConfig.tsx New: Config panel for nanopub triple templates and settings.
src/components/nanopub/PreviewNanopub.tsx New: Component for previewing nanopub triples and HTML content.
src/components/nanopub/SourceManager.tsx New: Source URL manager with debounced updates and validation.
src/data/defaultNanopubTemplates.ts New: Default nanopub template and node type mappings.
src/discourseGraphsMode.ts Added nanopub config panels to node and main settings UI.
src/index.ts Integrated nanopub title buttons, contributor node command, and improved metadata handling.
src/utils/conditionToDatalog.ts Added translators for "has contributor" and "is published" query conditions.
src/utils/findDiscourseNode.ts Added cache parameter to control node lookup caching.
src/utils/getDiscourseNode.ts New: Utility for fetching a discourse node by UID, with optional caching.
src/utils/getDiscourseNodes.ts Added support for nanopub config parsing and integration into discourse nodes.
src/utils/getExportSettings.ts New: Utilities for extracting export settings from Roam config.
src/utils/getExportTypes.ts Refactored export settings, added HTML export type, improved frontmatter handling.
src/utils/handleTitleAdditions.ts New: Utility for managing dynamic heading additions and cleanup.
src/utils/types.ts Added ExportSettings type and updated export type callback signature.
tailwind.config.ts New: Basic Tailwind CSS configuration file.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant ExportDialog
    participant ExportNanopub
    participant NanopubDialog
    participant ContributorManager
    participant RoamAPI

    User->>ExportDialog: Select "Publish as Nanopub" and click Export
    ExportDialog->>ExportNanopub: Open dialog with results
    ExportNanopub->>User: Display nodes and publishing options
    User->>ExportNanopub: Configure settings, manage contributors
    ExportNanopub->>ContributorManager: Manage contributors for node
    ContributorManager->>RoamAPI: Update contributors in Roam
    User->>ExportNanopub: Click Publish
    ExportNanopub->>NanopubDialog: Open nanopub dialog for node
    NanopubDialog->>User: Show preview, signing, publishing tools
    User->>NanopubDialog: Sign and publish nanopub
    NanopubDialog->>RoamAPI: Update node with published URL
    NanopubDialog->>User: Show success or error message
Loading

Poem

🐇✨
Nanopubs now hop into view,
With triples, roles, and sources too.
Contributors join, with ORCID in tow,
Dialogs and panels in a dazzling show.
From Roam to the world, with a signature sign,
Our discourse grows richer, one node at a time!


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 132cd0f and a25dcfe.

📒 Files selected for processing (1)
  • .github/workflows/pr.yaml (1 hunks)
✅ Files skipped from review due to trivial changes (1)
  • .github/workflows/pr.yaml

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.

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@mdroidian mdroidian marked this pull request as ready for review June 9, 2025 23:12
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 20

🧹 Nitpick comments (15)
src/utils/getExportSettings.ts (1)

70-76: Consider error handling for missing configuration.

The function assumes the "roam/js/discourse-graph" page and "export" subtree exist. Consider adding error handling for missing configuration.

 export const getExportSettingsAndUids = (): ExportConfigWithUids => {
+  const pageUid = getPageUidByPageTitle("roam/js/discourse-graph");
+  if (!pageUid) {
+    throw new Error("discourse-graph configuration page not found");
+  }
+  const configTree = getBasicTreeByParentUid(pageUid);
-  const configTree = getBasicTreeByParentUid(
-    getPageUidByPageTitle("roam/js/discourse-graph")
-  );
   const exportNode = getSubTree({ tree: configTree, key: "export" });
+  if (!exportNode) {
+    throw new Error("export configuration not found");
+  }
src/components/QueryEditor.tsx (1)

901-904: Improve template literal formatting for better readability.

The className template literal is functional but could be formatted more clearly.

-            className={`
-              ${disabledMessage ? "bp3-disabled" : ""}
-              ${hideQueryButton ? "hidden" : ""}
-            `}
+            className={[
+              disabledMessage && "bp3-disabled",
+              hideQueryButton && "hidden"
+            ].filter(Boolean).join(" ")}

Alternatively, use a more readable template literal format:

-            className={`
-              ${disabledMessage ? "bp3-disabled" : ""}
-              ${hideQueryButton ? "hidden" : ""}
-            `}
+            className={`${disabledMessage ? "bp3-disabled" : ""} ${hideQueryButton ? "hidden" : ""}`.trim()}
src/utils/findDiscourseNode.ts (1)

6-6: Consider implementing the TODO suggestion.

The TODO comment suggests integrating cache management with refreshConfigTree. This could improve cache invalidation and consistency across the system.

Would you like me to help design an implementation that ties the cache lifecycle to refreshConfigTree?

src/data/defaultNanopubTemplates.ts (1)

9-11: Consider expanding source requirements if needed.

The requiresSource object currently only specifies that evidence nodes require sources. Consider whether other node types might also benefit from source requirements in certain contexts.

For example:

 export const requiresSource = {
   evidence: true,
+  claim: false, // optional: claims might sometimes need sources
 };
src/components/nanopub/SourceManager.tsx (2)

21-21: Improve type safety for nanopubProps.

The type assertion as NanopubPage could be unsafe if the nanopub property doesn't exist or has an unexpected structure.

Consider adding a type guard or default value:

-  const nanopubProps = props["nanopub"] as NanopubPage;
+  const nanopubProps = (props["nanopub"] as NanopubPage) || { contributors: [] };

41-43: Potential infinite loop with useEffect dependency.

The updateSourceProps function is included in the dependency array, which could cause unnecessary re-renders since it's recreated whenever its dependencies change.

Remove updateSourceProps from the dependency array since source changes will trigger the effect:

  useEffect(() => {
    updateSourceProps(source);
-  }, [source, updateSourceProps]);
+  }, [source]);

Or better yet, move the logic directly into the useEffect to eliminate the need for useCallback.

src/components/Export.tsx (1)

821-831: Consider moving the helper function closer to its usage.

The handleNanopubExport function is defined far from where it's used (line 659), which affects code readability.

Consider moving the function definition closer to its usage or to the top of the component for better organization.

src/components/nanopub/NanopubBodySpecification.tsx (1)

94-96: Potential infinite loop in useEffect dependencies.

The dependency array includes initialQueryArgs which is a memoized object that could cause unnecessary re-renders.

Consider extracting only the specific properties needed:

  useEffect(() => {
    if (!showQuery && !hidden) createInitialQueryblocks();
-  }, [customBodyDefinitionUid, initialQueryArgs, showQuery, hidden]);
+  }, [customBodyDefinitionUid, initialQueryArgs.conditionsNodesUid, showQuery, hidden]);

Or better yet, use a more specific dependency that indicates when the query structure changes.

src/index.ts (2)

215-215: Remove redundant double-negation.

The !! operator is unnecessary here as the condition will already be coerced to a boolean.

-    if (!!extensionAPI.settings.get("show-page-metadata")) {
+    if (extensionAPI.settings.get("show-page-metadata")) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 215-215: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)


881-886: Consider removing or making the toast notification more specific.

This generic "Successfully loaded" toast seems unrelated to the nanopub feature. If it's intended for nanopub loading, make the message more specific. Otherwise, consider moving it to a separate PR.

src/components/nanopub/NanopubMainConfig.tsx (1)

51-51: Use optional chaining for cleaner code.

-        if (title && title.startsWith("Anonymous") && email) {
+        if (title?.startsWith("Anonymous") && email) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 51-51: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/nanopub/PreviewNanopub.tsx (1)

131-131: Pass children as JSX elements instead of props.

-                      children={discourseNode?.text || ""}
+                    >{discourseNode?.text || ""}</Text>
-                      children={triple.predicate}
+                    >{triple.predicate}</Text>

Also applies to: 136-136

🧰 Tools
🪛 Biome (1.9.4)

[error] 131-131: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

src/components/nanopub/NanopubNodeConfig.tsx (2)

531-531: Remove redundant double-negation.

-            if (!!triples.length) {
+            if (triples.length) {
🧰 Tools
🪛 Biome (1.9.4)

[error] 531-531: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)


217-720: Consider refactoring for better maintainability.

This component is quite complex with many state variables and nested logic. Consider:

  1. Using useReducer instead of multiple useState calls for related state
  2. Extracting the triple type sections into separate components
  3. Creating custom hooks for triple management logic
🧰 Tools
🪛 Biome (1.9.4)

[error] 531-531: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

src/components/nanopub/ExportNanopub.tsx (1)

338-343: Missing publish implementation.

The publish functionality is not yet implemented. This is a critical feature for the nanopub export dialog.

Would you like me to help implement the batch publishing logic or create an issue to track this TODO?

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c71de5d and 132cd0f.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (24)
  • package.json (1 hunks)
  • src/components/Export.tsx (5 hunks)
  • src/components/QueryEditor.tsx (3 hunks)
  • src/components/SettingsDialog.tsx (1 hunks)
  • src/components/nanopub/ContributorManager.tsx (1 hunks)
  • src/components/nanopub/ExportNanopub.tsx (1 hunks)
  • src/components/nanopub/Nanopub.tsx (1 hunks)
  • src/components/nanopub/NanopubBodySpecification.tsx (1 hunks)
  • src/components/nanopub/NanopubMainConfig.tsx (1 hunks)
  • src/components/nanopub/NanopubNodeConfig.tsx (1 hunks)
  • src/components/nanopub/PreviewNanopub.tsx (1 hunks)
  • src/components/nanopub/SourceManager.tsx (1 hunks)
  • src/data/defaultNanopubTemplates.ts (1 hunks)
  • src/discourseGraphsMode.ts (3 hunks)
  • src/index.ts (8 hunks)
  • src/utils/conditionToDatalog.ts (1 hunks)
  • src/utils/findDiscourseNode.ts (1 hunks)
  • src/utils/getDiscourseNode.ts (1 hunks)
  • src/utils/getDiscourseNodes.ts (6 hunks)
  • src/utils/getExportSettings.ts (1 hunks)
  • src/utils/getExportTypes.ts (8 hunks)
  • src/utils/handleTitleAdditions.ts (1 hunks)
  • src/utils/types.ts (1 hunks)
  • tailwind.config.ts (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (10)
src/components/Export.tsx (1)
src/utils/types.ts (1)
  • Result (55-59)
src/data/defaultNanopubTemplates.ts (1)
src/utils/getDiscourseNodes.ts (1)
  • NanopubConfig (85-93)
src/components/nanopub/NanopubBodySpecification.tsx (1)
src/utils/parseQuery.ts (2)
  • DEFAULT_RETURN_NODE (56-56)
  • parseQuery (58-118)
src/index.ts (4)
src/utils/handleTitleAdditions.ts (2)
  • handleTitleAdditions (6-47)
  • removeTitleAdditions (49-57)
src/components/nanopub/Nanopub.tsx (2)
  • NanoPubTitleButtons (70-90)
  • NanopubPage (54-58)
src/utils/getBlockProps.ts (1)
  • normalizeProps (9-25)
src/components/SettingsDialog.tsx (1)
  • renderSelectDialog (84-85)
src/components/nanopub/SourceManager.tsx (1)
src/components/nanopub/Nanopub.tsx (1)
  • NanopubPage (54-58)
src/components/nanopub/ExportNanopub.tsx (4)
src/utils/getDiscourseNodes.ts (1)
  • DiscourseNode (15-28)
src/components/nanopub/Nanopub.tsx (3)
  • NanopubPage (54-58)
  • Contributor (59-64)
  • render (920-921)
src/utils/types.ts (1)
  • Result (55-59)
src/components/Export.tsx (1)
  • render (860-861)
src/components/nanopub/PreviewNanopub.tsx (4)
src/components/nanopub/Nanopub.tsx (3)
  • Contributor (59-64)
  • updateObjectPlaceholders (148-188)
  • NanopubTriple (92-118)
src/components/nanopub/NanopubNodeConfig.tsx (1)
  • NanopubTripleType (77-82)
src/utils/getDiscourseNodes.ts (1)
  • DiscourseNode (15-28)
src/components/nanopub/ContributorManager.tsx (2)
  • creditRoles (21-92)
  • getCurrentUserOrcid (112-117)
src/components/nanopub/ContributorManager.tsx (2)
src/components/nanopub/NanopubMainConfig.tsx (1)
  • PossibleContributor (17-21)
src/components/nanopub/Nanopub.tsx (2)
  • Contributor (59-64)
  • NanopubPage (54-58)
src/components/nanopub/NanopubNodeConfig.tsx (2)
src/utils/getDiscourseNodes.ts (1)
  • DiscourseNode (15-28)
src/data/defaultNanopubTemplates.ts (3)
  • defaultNanopubTemplate (12-57)
  • nodeTypes (3-8)
  • requiresSource (9-11)
src/utils/getDiscourseNodes.ts (1)
src/components/nanopub/NanopubNodeConfig.tsx (3)
  • NanopubTripleType (77-82)
  • PredicateKey (73-73)
  • TripleType (75-75)
🪛 Biome (1.9.4)
src/index.ts

[error] 215-215: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

src/components/nanopub/ExportNanopub.tsx

[error] 291-291: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

src/components/nanopub/NanopubMainConfig.tsx

[error] 51-51: Change to an optional chain.

Unsafe fix: Change to an optional chain.

(lint/complexity/useOptionalChain)

src/components/nanopub/PreviewNanopub.tsx

[error] 107-107: Avoid passing content using the dangerouslySetInnerHTML prop.

Setting content using code can expose users to cross-site scripting (XSS) attacks

(lint/security/noDangerouslySetInnerHtml)


[error] 131-131: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 136-136: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

src/components/nanopub/NanopubNodeConfig.tsx

[error] 531-531: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

src/components/nanopub/Nanopub.tsx

[error] 105-105: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 110-110: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 115-115: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🔇 Additional comments (26)
src/components/SettingsDialog.tsx (3)

47-54: Excellent accessibility implementation.

The visually hidden focus button is a great accessibility pattern that allows proper keyboard navigation when the dialog is opened via command palette. This ensures screen readers and keyboard users can navigate the dialog properly.


66-69: Good UX pattern: auto-close on selection.

Automatically closing the dialog after item selection provides a smooth user experience and prevents the need for manual dialog dismissal.


73-77: Robust fallback for empty states.

The fallback message handling for empty items list with optional error message provides good user feedback for various scenarios.

src/utils/getExportSettings.ts (1)

83-85: Good default value handling.

The default value of 64 for max filename length is sensible and prevents issues with undefined values.

src/utils/getDiscourseNode.ts (1)

4-16: Clean and well-structured utility function.

The function provides a simple, focused interface for retrieving discourse nodes with good parameter defaults and proper null handling. The cache parameter provides flexibility for different use cases.

src/components/QueryEditor.tsx (1)

440-440: LGTM! Prop added correctly.

The optional hideQueryButton prop is properly typed and provides clean UI control for hiding the query button when needed.

src/utils/findDiscourseNode.ts (1)

8-16: Enhanced cache control implemented correctly.

The addition of the optional cache parameter provides explicit control over caching behavior while maintaining backward compatibility through the default value. The logic correctly bypasses cache when cache is false and uses cached results when true.

src/utils/types.ts (2)

33-42: Well-designed export settings type.

The ExportSettings type provides comprehensive configuration options for export functionality. All properties are appropriately typed with meaningful names that clearly indicate their purpose.


51-51: Optional settings parameter maintains backward compatibility.

The addition of the optional settings parameter to the ExportTypes callback signature is well-implemented, maintaining backward compatibility while enabling enhanced export configuration.

src/discourseGraphsMode.ts (1)

60-61: Import statements are correctly added.

The nanopub-related component imports are properly added and will support the new configuration panels.

src/data/defaultNanopubTemplates.ts (2)

3-8: Well-defined node type mappings with standard URIs.

The nodeTypes mapping uses URIs from what appears to be a legitimate knowledge representation vocabulary (w3id.org/kpxl), providing standard semantic types for different discourse nodes.


12-57: Comprehensive and well-structured default nanopub template.

The defaultNanopubTemplate provides a complete default configuration with:

  • Appropriate triple categorization (assertion, provenance, publication info)
  • Intuitive placeholder syntax for dynamic content
  • Reasonable default settings for contributors and source requirements

The template structure aligns well with the NanopubConfig interface and provides a solid foundation for nanopublication generation.

src/components/Export.tsx (2)

531-531: Verify the export type selector disable condition.

The condition activeExportType === "nanopub" disables the export type selector when nanopub is selected, but this might prevent users from changing the export type once nanopub is selected.

Please confirm this is the intended behavior. If users should be able to change away from nanopub, consider using activeExportDestination === "nanopub" instead.


654-661: LGTM! Clean nanopub export integration.

The nanopub export handling is well-integrated with the existing export flow. The early return pattern prevents the normal export logic from executing when nanopub is selected.

src/utils/conditionToDatalog.ts (2)

949-1022: Excellent datalog pattern implementation for contributor queries.

The "has contributor" translator correctly:

  • Resolves {current user} to the actual display name
  • Uses proper datalog patterns to navigate the nanopub data structure
  • Provides appropriate target options from user display names
  • Handles variable bindings correctly

1023-1065: Clean implementation of publication status queries.

The "is published" translator is well-designed:

  • Uses case-insensitive matching for "as nanopub"
  • Returns empty array for unsupported targets (fail-safe behavior)
  • Follows consistent datalog pattern structure
  • Provides clear user guidance with placeholder text
src/index.ts (3)

259-263: LGTM!

The nanopub title button integration is well implemented with proper conditional rendering.


610-635: Well-implemented query function.

The getNanopubPages function correctly queries and transforms nanopub pages with contributors.


906-906: Good cleanup practice.

Properly cleaning up title additions on unload prevents memory leaks and DOM pollution.

src/utils/getDiscourseNodes.ts (2)

85-142: Well-structured nanopub configuration parsing.

The NanopubConfig type and parseNanopub function are well implemented with clear structure and proper data extraction from the Roam tree.


167-172: Consistent nanopub configuration integration.

Good job ensuring both user-configured nodes and relation-based nodes have nanopub configurations.

Also applies to: 199-207

src/components/nanopub/PreviewNanopub.tsx (1)

32-70: Well-structured triple grouping logic.

The groupTriplesByType function properly categorizes triples and adds source/contributor information as needed.

src/utils/getExportTypes.ts (2)

277-279: LGTM! Good defensive programming.

The guard clause properly handles both null and empty array cases, preventing potential errors downstream.


873-875: Clean implementation of highlight syntax conversion.

The regex pattern correctly handles the conversion from Roam's ^^text^^ syntax to HTML <mark> tags with non-greedy matching.

src/components/nanopub/Nanopub.tsx (1)

619-646: Excellent error handling and reporting.

The error handling is comprehensive with:

  • User-friendly error messages
  • Detailed logging for debugging
  • Error reporting to external API for monitoring
  • Proper state management after errors
src/components/nanopub/ContributorManager.tsx (1)

145-164: Well-implemented debounced updates.

The debounce logic is properly implemented with:

  • Correct use of useRef to persist timer across renders
  • Proper cleanup with clearTimeout
  • Reasonable 1-second delay for API updates

"widgets"
],
"dependencies": {
"@nanopub/sign": "^0.1.4",
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify the nanopub package version and security.

The new dependency @nanopub/sign supports the nanopub functionality. Please ensure this version is current and secure.


🌐 Web query:

What is the latest version of @nanopub/sign npm package and are there any known security vulnerabilities?

💡 Result:

The latest version of the @nanopub/sign npm package is 0.1.3, released on March 31, 2024. (libraries.io)

As of now, there are no known security vulnerabilities associated with this package. To ensure your project remains secure, it's advisable to regularly update your dependencies and monitor for any new vulnerabilities.

You can use the npm audit command to scan your project for known vulnerabilities and the npm audit fix command to automatically update packages to their latest secure versions. (geeksforgeeks.org)

Additionally, consider using automated tools like Snyk or WhiteSource Bolt to continuously monitor your project's dependencies for security issues. (geeksforgeeks.org)

By following these practices, you can help maintain the security and integrity of your project.

Citations:


Update @nanopub/sign to a valid published version

It looks like you’ve added

"@nanopub/sign": "^0.1.4"

but the latest published release is 0.1.3 (Mar 31, 2024). Please update to:

- "@nanopub/sign": "^0.1.4",
+ "@nanopub/sign": "^0.1.3",

There are currently no known security vulnerabilities for this package. To keep dependencies safe, consider running npm audit (and npm audit fix) or integrating tools like Snyk or WhiteSource Bolt for continuous monitoring.

  • File: package.json
  • Line: 29
🤖 Prompt for AI Agents
In package.json at line 29, the dependency "@nanopub/sign" is set to version
"^0.1.4" which is not a published version. Update this version to the latest
valid published release "0.1.3" to ensure the dependency is correctly resolved
and avoid potential installation errors. Additionally, consider running `npm
audit` and integrating security monitoring tools to maintain dependency
security.

Comment on lines +55 to +61
export const getUidAndBooleanSetting = (props: Props): BooleanSetting => {
const node = props.tree.find((node) => node.text === props.text);
return {
uid: node?.uid,
value: !!node?.uid,
};
};
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Fix boolean setting logic.

The boolean setting logic is incorrect. It returns true whenever a UID exists, regardless of the actual boolean value. This will always return true for any configured setting.

 export const getUidAndBooleanSetting = (props: Props): BooleanSetting => {
   const node = props.tree.find((node) => node.text === props.text);
+  const childText = node?.children[0]?.text?.toLowerCase();
+  const boolValue = childText === "true" || childText === "yes" || !!node?.uid && !childText;
   return {
     uid: node?.uid,
-    value: !!node?.uid,
+    value: boolValue,
   };
 };
📝 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.

Suggested change
export const getUidAndBooleanSetting = (props: Props): BooleanSetting => {
const node = props.tree.find((node) => node.text === props.text);
return {
uid: node?.uid,
value: !!node?.uid,
};
};
export const getUidAndBooleanSetting = (props: Props): BooleanSetting => {
const node = props.tree.find((node) => node.text === props.text);
const childText = node?.children[0]?.text?.toLowerCase();
const boolValue =
childText === "true" ||
childText === "yes" ||
(!!node?.uid && !childText);
return {
uid: node?.uid,
value: boolValue,
};
};
🤖 Prompt for AI Agents
In src/utils/getExportSettings.ts around lines 55 to 61, the boolean setting
logic incorrectly returns true whenever a UID exists, ignoring the actual
boolean value. Update the function to retrieve and return the correct boolean
value associated with the setting instead of coercing the UID presence to a
boolean. Ensure the returned value reflects the intended boolean setting from
the node's data.

@@ -0,0 +1,8 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [],
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Configure content paths for CSS purging.

The empty content array will prevent Tailwind from purging unused styles in production, resulting in a much larger CSS bundle. Add paths to your source files that use Tailwind classes.

 module.exports = {
-  content: [],
+  content: [
+    "./src/**/*.{js,ts,jsx,tsx}",
+    "./build/**/*.html"
+  ],
   theme: {
     extend: {},
   },
   plugins: [],
 };
📝 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.

Suggested change
content: [],
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./build/**/*.html"
],
theme: {
extend: {},
},
plugins: [],
};
🤖 Prompt for AI Agents
In tailwind.config.ts at line 3, the content array is empty, which disables
Tailwind's CSS purging and leads to larger CSS bundles. Fix this by adding the
appropriate file paths (e.g., all your source files like .tsx, .js, .html) that
contain Tailwind classes to the content array so Tailwind can properly purge
unused styles in production.

Comment on lines +558 to +571
// @ts-ignore
{
title: "Nanopub",
description: "Nanopub settings",
Panel: CustomPanel,
options: {
component: (props) =>
React.createElement(NanopubMainConfig, {
...props,
parentUid: pageUid,
onloadArgs: args,
}),
},
} as Field<CustomField>,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address TypeScript issues instead of using @ts-ignore.

Similar to the node-specific panel, the main nanopub configuration panel should have proper TypeScript support rather than suppression.

Apply the same TypeScript improvement as suggested for the node-specific panel above.

🤖 Prompt for AI Agents
In src/discourseGraphsMode.ts around lines 558 to 571, the use of @ts-ignore to
suppress TypeScript errors for the Nanopub configuration panel should be
removed. Instead, properly type the object by ensuring it conforms to the
Field<CustomField> interface without ignoring errors. This involves adjusting
the types of the properties, especially the component function, to match
expected types and importing or defining any missing types so that TypeScript
validation passes cleanly.

Comment on lines +254 to +268
// @ts-ignore
{
title: "Nanopub",
description:
"Configure the Nanopub triple template for this node type",
Panel: CustomPanel,
options: {
component: (props) =>
React.createElement(NanopubConfigPanel, {
...props,
node,
onloadArgs,
}),
},
} as Field<CustomField>,
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address TypeScript issues instead of using @ts-ignore.

The nanopub configuration panel is well-integrated, but the @ts-ignore annotation suggests TypeScript compatibility issues that should be resolved.

Consider updating the type definitions to properly support the CustomField configuration or cast the object to the appropriate type instead of suppressing TypeScript checks:

-          // @ts-ignore
           {
             title: "Nanopub",
             description:
               "Configure the Nanopub triple template for this node type",
             Panel: CustomPanel,
             options: {
               component: (props) =>
                 React.createElement(NanopubConfigPanel, {
                   ...props,
                   node,
                   onloadArgs,
                 }),
             },
-          } as Field<CustomField>,
+          } as Field<CustomField>,

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/discourseGraphsMode.ts around lines 254 to 268, the use of @ts-ignore to
suppress TypeScript errors on the Nanopub configuration panel indicates type
incompatibility. To fix this, update or extend the type definitions to correctly
represent the CustomField configuration object, or explicitly cast the object to
the correct type instead of ignoring the error. This ensures proper type
checking and compatibility without suppressing TypeScript warnings.

Comment on lines +873 to +875
const highlightText = (content: string): string => {
return content.replace(/\^\^([\s\S]+?)\^\^/g, "<mark>$1</mark>");
};
Copy link

Choose a reason for hiding this comment

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

💡 Verification agent

🧩 Analysis chain

Verify XSS protection when converting markdown to HTML.

While the marked library typically handles XSS protection, ensure that user-generated content in markdown doesn't contain malicious scripts that could execute in the HTML output.


🌐 Web query:

Does the marked library automatically sanitize HTML to prevent XSS attacks? What are the best practices for using marked.js securely?

💡 Result:

The popular JavaScript library marked.js is a markdown parser and compiler, but by default, marked.js does not automatically sanitize HTML embedded in markdown to prevent XSS (Cross-Site Scripting) attacks. This means if you pass untrusted user input through marked.js, and that input contains HTML tags with malicious scripts, those scripts could be executed in the browser.

Does marked.js automatically sanitize HTML?

  • No, marked.js itself does not provide HTML sanitization.
  • It parses markdown and can allow embedded HTML as is.
  • The library leaves sanitization responsibility to the developer.

Best practices for using marked.js securely

  1. Sanitize Input Before or After Parsing
    Use a dedicated HTML sanitizer library such as:

    • DOMPurify (highly recommended and widely used)
    • sanitize-html
    • xss

    These libraries clean the HTML output generated by marked.js or sanitize the input before processing it.

  2. Disable HTML Parsing in marked.js (optional)
    You can configure marked.js to ignore HTML input entirely:

    marked.setOptions({
      sanitize: false,      // Deprecated, better to use external sanitizer
      mangle: false,        // To prevent email address mangling, optional
      headerIds: false,
      smartLists: true,
      smartypants: false,
      breaks: true,
      gfm: true,
      // Disable raw HTML parsing:
      renderer: {
        html: () => ''      // Override HTML rendering to output empty strings
      }
    });

    Or simply use:

    marked.setOptions({
      renderer: new marked.Renderer()
    });
    marked.use({ 
      renderer: {
        html: () => ''
      }
    });

    This means any raw HTML in the markdown input will be ignored, greatly reducing the attack surface.

  3. Use Trusted Sources Only
    If you control the markdown content or trust the source, sanitization may be less critical, but best practice is always to sanitize.

  4. Keep Libraries Updated
    Ensure you use up-to-date versions of marked.js and any sanitizer libraries to benefit from security patches.

Summary

  • Marked.js does not automatically sanitize input.
  • Always sanitize the HTML output with a dedicated sanitizer like DOMPurify.
  • Consider disabling HTML parsing if raw HTML is not needed.
  • Keep dependencies updated.

If you want, I can also help you with example code snippets for securely using marked.js with DOMPurify. Would you like that?


Sanitize HTML output from marked to prevent XSS

marked.js does not strip or escape raw HTML by default, so untrusted markdown can introduce malicious scripts. You should integrate a sanitizer or disable HTML parsing in marked:

• File: src/utils/getExportTypes.ts
– After you call marked(markdownContent), wrap its output in a sanitizer (e.g., DOMPurify) before inserting into your HTML template.
– Or configure marked’s renderer to ignore raw HTML if you don’t need it.

Suggested snippet:

import { marked } from 'marked';
import DOMPurify from 'dompurify';

const rawHtml = marked(markdownContent);
const safeHtml = DOMPurify.sanitize(rawHtml);
// use `safeHtml` in your export instead of rawHtml
🤖 Prompt for AI Agents
In src/utils/getExportTypes.ts around lines 873 to 875, the markdown-to-HTML
conversion using marked.js does not sanitize the output, risking XSS attacks
from untrusted input. To fix this, after generating HTML with
marked(markdownContent), pass the result through a sanitizer like DOMPurify by
importing it and calling DOMPurify.sanitize on the raw HTML before using it.
Alternatively, configure marked's renderer to disable raw HTML parsing if you
don't need embedded HTML. This ensures the exported HTML is safe from malicious
scripts.

<td style={{ verticalAlign: "middle" }}>
<Tooltip
content={
!!nanopubProps?.published
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Remove redundant double-negation.

The double-negation is unnecessary since the value will be coerced to boolean in the ternary condition.

-                              ? "Already Published"
-                              : !nanopubSettings?.enabled
+                              ? "Already Published"
+                              : !nanopubSettings?.enabled

Actually, looking at the full context:

                            !!nanopubProps?.published
                              ? "Already Published"
-                              : !nanopubSettings?.enabled
+                              : !nanopubSettings?.enabled

The issue is with !!nanopubProps?.published on line 291. Change to:

-                            !!nanopubProps?.published
+                            nanopubProps?.published
📝 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.

Suggested change
!!nanopubProps?.published
nanopubProps?.published
? "Already Published"
: !nanopubSettings?.enabled
🧰 Tools
🪛 Biome (1.9.4)

[error] 291-291: Avoid redundant double-negation.

It is not necessary to use double-negation when a value will already be coerced to a boolean.
Unsafe fix: Remove redundant double-negation

(lint/complexity/noExtraBooleanCast)

🤖 Prompt for AI Agents
In src/components/nanopub/ExportNanopub.tsx at line 291, remove the redundant
double-negation (!!) before nanopubProps?.published. Replace
`!!nanopubProps?.published` with just `nanopubProps?.published` to rely on the
natural boolean coercion in the ternary condition.

Comment on lines +100 to +117
}) => (
<div className="grid grid-cols-12 gap-4 border-0 border-b sm:border-b-0 py-2">
<Text
className="col-span-12 sm:col-span-2 truncate"
title={subject}
children={subject}
/>
<Text
className="col-span-12 sm:col-span-2 truncate"
title={predicate}
children={predicate}
/>
<Text
className="col-span-12 sm:col-span-8 truncate"
title={object}
children={object}
/>
</div>
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Use JSX children instead of children prop.

React's canonical way to pass children is through JSX elements, not as a prop.

-    <Text
-      className="col-span-12 sm:col-span-2 truncate"
-      title={subject}
-      children={subject}
-    />
-    <Text
-      className="col-span-12 sm:col-span-2 truncate"
-      title={predicate}
-      children={predicate}
-    />
-    <Text
-      className="col-span-12 sm:col-span-8 truncate"
-      title={object}
-      children={object}
-    />
+    <Text
+      className="col-span-12 sm:col-span-2 truncate"
+      title={subject}
+    >
+      {subject}
+    </Text>
+    <Text
+      className="col-span-12 sm:col-span-2 truncate"
+      title={predicate}
+    >
+      {predicate}
+    </Text>
+    <Text
+      className="col-span-12 sm:col-span-8 truncate"
+      title={object}
+    >
+      {object}
+    </Text>
📝 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.

Suggested change
}) => (
<div className="grid grid-cols-12 gap-4 border-0 border-b sm:border-b-0 py-2">
<Text
className="col-span-12 sm:col-span-2 truncate"
title={subject}
children={subject}
/>
<Text
className="col-span-12 sm:col-span-2 truncate"
title={predicate}
children={predicate}
/>
<Text
className="col-span-12 sm:col-span-8 truncate"
title={object}
children={object}
/>
</div>
}) => (
<div className="grid grid-cols-12 gap-4 border-0 border-b sm:border-b-0 py-2">
<Text
className="col-span-12 sm:col-span-2 truncate"
title={subject}
>
{subject}
</Text>
<Text
className="col-span-12 sm:col-span-2 truncate"
title={predicate}
>
{predicate}
</Text>
<Text
className="col-span-12 sm:col-span-8 truncate"
title={object}
>
{object}
</Text>
</div>
)
🧰 Tools
🪛 Biome (1.9.4)

[error] 105-105: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 110-110: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)


[error] 115-115: Avoid passing children using a prop

The canonical way to pass children in React is to use JSX elements

(lint/correctness/noChildrenProp)

🤖 Prompt for AI Agents
In src/components/nanopub/Nanopub.tsx between lines 100 and 117, replace the
usage of the children prop in the Text components with JSX children syntax.
Instead of passing children as a prop, nest the content between the opening and
closing Text tags to follow React's standard practice for passing children.

Comment on lines +66 to +68
// TEMP PRIVATE KEY
const PRIVATE_KEY =
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc=";
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue

Critical: Remove hardcoded private key.

Hardcoded private keys are a severe security vulnerability. This key should be stored securely and retrieved at runtime.

Consider:

  1. Store the key in secure environment variables
  2. Use a key management service
  3. Generate keys per user/session
  4. At minimum, move to a configuration file that's not committed to version control
-// TEMP PRIVATE KEY
-const PRIVATE_KEY =
-  "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc=";
+// TODO: Implement secure key management
+const getPrivateKey = () => {
+  // Retrieve from secure storage
+  throw new Error("Private key management not implemented");
+};
📝 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.

Suggested change
// TEMP PRIVATE KEY
const PRIVATE_KEY =
"MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCjY1gsFxmak6SOCouJPuEzHNForkqFhgfHE3aAIAx+Y5q6UDEDM9Q0EksheNffJB4iPqsAfiFpY0ARQY92K5r8P4+a78eu9reYrb2WxZb1qPJmvR7XZ6sN1oHD7dd/EyQoJmQsmOKdrqaLRbzR7tZrf52yvKkwNWXcIVhW8uxe7iUgxiojZpW9srKoK/qFRpaUZSKn7Z/zgtDH9FJkYbBsGPDMqp78Kzt+sJb+U2W+wCSSy34jIUxx6QRbzvn6uexc/emFw/1DU5y7zBudhgC7mVk8vX1gUNKyjZBzlOmRcretrANgffqs5fx/TMHN1xtkA/H1u1IKBfKoyk/xThMLAgMBAAECggEAECuG0GZA3HF8OaqFgMG+W+agOvH04h4Pqv4cHjYNxnxpFcNV9nEssTKWSOvCwYy7hrwZBGV3PQzbjFmmrxVFs20+8yCD7KbyKKQZPVC0zf84bj6NTNgvr6DpGtDxINxuGaMjCt7enqhoRyRRuZ0fj2gD3Wqae/Ds8cpDCefkyMg0TvauHSUj244vGq5nt93txUv1Sa+/8tWZ77Dm0s5a3wUYB2IeAMl5WrO2GMvgzwH+zT+4kvNWg5S0Ze4KE+dG3lSIYZjo99h14LcQS9eALC/VBcAJ6pRXaCTT/TULtcLNeOpoc9Fu25f0yTsDt6Ga5ApliYkb7rDhV+OFrw1sYQKBgQDCE9so+dPg7qbp0cV+lbb7rrV43m5s9Klq0riS7u8m71oTwhmvm6gSLfjzqb8GLrmflCK4lKPDSTdwyvd+2SSmOXySw94zr1Pvc7sHdmMRyA7mH3m+zSOOgyCTTKyhDRCNcRIkysoL+DecDhNo4Fumf71tsqDYogfxpAQhn0re8wKBgQDXhMmmT2oXiMnYHhi2k7CJe3HUqkZgmW4W44SWqKHp0V6sjcHm0N0RT5Hz1BFFUd5Y0ZB3JLcah19myD1kKYCj7xz6oVLb8O7LeAZNlb0FsrtD7NU+Hciywo8qESiA7UYDkU6+hsmxaI01DsttMIdG4lSBbEjA7t4IQC5lyr7xiQKBgQCN87YGJ40Y5ZXCSgOZDepz9hqX2KGOIfnUv2HvXsIfiUwqTXs6HbD18xg3KL4myIBOvywSM+4ABYp+foY+Cpcq2btLIeZhiWjsKIrw71+Q/vIe0YDb1PGf6DsoYhmWBpdHzR9HN+hGjvwlsYny2L9Qbfhgxxmsuf7zeFLpQLijjwKBgH7TD28k8IOk5VKec2CNjKd600OYaA3UfCpP/OhDl/RmVtYoHWDcrBrRvkvEEd2/DZ8qw165Zl7gJs3vK+FTYvYVcfIzGPWA1KU7nkntwewmf3i7V8lT8ZTwVRsmObWU60ySJ8qKuwoBQodki2VX12NpMN1wgWe3qUUlr6gLJU4xAoGAet6nD3QKwk6TTmcGVfSWOzvpaDEzGkXjCLaxLKh9GreM/OE+h5aN2gUoFeQapG5rUwI/7Qq0xiLbRXw+OmfAoV2XKv7iI8DjdIh0F06mlEAwQ/B0CpbqkuuxphIbchtdcz/5ra233r3BMNIqBl3VDDVoJlgHPg9msOTRy13lFqc=";
// TODO: Implement secure key management
const getPrivateKey = () => {
// Retrieve from secure storage
throw new Error("Private key management not implemented");
};
🤖 Prompt for AI Agents
In src/components/nanopub/Nanopub.tsx around lines 66 to 68, the private key is
hardcoded directly in the source code, which is a critical security risk. Remove
the hardcoded private key and instead load it securely at runtime from
environment variables or a secure key management service. If environment
variables are used, update the code to read the key from process.env or a
similar secure source, and ensure the key is not committed to version control by
adding it to .gitignore or equivalent.

Comment on lines +232 to +234
// this is susceptible to duplicate names
const newOrcid =
possibleContributors.find((c) => c.name === newName)?.orcid || "";
Copy link

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Address the duplicate name vulnerability.

The comment indicates a known issue with duplicate names. This could cause incorrect ORCID assignment if multiple contributors have the same name.

Consider using a unique identifier (like uid) instead of name for contributor lookup:

-            // this is susceptible to duplicate names
-            const newOrcid =
-              possibleContributors.find((c) => c.name === newName)?.orcid || "";
+            // Use the selected contributor's data directly from the menu selection
+            // This would require passing the full contributor object from MenuItemSelect
+            const selectedContributor = possibleContributors.find((c) => c.name === newName);
+            const newOrcid = selectedContributor?.orcid || "";

Alternatively, modify the MenuItemSelect to work with the full contributor objects instead of just names.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In src/components/nanopub/ContributorManager.tsx around lines 232 to 234, the
code uses contributor names to find ORCID, which risks incorrect matches due to
duplicate names. To fix this, update the lookup to use a unique identifier such
as uid instead of name when searching possibleContributors. Alternatively,
refactor the MenuItemSelect component to handle full contributor objects rather
than just names, ensuring accurate ORCID assignment without relying on
potentially duplicated names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants