Commit graph

13 commits

Author SHA1 Message Date
Danny Avila
e807c63d5d
🔐 fix: Gate Shared Startup Config By Link Access (#13897)
* fix: gate shared startup config by link access

* fix: satisfy shared config CI checks

* fix: align shared config client types

* fix: reject expired shared link access
2026-06-23 08:28:37 -04:00
Danny Avila
e515063ffe
🔗 feat: Snapshot Files for Shared-Link Attachments (#13740)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
* 🔗 feat: Snapshot Files for Shared-Link Attachments

Shared-link viewers could read a shared conversation snapshot but not its
attachments: file preview/download still went through the owner-scoped file
ACL (the /api/files router sits behind requireJwtAuth + owner/agent checks),
so anonymous viewers got 401s and authenticated non-owners got 403s — the
repeated `[fileAccess] denied` warnings seen for the preview poller.

Capture an immutable per-share file snapshot (embedded on the SharedLink
document, referencing the original stored object — no byte copy) at share
create/update, and serve those files through new share-scoped routes
authorized by the existing shared-link view permission (public/ACL) plus
snapshot membership, never the owner's live file ACL.

- data-schemas: fileSnapshots on the share doc; capture in create/update;
  read-time rewrite of filepath/preview to /api/share/:id/files/:fileId;
  getSharedLinkFile + lazy backfillSharedLinkFiles for legacy links
- api: GET /api/share/:shareId/files/:file_id[/download|/preview]; route
  context added to fileAccess denial logs
- packages/api: isFileSnapshotEnabled resolver (env + yaml)
- data-provider: interface.sharedLinks.snapshotFiles (default on) + client
  endpoints/services
- client: ShareContext.shareId wired to Image, preview hook, and downloads
- config: SHARED_LINKS_SNAPSHOT_FILES env override (default on)

* 🔒 fix: Address Codex review on shared-link file snapshots

Triage of the Codex review on PR #13740 (2 P1, 7 P2 — all valid):

- P1 (cross-user access): scope the snapshot lookup to the sharing user's own
  files so a message referencing another user's file_id can't widen access.
- P1 (stored XSS): the inline share-file route now serves only safe preview
  types inline (raster images/pdf); everything else is forced to attachment with
  X-Content-Type-Options: nosniff.
- Stream shared downloads by default; redirect to a signed URL only on
  ?direct=true (blob/XHR callers work without bucket CORS).
- Read preview status live from the file record (always current for deferred
  previews) and stop embedding extracted text in the share doc (16MB-limit risk).
- Only lazily backfill when the fileSnapshots field is absent (legacy), not on
  every snapshot miss.
- Backfill legacy shares before rewriting message URLs, and gate URL rewriting
  to public shares so non-public (ACL) shares keep prior behavior (img/anchor
  can't carry the bearer token).
- Frontend: only route a download through the share path when the file was
  actually snapshotted (rewritten href / filepath), else fall back.

* 🔑 feat: Authorize shared-link files for non-public shares via cookie

Extends shared-link file access to non-public (ACL) shares (Codex finding 5).
`<img>`/anchor requests can't carry the bearer access token, so non-public
shares previously 401'd on file loads. Add an optional cookie-auth fallback on
the share file routes that resolves the viewer from the `refreshToken` cookie
(or signed `openid_user_id` cookie) — the same mechanism secure image links use
(validateImageRequest) — then let canAccessSharedLink run the viewer's ACL check.

- new middleware optionalShareFileAuth (+ unit spec); applied to the three
  share file routes after optionalJwtAuth
- URL rewriting in getSharedMessages is no longer gated to public shares (the
  route now authorizes header-less requests), so files work uniformly across
  public and non-public shares; revert the now-unused req.sharePublic plumbing

* 🔒 fix: Second Codex pass on shared-link file snapshots

Addresses the follow-up Codex findings on PR #13740:

- Don't snapshot transient text-source files: FileSources.text filepaths are
  Multer temp paths the upload route deletes, so they can't be streamed —
  removed from the streamable allowlist.
- Unset stale snapshots on a disabled-feature update: updateSharedLink now
  $unsets fileSnapshots when snapshotFiles is false, so an opted-out update
  can't keep serving file ids the update dropped.
- Load tenant config after share resolution: configMiddleware now runs after
  canAccessSharedLink (which enters the share's tenant ALS context), so
  per-tenant interface.sharedLinks.snapshotFiles overrides apply to anonymous
  public views.
- Return a clean 404 when the snapshotted object is gone: resolveShareFile now
  requires the live file record and 404s if it's been deleted/expired, instead
  of letting the stream error after headers are sent (ENOENT / 500).

(The re-flagged P1 about private-viewer rewriting was already fixed in the prior
commit's cookie-auth change.)

* 🔒 fix: Third Codex pass on shared-link file snapshots

Addresses the third Codex review pass on PR #13740:

- P1: keep shared previews/files pinned to the snapshotted version. Snapshot the
  small previewRevision; resolveShareFile 404s when the live file's revision no
  longer matches (file_id reused/overwritten by a later turn), so old links can't
  surface post-share content — covers both preview text and streamed bytes.
- Honor the toggle as a kill switch: resolveShareFile 404s when snapshotFiles is
  disabled, instead of only skipping backfill, so disabling stops serving
  already-snapshotted file URLs.
- Lazy-sweep orphaned 'pending' previews to 'failed' in the share preview route
  (mirrors the owner route) so the client poller reaches a terminal state.
- Resolve the cookie-fallback user in runAsSystem so strict tenant isolation
  doesn't throw before canAccessSharedLink establishes the share tenant context.

*  feat: Per-link "share files" checkbox for shared links

Add a checkbox to the share-link dialog (checked by default) letting the user
choose whether to include the conversation's files in the shared link, with
copy explaining images/files won't be visible to viewers otherwise. Opting out
skips snapshot creation/serving for that link.

- client: ShareButton renders the checkbox gated on the new
  startupConfig.sharedLinksSnapshotFilesEnabled flag; state threads through
  SharedLinkButton into the create/update mutations as `snapshotFiles`.
- data-provider: createSharedLink/updateSharedLink send `snapshotFiles` in the
  body; TStartupConfig gains `sharedLinksSnapshotFilesEnabled`.
- api: POST/PATCH /api/share compute snapshotFiles as
  isFileSnapshotEnabled(req.config) && body.snapshotFiles !== false (admin gate
  AND per-link opt-out); config.js exposes the effective enabled flag to clients.
- en locale: com_ui_share_files (+ _description).

* 🐛 fix: Make the "share files" opt-out actually hide files

Unchecking "share files" at creation didn't hide anything: the shared message
JSON still carried each file's original (e.g. static-served) path, and because
opting out only meant "no fileSnapshots field" — indistinguishable from a legacy
link — getSharedMessages would backfill snapshots on first view whenever the
admin feature was on, re-enabling files entirely.

Fix by persisting and honoring the per-link choice:
- Store `snapshotFiles` (boolean) on the SharedLink so opt-out is distinct from a
  legacy link; set it on create and update.
- getSharedMessages computes includeFiles = adminEnabled && link not opted out;
  when excluded it strips files/attachments from the payload (no original-path
  leak) and never backfills the opted-out link.
- Surface the stored choice via getSharedLink so the dialog checkbox reflects an
  existing link's actual setting instead of always defaulting to checked.

Note: changing the checkbox on an already-created link still applies only when
the link is refreshed (which regenerates the URL) — a UX follow-up.

* 🔒 fix: Close remaining shared-link file opt-out leaks (Codex)

Follow-up to the per-link opt-out, addressing the third Codex pass:

- Honor the opt-out on the file route too: getSharedLinkFile now returns the
  link's `optedOut` choice; resolveShareFile 404s (and never backfills) an
  opted-out link, so a direct /files/:id request can't re-create snapshots.
- Make read/serve viewer-independent: the gate no longer uses the viewer's
  resolved config (isFileSnapshotEnabled(req.config)) — it uses the link's stored
  choice plus a global env-only kill switch (isFileSnapshotKillSwitchActive). A
  viewer's own interface.sharedLinks.snapshotFiles can no longer hide a link's
  files. Create/update still use the creator's config to set the per-link choice.
- Neutralize render URLs for non-snapshotted files: applyShareFileRoute now
  strips filepath/preview for any file/attachment not in the snapshot, so the
  owner's original (e.g. static) path can't be loaded through the share.

* 🔒 fix: Harden shared-file version pinning and local path handling (Codex)

- Refuse reused/overwritten file snapshots more broadly: resolveShareFile now
  refuses to serve when either previewRevision OR `bytes` changed vs the
  snapshot. `bytes` catches non-office reused outputs (e.g. code-exec
  same-filename images that lack previewRevision) and is stable across S3 URL
  refresh and the pending->ready transition. Same-size content swaps remain a
  best-effort gap inherent to the no-byte-copy design.
- Strip cache-busting query strings before local streaming: code-output images
  add `?v=...` to filepath; the share route now splits it off so getLocalFileStream
  resolves the real filename instead of a literal `*.png?v=...` path.

* 💬 fix: Clarify that file-sharing changes apply on link refresh

For an already-created shared link, changing the "share files" checkbox only
takes effect when the link is refreshed (which regenerates the snapshot). Add a
note under the checkbox, shown only when a link already exists, so the behavior
isn't surprising: "Refresh the link to apply this change — files are snapshotted
when the link is refreshed."
2026-06-20 23:05:13 -04:00
Danny Avila
4b871a11ad
🧼 fix: Prevent Shared Link Caching and Strengthen Log Redaction (#13561)
* fix: tighten share caching and log redaction

* fix: sort changed imports

* fix: redact splat log arguments

* fix: avoid mutating log metadata during redaction

* fix: redact error and api_key log values

* fix: preserve error log context during redaction

* fix: cover remaining log redaction paths

* fix: bound log redaction work

* fix: align redaction scan cap with log config
2026-06-06 18:40:57 -04:00
Atef Bellaaj
86fe79c37d
🔗 feat: Add Granular Access Control to Shared Links via ACL System (#13051)
* feat: Add granular access control to shared links via ACL system

* fix(shared-links): preserve isPublic on failed migration grants

Transient ACL failures during auto-migration permanently stranded
links — $unset ran unconditionally, removing the legacy flag that
triggers retry. Now only $unset isPublic after all grants succeed.

* fix(config): skip isPublic unset for failed ACL grants

Bulk migration unconditionally removed isPublic from all links,
even those whose ACL writes failed. Failed links then lost the
legacy marker needed for auto-migration retry. Now tracks failed
link IDs per-batch and excludes them from the $unset step.

Also adds sharedLink to AccessRole resourceType schema enum —
was missing, only worked because seedDefaultRoles uses
findOneAndUpdate which bypasses validation.

* ci(config): add jest config and PR workflow for migration tests

config/__tests__/ specs depend on api/jest.config.js module
mappings but had no dedicated runner. Adds config/jest.config.js
extending api config with absolutized paths, npm test:config
script, and a GitHub Actions workflow triggered by changes to
config/, api/models/, api/db/, or packages/ ACL code.

* fix(permissions): honor boolean sharedLinks config

SHARED_LINKS has no USE permission, so boolean config produced
an empty update payload — gate conditions only matched object
form, making `sharedLinks: false` a no-op on existing perms.

* fix(share): resolve role before creating shared link

Role lookup between create and grant left an orphaned link
without ACL entries if getRoleByName threw — retry then hit "Share already exists" with no recovery path.

* fix: Restore Public ACL Access Checks

* fix: Type Public ACL Lookup

* fix: Preserve Private Legacy Shared Links

* chore: Promote Shared Link Permission Migration

* fix: Address Shared Link Review Findings

* fix: Repair Shared Link CI Follow-Up

* fix: Narrow Shared Link Mongoose Test Mock

* fix: Address Shared Link Review Follow-Ups

* fix: Close Shared Link Review Gaps

* fix: Guard Missing Shared Link Permission Backfill

* test: Add Shared Link Mock E2E

* test: Stabilize Shared Link Mock E2E

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2026-06-03 14:17:17 -04:00
Danny Avila
9dd062e42e
🧯 fix: Harden Data Retention Semantics (#13049)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
* feat: support data retention for normal chats

Add retentionMode config variable supporting "all" and "temporary" values.
When "all" is set, data retention applies to all chats, not just temporary ones.
Adds isTemporary field to conversations for proper filtering.

Adapted to new TS method files in packages/data-schemas since upstream
moved models out of api/models/.

Based on danny-avila/LibreChat#10532

Co-Authored-By: WhammyLeaf <233105313+WhammyLeaf@users.noreply.github.com>
(cherry picked from commit 30109e90b0)

* feat: extend data retention to files, tool calls, and shared links

Add expiredAt field and TTL indexes to file, toolCall, and share schemas.
Set expiredAt on tool calls, shared links, and file uploads when
retentionMode is "all" or chat is temporary.

(cherry picked from commit 48973752d3)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: lint/test

(cherry picked from commit 310c514e6a)

* fix: address code review feedback for data retention PR

Critical:
- Fix BookmarkMenu crash: restore optional chaining on conversation
- Fix migration hazard: backward-compatible sidebar filter that also
  checks expiredAt for documents without isTemporary field

Major:
- Add logging to getRetentionExpiry error path, align with tools.js
- Add tests for retentionMode: ALL in saveConvo and saveMessage
- Fix share route: apply expiredAt for temporary chats too by
  querying the conversation's isTemporary flag server-side
- Add assertions for getRetentionExpiry mocks in process tests

Minor:
- Fix ChatRoute isTemporaryChat to be strictly boolean via Boolean()
- Fix stale test description (expired -> temporary)
- Comment out retentionMode default in example yaml
- Simplify verbose if/else to isTemporary === true
- Add compound index on { user: 1, isTemporary: 1 }
- Remove narrating comment from process.spec.js

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
(cherry picked from commit 6bad535f90)

* chore: fix typescript

(cherry picked from commit 826527a46b)

* fix: lint

(cherry picked from commit 77817e80ea)

* fix: use mockSanitizeArtifactPath in retention test

The 'getRetentionExpiry is called with the request object' test
referenced an undefined `mockSanitizeFilename` identifier, breaking
both lint (no-undef) and the test suite. Use the existing
`mockSanitizeArtifactPath` mock that the surrounding tests already
use, since `processCodeOutput` calls `sanitizeArtifactPath` (not
`sanitizeFilename`) before invoking `getRetentionExpiry`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 52ea2da66d)

* fix: forward isTemporary from client for retention on file uploads and tool calls

Server-side `getRetentionExpiry` (file uploads) and the tool-call
controller both read `req.body.isTemporary`, but the file upload
multipart form and the tool-call payload did not include that field.
In `retentionMode: temporary` (default), files uploaded and tool
calls created from temporary chats were therefore retained
indefinitely.

Forward the Recoil `isTemporary` flag in both client paths so the
existing server checks can fire correctly. `ToolParams` gains an
optional `isTemporary` field.

Addresses Codex P1 review feedback on PR #29.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit 7e937df05a)

* test: stub store.isTemporary in useFileHandling test mocks

Previous commit added `useRecoilValue(store.isTemporary)` to the
hook. The test file mocks `~/store` with only `ephemeralAgentByConvoId`
and does not stub `useRecoilValue`, so all 7 cases threw
"Invalid argument to useRecoilValue: expected an atom or selector but
got undefined". Add a stub default export with `isTemporary` and a
`useRecoilValue` mock returning `false`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
(cherry picked from commit eb1609537d)

* fix: harden data retention semantics

* fix: provide sweep request context for expired files

* fix: preserve temporary flags in all-retention updates

* fix: honor assistant versions in retention sweeps

* fix: retain non-temporary flags in all mode

* fix: hide expired retained records

* fix: propagate retained conversation expiry

* fix: refresh meili retention cutoff

* fix: prevent overlapping file sweeps

* fix: show legacy retained conversations

* fix: index legacy retained records

* fix: harden retention cleanup edge cases

* fix: count failed file storage sweeps

* fix: preserve legacy temporary retention

* fix: assign retention sweep worker deterministically

* fix: hide expired shared links on reads

* fix: prevent retention refresh after parent expiry

* fix: break code output retention import cycle

* fix: harden retention review findings

* fix: ignore expired share duplicates

* fix: reject expired retained share creation

* fix: harden retention review edge cases

* fix: address retention audit findings

* fix: enforce expired conversation shares in all retention

* fix: scope temporary upload flag to chat files

* fix: address retention review findings

* fix: address codex retention review findings

* fix: tighten missing storage detection

* test: remove unused file process spec bindings

---------

Co-authored-by: WhammyLeaf <233105313+WhammyLeaf@users.noreply.github.com>
Co-authored-by: Aron Gates <aron@muonspace.com>
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-05-19 21:58:42 -04:00
Danny Avila
ae75fb68a6
📸 refactor: Refresh Shared Links With Latest Snapshot (#13095)
Some checks are pending
Docker Dev Branch Images Build / build (Dockerfile, lc-dev, node) (push) Waiting to run
Docker Dev Branch Images Build / build (Dockerfile.multi, lc-dev-api, api-build) (push) Waiting to run
GitNexus Index / index (push) Waiting to run
GitNexus Index / post-index (push) Blocked by required conditions
* fix: refresh shared links with latest target

* fix: validate shared link refresh payload
2026-05-13 19:38:28 -04:00
Lionel Ringenbach
6d0938be64
🔒 refactor: Set ALLOW_SHARED_LINKS_PUBLIC to false by Default (#12100)
* fix: default ALLOW_SHARED_LINKS_PUBLIC to false for security

Shared links were publicly accessible by default when
ALLOW_SHARED_LINKS_PUBLIC was not explicitly set, which could lead to
unintentional data exposure. Users may assume their authentication
settings protect shared links when they do not.

This changes the default behavior so shared links require JWT
authentication unless ALLOW_SHARED_LINKS_PUBLIC is explicitly set to
true.

* Document ALLOW_SHARED_LINKS_PUBLIC in .env.example

Add comment explaining ALLOW_SHARED_LINKS_PUBLIC setting.

---------

Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Danny Avila <danacordially@gmail.com>
2026-03-06 19:05:56 -05:00
Marco Beretta
5566cc499e
🔗 fix: Add branch-specific shared links (targetMessageId) (#10016)
* feat: Enhance shared link functionality with target message support

* refactor: Remove comment on compound index in share schema

* chore: Reorganize imports in ShareButton component for clarity

* refactor: Integrate Recoil for latest message tracking in ShareButton component

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2025-10-10 08:42:05 -04:00
Danny Avila
3af2666890
🪐 refactor: Migrate Share Functionality to Type-Safe Methods (#7903)
* chore: Update import for isEnabled utility in convoAccess middleware

* refactor: Migrate Share functionality to new methods structure in `@librechat/data-schemas`

- Deleted the old Share.js model and moved its functionality to a new share.ts file within the data-schemas package.
- Updated imports across the codebase to reflect the new structure.
- Enhanced error handling and logging in shared link operations.
- Introduced TypeScript types for shared links and related operations to improve type safety and maintainability.

* chore: Update promptGroupSchema validation with typing

* fix: error handling and logging in createSharedLink

* fix: don't allow empty shared link or shared link without messages

* ci: add tests for shared link methods

* chore: Bump version of @librechat/data-schemas to 0.0.9 in package.json and package-lock.json

* chore: Add nanoid as peer dependency

- Introduced `nanoid` as a dependency in `package.json` and `package-lock.json`.
- Replaced UUID generation with `nanoid` for creating unique conversation and message IDs in share methods tests.
2025-06-14 11:24:30 -04:00
Marco Beretta
fa9e778399
🔗 feat: Enhance Share Functionality, Optimize DataTable & Fix Critical Bugs (#5220)
* 🔄 refactor: frontend and backend share link logic; feat: qrcode for share link; feat: refresh link

* 🐛 fix: Conditionally render shared link and refactor share link creation logic

* 🐛 fix: Correct conditional check for shareId in ShareButton component

* 🔄 refactor: Update shared links API and data handling; improve query parameters and response structure

* 🔄 refactor: Update shared links pagination and response structure; replace pageNumber with cursor for improved data fetching

* 🔄 refactor: DataTable performance optimization

* fix: delete shared link cache update

* 🔄 refactor: Enhance shared links functionality; add conversationId to shared link model and update related components

* 🔄 refactor: Add delete functionality to SharedLinkButton; integrate delete mutation and confirmation dialog

* 🔄 feat: Add AnimatedSearchInput component with gradient animations and search functionality; update search handling in API and localization

* 🔄 refactor: Improve SharedLinks component; enhance delete functionality and loading states, optimize AnimatedSearchInput, and refine DataTable scrolling behavior

* fix: mutation type issues with deleted shared link mutation

* fix: MutationOptions types

* fix: Ensure only public shared links are retrieved in getSharedLink function

* fix: `qrcode.react` install location

* fix: ensure non-public shared links are not fetched when checking for existing shared links, and remove deprecated .exec() method for queries

* fix: types and import order

* refactor: cleanup share button UI logic, make more intuitive

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2025-01-21 09:31:05 -05:00
Yuichi Oneda
4e4de88faa
🔧 fix(Shared Links): Handling Shared Link Errors (#3118)
* refactor: add error handling in Share model

* refactor: add error handing to API routers

* refactor: display error message when API response is an error

* chore: remove unneccesary JSON.stringify

* chore: revert unintended changes

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2024-06-21 10:12:37 -04:00
Yuichi Oneda
8d8b17e7ed
🚀 feat: Add Option to Disable Shared Links (#2986)
* feat: add option to disable shared links

* chore: update languages

---------

Co-authored-by: Danny Avila <danny@librechat.ai>
2024-06-15 11:12:03 -04:00
Danny Avila
f0e8cca5df
🚀 feat: Shared Links (#2772)
*  feat(types): add necessary types for shared link feature

*  feat: add shared links functions to data service

Added functions for retrieving, creating, updating, and deleting shared links and shared messages.

*  feat: Add useGetSharedMessages hook to fetch shared messages by shareId

Adds a new hook `useGetSharedMessages` which fetches shared messages based on the provided shareId.

*  feat: Add share schema and data access functions to API models

*  feat: Add share endpoint to API

The GET /api/share/${shareId} is exposed to the public, so authentication is not required. Other paths require authentication.

* ♻️ refactor(utils): generalize react-query cache manipulation functions

Introduces generic functions for manipulating react-query cache entries, marking a refinement in how query cache data is managed. It aims to enhance the flexibility and reusability of the cache interaction patterns within our application.

- Replaced specific index names with more generic terms in queries.ts, enhancing consistency across data handling functions.
- Introduced new utility functions in collection.ts for adding, updating, and deleting data entries in an InfiniteData<TCollection>. These utility functions (`addData`, `updateData`, `deleteData`, `findPage`) are designed to be re-usable across different data types and collections.
- Adapted existing conversation utility functions in convos.ts to leverage these new generic utilities.

*  feat(shared-link): add functions to manipulate shared link cache list

implemented new utility functions to handle additions, updates, and deletions in the shared link cache list.

*  feat: Add mutations and queries for shared links

*  feat(shared-link): add `Share` button to conversation list

- Added a share button in each conversation in the conversation list.
- Implemented functionality where clicking the share button triggers a POST request to the API.
- The API checks if a share link was already created for the conversation today; if so, it returns the existing link.
- If no link was created for today, the API will create a new share link and return it.
- Each click on the share button results in a new API request, following the specification similar to ChatGPT's share link feature.

* ♻️ refactor(hooks): generalize useNavScrolling for broader use

- Modified `useNavScrolling` to accept a generic type parameter `TData`, allowing it to be used with different data structures besides `ConversationListResponse`.
- Updated instances in `Nav.tsx` and `ArchivedChatsTable.tsx` to explicitly specify `ConversationListResponse` as the type argument when invoking `useNavScrolling`.

*  feat(settings): add shared links listing table with delete functionality in settings

- Integrated a delete button for each shared link in the table, allowing users to remove links as needed.

* ♻️ refactor(components): separate `EndpointIcon` from `Icon` component for standalone use

* ♻️ refactor: update useGetSharedMessages to return TSharedLink

- Modified the useGetSharedMessages hook to return not only a list of TMessage but also the TSharedLink itself.
- This change was necessary to support displaying the title and date in the Shared Message UI, which requires data from TSharedLink.

*  feat(shared link): add UI for displaying shared conversations without authentication

- Implemented a new UI component to display shared conversations, designed to be accessible without requiring authentication.
- Reused components from the authenticated Messages module where possible. Copied and adapted components that could not be directly reused to fit the non-authenticated context.

* 🔧 chore: Add translations

Translate labels only. Messages remain in English as they are possibly subject to change.

* ♻️ refactor: add icon and tooltip props to EditMenuButton component

* moved icon and popover to arguments so that EditMenuButton can be reused.
* modified so that when a ShareButton is closed, the parent DropdownMenu is also closed.

* ♻️irefactor: added DropdownMenu for Export and Share

* ♻️ refactor: renamed component names more intuitive

* More accurate naming of the dropdown menu.
* When the export button is closed, the parent dropdown menu is also closed.

* 🌍 chore: updated translations

* 🐞 Fix: OpenID Profile Image Download (#2757)

* Add fetch requirement

Fixes - error: [openidStrategy] downloadImage: Error downloading image at URL "https://graph.microsoft.com/v1.0/me/photo/$value": TypeError: response.buffer is not a function

* Update openidStrategy.js

---------

Co-authored-by: Danny Avila <danacordially@gmail.com>

* 🚑 fix(export): Issue exporting Conversation with Assistants (#2769)

* 🚑 fix(export): use content as text if content is present in the message

If the endpoint is assistants, the text of the message goes into content, not message.text.

* refactor(ExportModel): TypeScript, remove unused code

---------

Co-authored-by: Yuichi Ohneda <ohneda@gmail.com>

* 📤style: export button icon (#2752)

* refactor(ShareDialog): logic and styling

* refactor(ExportAndShareMenu): imports order and icon update

* chore: imports

* chore: imports/render logic

* feat: message branching

* refactor: add optional config to useGetStartupConfig

* refactor: disable endpoints query

* chore: fix search view styling gradient in light mode

* style: ShareView gradient styling

* refactor(Share): use select queries

* style: shared link table buttons

* localization and dark text styling

* style: fix clipboard button layout shift app-wide and add localization for copy code

* support assistants message content in shared links, add useCopyToClipboard, add copy buttons to Search Messages and Shared Link Messages

* add localizations

* comparisons

---------

Co-authored-by: Yuichi Ohneda <ohneda@gmail.com>
Co-authored-by: bsu3338 <bsu3338@users.noreply.github.com>
Co-authored-by: Fuegovic <32828263+fuegovic@users.noreply.github.com>
2024-05-17 18:13:32 -04:00