Skip to content

fix(web): tweet embeds fetch without the RPC client's credentials - #392

Merged
Makisuo merged 1 commit into
mainfrom
fix/unfurl-credentials
Nov 1, 2026
Merged

Makisuo merged 1 commit into
mainfrom
fix/unfurl-credentials

Conversation

@Makisuo

@Makisuo Makisuo commented Nov 1, 2026 •

Copy link
Copy Markdown
Collaborator

Tweets still showed "Tweet not found" after #386.

Cause: Effect.provide(FetchHttpClient.layer) inside a command reuses the runtime's memoized FetchHttpClient.layer, which is the RPC client's, built with credentials: "include". The link-preview worker answers Access-Control-Allow-Origin: *, and browsers refuse that for a credentialed request. In prod the app's /tweet?id=… requests ended with status 0 in 13–27ms, while the same request without credentials returned 200.

Fix: the unfurl fetches (chat/unfurl.ts) and the emoji-data CDN fetch (emoji-picker/data.ts, same pattern) provide Layer.fresh(FetchHttpClient.layer).

Added unfurl-fetch.test.ts: the memoized layer sends include, the fresh one sends nothing.

🤖 Generated with Claude Code


View with [code]smith Autofix with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need.

`Effect.provide(FetchHttpClient.layer)` in a command reuses the runtime's
memoized client, the RPC client built with `credentials: "include"`. The
link-preview worker answers `Access-Control-Allow-Origin: *`, which the
browser refuses for a credentialed request, so every tweet showed "Tweet not
found". The unfurl and emoji-data fetches now build a fresh client.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@maple-review-bot

maple-review-bot Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Maple review

🟢 Confidence 8/10 · likely safe to merge. The Layer.fresh swap is correct against Effect's layerMergedContext; only the test does not cover the app code it fixes.
1 warning −1 · tests partial −1 · risk medium

Makes the link-preview and emoji-CDN fetches build their own FetchHttpClient layer, so they stop inheriting the RPC client's RequestInit and authenticatedFetch. Correct in mechanism; the added test does not pin it.

  • getJson provides Layer.fresh(FetchHttpClient.layer) instead of the shared layer
  • fetchEmojiData does the same for the jsdelivr CDN fetches

Findings

🟠 Warning · F1 · Reverting Layer.fresh here and in data.ts leaves unfurl-fetch.test.ts green

tests · apps/web-foldkit/src/chat/unfurl.ts:333

The new test builds its own Rpc layer and never runs getJson or fetchEmojiData, so it pins Effect's memoization behaviour, not this fix: putting Effect.provide(FetchHttpClient.layer) back at unfurl.ts:333 and emoji-picker/data.ts:193 keeps it passing while tweets go back to "Tweet not found".

Export `getJson` and run it in the test with the fake `Fetch` plus the RPC resources in context, asserting the recorded `init.credentials` is undefined.
🤖 Prompt to fix this finding with an AI agent
Findings from an automated review of commit 8e744e78ee4e072be4a527dfc5789d78af4ad086. Verify each one against the current code before changing anything, fix only those that still apply, and keep each fix to the lines it names.

---

F1 · Warning · tests · apps/web-foldkit/src/chat/unfurl.ts:333
Reverting `Layer.fresh` here and in `data.ts` leaves `unfurl-fetch.test.ts` green
The new test builds its own `Rpc` layer and never runs `getJson` or `fetchEmojiData`, so it pins Effect's memoization behaviour, not this fix: putting `Effect.provide(FetchHttpClient.layer)` back at `unfurl.ts:333` and `emoji-picker/data.ts:193` keeps it passing while tweets go back to "Tweet not found".
Suggested fix: Export `getJson` and run it in the test with the fake `Fetch` plus the RPC resources in context, asserting the recorded `init.credentials` is undefined.

8e744e7 · What was checked, coverage and telemetry details are on the Maple / review check. Reply "won't fix" to dismiss a finding, or mention @maple-review-bot to ask about one.

@Makisuo
Makisuo merged commit 65122b3 into main Nov 1, 2026
5 checks passed
@Makisuo
Makisuo deleted the fix/unfurl-credentials branch November 1, 2026 14:43
@coderabbitai

coderabbitai Bot commented Nov 1, 2026 •

Copy link
Copy Markdown

Review in Change Stack →

Caution

Review failed

The pull request is closed.

  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

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

@maple-review-bot maple-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

1 inline note from Maple's review. The score and summary are in the review comment above.

Effect.provide(FetchHttpClient.layer),
// Fresh: the runtime's memoized `FetchHttpClient.layer` is the RPC client's, which sends
// credentials, and a credentialed request fails the worker's `Access-Control-Allow-Origin: *`.
Effect.provide(Layer.fresh(FetchHttpClient.layer)),

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Warning

Reverting Layer.fresh here and in data.ts leaves unfurl-fetch.test.ts green

F1 · Warning · tests

The new test builds its own Rpc layer and never runs getJson or fetchEmojiData, so it pins Effect's memoization behaviour, not this fix: putting Effect.provide(FetchHttpClient.layer) back at unfurl.ts:333 and emoji-picker/data.ts:193 keeps it passing while tweets go back to "Tweet not found".

Export `getJson` and run it in the test with the fake `Fetch` plus the RPC resources in context, asserting the recorded `init.credentials` is undefined.
🤖 Prompt to fix with an AI agent
In `apps/web-foldkit/src/chat/unfurl.ts:333`: Reverting `Layer.fresh` here and in `data.ts` leaves `unfurl-fetch.test.ts` green.

The new test builds its own `Rpc` layer and never runs `getJson` or `fetchEmojiData`, so it pins Effect's memoization behaviour, not this fix: putting `Effect.provide(FetchHttpClient.layer)` back at `unfurl.ts:333` and `emoji-picker/data.ts:193` keeps it passing while tweets go back to "Tweet not found".

Suggested fix: Export `getJson` and run it in the test with the fake `Fetch` plus the RPC resources in context, asserting the recorded `init.credentials` is undefined.

Verify the problem exists at that location before changing it, and keep the fix to those lines.

@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown

Coverage Report

Status Category Percentage Covered / Total
🔵 Lines 70.77% 22865 / 32307
🔵 Statements 70.18% 25860 / 36844
🔵 Functions 60.19% 8919 / 14817
🔵 Branches 58.94% 11181 / 18970
File Coverage
File Stmts Branches Functions Lines Uncovered Lines
Changed Files
apps/web-foldkit/src/chat/unfurl.ts 84.52% 78.33% 64.51% 86.48% 82-83, 215-220, 234, 249, 308-311, 327-336, 344-348, 357-361
apps/web-foldkit/src/emoji-picker/data.ts 51.09% 33.33% 22.5% 54.23% 53, 57-59, 64-65, 67, 101-117, 121-129, 133-141, 147-188, 198-213, 218-223, 231-243
Generated in workflow #1998 for commit 8e744e7 by the Vitest Coverage Report Action

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant