Skip to content

Wallet-auth upload contexts rewrite signed multipart field names #2001

Description

@Osraka

Describe the bug

Wallet-auth upload helpers recursively camelize UploadContext.fields, even though the generated OpenAPI schema describes that map as opaque signed multipart data and says every entry must be submitted unchanged.

If an upload context contains a valid field with an underscore, such as Amazon S3's success_action_status, the SDK returns it as successActionStatus instead. The caller can no longer reproduce the form described by the response.

The same UploadContext schema is returned by four helpers:

  • createProfileImageUpload
  • createCollectionImageUpload
  • createDropAllowlistUpload
  • createDropItemMediaUpload (an array of contexts)

Steps to reproduce

Stub the upload response at the real fetch boundary and call one of the helpers:

vi.spyOn(globalThis, "fetch").mockResolvedValue(
  new Response(JSON.stringify({
    url: "https://uploads.example.com/",
    method: "POST",
    fields: {
      key: "uploads/example.png",
      "Content-Type": "image/png",
      success_action_status: "201",
    },
    token: "upload-token-example",
  }), { status: 200 }),
)

const api = new OpenSeaAPI({ apiKey: "key", authToken: "jwt" })
const context = await api.walletAuth.createProfileImageUpload({
  imageType: "PROFILE",
  contentType: "image/png",
})

console.log(context.fields)

Current result:

{
  key: "uploads/example.png",
  "Content-Type": "image/png",
  successActionStatus: "201",
}

This comes from the blanket camelizeKeysDeep() call in OpenSeaAPI.request(). Existing wallet-auth tests mock WalletAuthFetcher.request() directly, so they do not exercise response conversion.

Expected behavior

UploadContext.fields should preserve every key byte-for-byte:

{
  key: "uploads/example.png",
  "Content-Type": "image/png",
  success_action_status: "201",
}

The smallest fix appears to be opting only the four UploadContext call sites out of response camelization. Their top-level response fields are url, method, fields, and token, so this does not change any SDK-style top-level key. createProfileImageUpload must keep its existing snakeizeBody: false request-body behavior.

I have a focused regression test that fails on v12.0.1 with:

Expected: success_action_status
Received: successActionStatus

I can open a narrow PR covering the single-object and array response paths unless this has already been fixed in the internal monorepo.

Environment

  • Package version: 12.0.1
  • Node.js version: 22.21.0
  • Operating system: macOS
  • Chain / network: not chain-specific; reproduced with an offline mocked response

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions