Skip to content

fix(ai-bedrock): use string-literal specifiers for AWS SDK dynamic imports#958

Open
feiiiiii5 wants to merge 2 commits into
TanStack:mainfrom
feiiiiii5:fix/ai-bedrock-static-bundler-specifiers
Open

fix(ai-bedrock): use string-literal specifiers for AWS SDK dynamic imports#958
feiiiiii5 wants to merge 2 commits into
TanStack:mainfrom
feiiiiii5:fix/ai-bedrock-static-bundler-specifiers

Conversation

@feiiiiii5

@feiiiiii5 feiiiiii5 commented Jul 19, 2026

Copy link
Copy Markdown

🎯 Changes

@tanstack/ai-bedrock loaded its AWS SDK dependencies (@aws-sdk/client-bedrock-runtime and @aws-sdk/credential-providers) through dynamic imports whose specifier was a variable:

```ts
const mod = '@aws-sdk/client-bedrock-runtime'
return import(/* @vite-ignore */ mod)
```

Static bundlers — esbuild, bun build, Rollup — cannot resolve `import()` when the argument is not a string literal, so the SDK was left external and runtime resolution failed in `node_modules`-free server bundles. The reported failure in #929: a Bun build of a Bedrock-backed server threw `Cannot find package @aws-sdk/client-bedrock-runtime` on the first request.

This PR switches both anti-pattern sites to string-literal specifiers:

  • `packages/ai-bedrock/src/utils/auth.ts` — credential-providers import
  • `packages/ai-bedrock/src/adapters/converse-text.ts` — client-bedrock-runtime import

The dynamic import still defers the Node-only SDK until first use, so the module-load graph is unchanged — but bundlers can now statically resolve and include the SDK in self-contained server artifacts.

Also adds a source-level regression test (`packages/ai-bedrock/tests/bundler-static-analysis.test.ts`) that pins the literal-specifier contract for both sites — if a future refactor brings the variable-specifier pattern back, the test fails before the regression ships. A source-level regex check was chosen over a real bundler run because the contract is purely about static analysability; a regex over the source is the smallest test that faithfully pins it, with no new dev dependency (esbuild/acorn/etc.) and no slow build step in the unit suite.

Vite's dev-time `optimizeDeps` pre-bundler may try to scan the now-static SDK import for the browser and fail on the SDK's Node-only exports. Browser-side use of this server-only adapter is unsupported; the comments in `auth.ts` and `converse-text.ts` document the `optimizeDeps.exclude` workaround and point to the matching pattern already in `examples/ts-react-chat/vite.config.ts`.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with `pnpm run test:pr`.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.

Test Plan

Ran locally (skipping `test:react-native` which needs a RN simulator — RN packages are not touched by this PR):

```
pnpm exec nx affected --targets=test:sherif,test:knip,test:docs,test:kiira,test:eslint,test:lib,test:types,test:build,build --exclude=examples/,testing/
pnpm test:dts
```

All green (12/12 Nx tasks, `test:dts` clean — 127 .d.ts files, no dangling references). The new `bundler-static-analysis.test.ts` passes 4/4. The `@tanstack/ai-bedrock:test:eslint` initially flagged a redundant `as Promise` cast that the string-literal specifier made unnecessary; that cast has been removed.

Fixes #929.

Summary by CodeRabbit

  • Bug Fixes

    • Improved AWS SDK dynamic imports so static bundlers can resolve them reliably by using string-literal import specifiers.
    • Continued deferred loading behavior for AWS services and credential providers.
  • Tests

    • Added a regression test that scans the codebase to ensure the bundler-compatible import pattern is maintained and to prevent reintroducing the prior indirection approach.

