Skip to content

Conversation

@john-royal
Copy link
Collaborator

@john-royal john-royal commented Dec 11, 2025

Provides access to runtime APIs for KV, D1, R2, and Queue resources. Uses a proxy to lazily initialize a Miniflare instance with either the remote binding or the local one.

Not sure if "node binding" is the right way to describe this - let me know if you have any other ideas.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Dec 11, 2025

Open in StackBlitz

npm i https://pkg.pr.new/alchemy-run/alchemy@1255

commit: 208f81d

@github-actions
Copy link

github-actions bot commented Dec 11, 2025

🚀 Website Preview Deployed

Your website preview is ready!

Preview URL: https://611c68fb-alchemy-website.alchemy-run.workers.dev

This preview was built from commit b2e805c


🤖 This comment will be updated automatically when you push new commits to this PR.

@john-royal john-royal marked this pull request as ready for review December 11, 2025 20:48
@@ -1,4 +1,3 @@
import type { R2PutOptions } from "@cloudflare/workers-types/experimental/index.ts";
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Removed because it was causing a type error. Now it relies on the global from @cloudflare/workers-types.

Comment on lines +468 to +477
resumeMultipartUpload: (promise) => (key: string, uploadId: string) =>
makeAsyncProxy(
{ key, uploadId },
promise.then((bucket) => bucket.resumeMultipartUpload(key, uploadId)),
{
uploadPart: true,
abort: true,
complete: true,
},
),
Copy link
Collaborator Author

Choose a reason for hiding this comment

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

resumeMultipartUpload does not return a promise. To match the type of the runtime API, we make this synchronous by returning another proxy.

This is also done for D1 prepared statements and sessions.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you show me an example of what the proxy fixes? Are all the properties Promise<T> or functions returning Promises?

Comment on lines +454 to +455
// TODO(john): this is a problem with @cloudflare/workers-types, it should not be nullable unless options.onlyIf is used
let putObj = (await bucket.put(testKey, testContent)) as R2Object;
Copy link
Collaborator Author

@john-royal john-royal Dec 11, 2025

Choose a reason for hiding this comment

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

Don't merge this PR until I report this to the CF team - this is a weird one

Copy link
Collaborator

Choose a reason for hiding this comment

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

Why not merge it? Is it unusable?

@john-royal john-royal linked an issue Dec 11, 2025 that may be closed by this pull request
@sam-goodwin
Copy link
Collaborator

Node bindings doesn't make sense to me. These are just APIs

Comment on lines +303 to +321
withSession: (promise) => (constraintOrBookmark) =>
makeAsyncProxy(
{},
promise.then((database) =>
database.withSession(constraintOrBookmark),
),
{
prepare: (session) => (query) =>
makePreparedStatementProxy(
session.then((session) => session.prepare(query)),
),
batch: true,
getBookmark: () => () => {
throw new Error(
"D1DatabaseSession.getBookmark is not implemented",
);
},
},
),
Copy link
Collaborator

Choose a reason for hiding this comment

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

We will need to add some tests for each of these APIs on all the resources given how much custom logic there is. Please add tests

@shellscape
Copy link

Really looking forward to this one. We've got a fairly decent amount of typing shenanigans to make Alchemy binding types play nice with @cloudflare/workers-types.

@@ -1,10 +1,8 @@
import type { R2PutOptions } from "@cloudflare/workers-types/experimental/index.ts";

Choose a reason for hiding this comment

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

The R2PutOptions type from experimental is identical to the non-experimental type. I'm not sure the experimental type is needed any longer.

@shellscape
Copy link

Just gave this one a shot locally. When using import { R2Bucket } from '@cloudflare/workers-types and trying to assign a bucket binding to an R2Bucket typed variable, we get the following error:

error TS2322: Type 'R2Bucket' is not assignable to type 'import("/Users/code/node_modules/.bun/@[email protected]/node_modules/@cloudflare/workers-types/index").R2Bucket'.
  The types returned by 'head(...)' are incompatible between these types.
    Type 'Promise<R2Object | null>' is not assignable to type 'Promise<import("/Users/code/node_modules/.bun/@[email protected]/node_modules/@cloudflare/workers-types/index").R2Object | null>'.
      Type 'R2Object | null' is not assignable to type 'import("/Users/code/node_modules/.bun/@[email protected]/node_modules/@cloudflare/workers-types/index").R2Object | null'.
        Type 'R2Object' is not assignable to type 'import("/Users/code/node_modules/.bun/@[email protected]/node_modules/@cloudflare/workers-types/index").R2Object'.
          Types of property 'writeHttpMetadata' are incompatible.
            Type '(headers: Headers) => void' is not assignable to type '(headers: import("/Users/code/node_modules/.bun/@[email protected]/node_modules/@cloudflare/workers-types/index").Headers) => void'.
              Types of parameters 'headers' and 'headers' are incompatible.
                Property 'getSetCookie' is missing in type 'import("/Users/code/node_modules/.bun/@[email protected]/node_modules/@cloudflare/workers-types/index").Headers' but required in type 'Headers'.

Fwiw our tsconfig is setup for strict.

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.

Alchemy R2Bucket types vs @cloudflare/workers-types

4 participants