…ports (TanStack#929)

The adapter loaded its AWS SDK dependencies through dynamic imports whose
specifier was a variable — `const mod = '@aws-sdk/...'; import(/* @vite-ignore */
mod)`. Static bundlers (esbuild, bun build, Rollup) cannot resolve import()
when the argument is not a string literal, so the SDK was left external and
runtime resolution failed in node_modules-free server bundles. The reported
failure: a Bun build of a Bedrock-backed server threw "Cannot find package
@aws-sdk/client-bedrock-runtime" on the first request.

Switch both anti-pattern sites (auth.ts credential-providers import and
converse-text.ts client-bedrock-runtime import) to string-literal specifiers.
The dynamic import still defers the Node-only SDK until first use, so the
module-load graph is unchanged, but bundlers can now statically resolve and
include the SDK in self-contained server artifacts.

Adds a source-level regression test that pins the literal-specifier contract
for both sites — if a future refactor brings the variable-specifier pattern
back, the test fails before the regression ships.

Fixes TanStack#929.
@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: b5a2c414-a924-4eb5-8065-09b906b9f803

📥 Commits

Reviewing files that changed from the base of the PR and between d5fc47c and 649ab2d.

📒 Files selected for processing (2)
  • packages/ai-bedrock/src/adapters/converse-text.ts
  • packages/ai-bedrock/tests/bundler-static-analysis.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/ai-bedrock/tests/bundler-static-analysis.test.ts
  • packages/ai-bedrock/src/adapters/converse-text.ts

📝 Walkthrough

Walkthrough

AWS SDK dynamic imports in the Bedrock adapter now use string-literal specifiers for static bundler resolution. A Vitest source-analysis regression test enforces this pattern, and a patch changeset documents the fix.

Changes

Bedrock bundler import handling

Layer / File(s) Summary
Literal AWS SDK imports
packages/ai-bedrock/src/adapters/converse-text.ts, packages/ai-bedrock/src/utils/auth.ts
Lazy imports for the Bedrock runtime and credential providers now use direct string literals while retaining deferred loading and existing credential resolution.
Static import regression coverage
packages/ai-bedrock/tests/bundler-static-analysis.test.ts, .changeset/ai-bedrock-static-bundler-specifiers.md
Source checks require literal AWS SDK import specifiers, reject variable-based patterns, and document the patch release.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

  • TanStack/ai#665: Updates the same Bedrock imports and adds matching regression coverage.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately captures the main change: switching AWS SDK dynamic imports to string-literal specifiers in ai-bedrock.
Description check ✅ Passed The description includes the required Changes, Checklist, and Release Impact sections, plus a useful test plan.
Linked Issues check ✅ Passed The PR implements #929 by making both AWS SDK imports statically analyzable and adding a regression test.
Out of Scope Changes check ✅ Passed The changes stay focused on the Bedrock import fix, comments/docs, a changeset, and a regression test.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
packages/ai-bedrock/src/adapters/converse-text.ts (1)

111-111: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Align the return type with the JSDoc comment.

The comment on line 100 mentions that typeof import(...) is used to maintain full typing without a cast, but the method returns Promise<typeof BedrockRuntime>. You can inline the typeof import(...) here to match the comment perfectly, which may also remove the need for a separate top-level type import for BedrockRuntime.

💅 Proposed refactor
-  protected importBedrockRuntime(): Promise<typeof BedrockRuntime> {
+  protected importBedrockRuntime(): Promise<typeof import('`@aws-sdk/client-bedrock-runtime`')> {
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ai-bedrock/src/adapters/converse-text.ts` at line 111, Update the
return type of importBedrockRuntime to inline the typeof import(...) expression
described by its JSDoc, replacing the separate BedrockRuntime type reference
while preserving the method’s Promise-based typing and implementation behavior.
packages/ai-bedrock/tests/bundler-static-analysis.test.ts (1)

1-3: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Reorder imports to place built-in Node modules before external packages.

As indicated by ESLint, built-in modules (node:fs, node:url) should precede external dependencies (vitest).

💅 Proposed refactor
-import { describe, expect, it } from 'vitest'
-import { readFileSync } from 'node:fs'
-import { fileURLToPath } from 'node:url'
+import { readFileSync } from 'node:fs'
+import { fileURLToPath } from 'node:url'
+import { describe, expect, it } from 'vitest'
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/ai-bedrock/tests/bundler-static-analysis.test.ts` around lines 1 -
3, Reorder the imports in bundler-static-analysis.test.ts so the built-in Node
modules, including node:fs and node:url, appear before the external vitest
import, without changing any import contents or test behavior.

Source: Linters/SAST tools

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@packages/ai-bedrock/src/adapters/converse-text.ts`:
- Line 111: Update the return type of importBedrockRuntime to inline the typeof
import(...) expression described by its JSDoc, replacing the separate
BedrockRuntime type reference while preserving the method’s Promise-based typing
and implementation behavior.

In `@packages/ai-bedrock/tests/bundler-static-analysis.test.ts`:
- Around line 1-3: Reorder the imports in bundler-static-analysis.test.ts so the
built-in Node modules, including node:fs and node:url, appear before the
external vitest import, without changing any import contents or test behavior.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ad9645a9-3c77-45d2-a0db-dc82ef68c21f

📥 Commits

Reviewing files that changed from the base of the PR and between bf870fa and d5fc47c.

📒 Files selected for processing (4)
  • .changeset/ai-bedrock-static-bundler-specifiers.md
  • packages/ai-bedrock/src/adapters/converse-text.ts
  • packages/ai-bedrock/src/utils/auth.ts
  • packages/ai-bedrock/tests/bundler-static-analysis.test.ts

- Reorder imports in `bundler-static-analysis.test.ts` so built-in `node:fs`
  and `node:url` precede the external `vitest` import (built-in-first per
  @typescript-eslint/consistent-type-imports and the repo's other tests).
- Align the `importBedrockRuntime` JSDoc with the actual return type
  (`typeof BedrockRuntime` from the type-only namespace import, not
  `typeof import(...)` — the inline form is rejected by the repo's
  `consistent-type-imports` config, so the namespace import stays).

CodeRabbit's first nitpick (inline `typeof import('@aws-sdk/...')` on the
return type) was tested and reverted: it triggers
`@typescript-eslint/consistent-type-imports`'s `import()` type-annotation
ban, so the type-only namespace import is preserved as-is.
@feiiiiii5

Copy link
Copy Markdown
Author

@coderabbitai thanks for the review. Both nitpicks addressed in 649ab2d:

1. bundler-static-analysis.test.ts import order — applied as suggested. Built-in node:fs / node:url now precede vitest (built-in-first, matching the repo's other test files).

2. converse-text.ts return type — tested inlining Promise<typeof import('@aws-sdk/client-bedrock-runtime')> and dropping the top-level import type * as BedrockRuntime namespace. It works at runtime but trips the repo's @typescript-eslint/consistent-type-imports rule, which bans import() type annotations in this codebase (error \import()` type annotations are forbidden). Reverted to the namespace import and aligned the JSDoc wording to match (typeof BedrockRuntimefrom the type-only namespace import, nottypeof import(...)`). The key fix for #929 — using a string-literal specifier — is unchanged.

Local pre-PR gate re-run after the refactor: nx affected --targets=test:lib,test:types,test:eslint,test:build,build 9/9 ✅, pnpm test:dts clean (127 .d.ts files).

@coderabbitai

coderabbitai Bot commented Jul 19, 2026

Copy link
Copy Markdown
Contributor

Tip

For best results, initiate chat on the files or code changes.

@feiiiiii5 Thanks for validating both paths. The built-in-first import ordering and retaining the type-only BedrockRuntime namespace are appropriate given the repository’s lint rule. Most importantly, the string-literal dynamic import behavior for #929 remains intact.

🐇✨


✏️ Learnings added
Learnt from: feiiiiii5
URL: https://github.com/TanStack/ai/pull/958

Timestamp: 2026-07-19T04:10:16.779Z
Learning: In the TanStack/ai TypeScript codebase, the `typescript-eslint/consistent-type-imports` configuration forbids `import()` type annotations. For `packages/ai-bedrock/src/adapters/converse-text.ts`, retain the `import type * as BedrockRuntime` namespace and use `typeof BedrockRuntime` for the lazy AWS Bedrock runtime import return type rather than `typeof import('aws-sdk/client-bedrock-runtime')`.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


If you found this review helpful, would you consider giving us a shout-out on X?

Thank you for using CodeRabbit!

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.

@tanstack/ai-bedrock: the AWS SDK cannot be bundled — variable-specifier dynamic imports defeat static bundlers (incl. esbuild)

1 participant