Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SyntaxError: Could not find export 'fromNodeProviderChain' in module '@aws-sdk/credential-providers' #518

Open
paul-uz opened this issue Aug 1, 2024 · 25 comments

Comments

@paul-uz
Copy link

paul-uz commented Aug 1, 2024

Despite this package beig included, I get this error when trying to run my code. Installing the package locally as a dev dependency, I get no errors about fromNodeProviderChain being missing, and can indeed see the export.

@paul-uz
Copy link
Author

paul-uz commented Aug 1, 2024

Ideally, could we get https://www.npmjs.com/package/@aws-sdk/credential-provider-node added to the runtime?

@nabetti1720
Copy link
Contributor

nabetti1720 commented Aug 1, 2024

I tried to add @aws-sdk/credential-provider-node but at the end of the dependency I got an error that the http module could not be resolved.

Optimized: CognitoIdentity
✘ [ERROR] Could not resolve "http"

    node_modules/@smithy/credential-provider-imds/dist-es/remoteProvider/httpRequest.js:3:24:
      3 │ import { request } from "http";~~~~~~

  The package "http" wasn't found on the file system but is built into node. Are you trying to
  bundle for node? You can use "platform: 'node'" to do that, which will remove this error.

Optimized: Aws_json1_1
Optimized: Aws_json1_1
Optimized: Aws_json1_1
Optimized: Aws_json1_1
Optimized: Aws_json1_1
Optimized: Aws_json1_1
Optimized: Aws_json1_1
Optimized: Aws_json1_1
1 error
/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:1472
  let error = new Error(text);
              ^

Error: Build failed with 1 error:
node_modules/@smithy/credential-provider-imds/dist-es/remoteProvider/httpRequest.js:3:24: ERROR: Could not resolve "http"
    at failureErrorWithLog (/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:1472:15)
    at /Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:945:25
    at runOnEndCallbacks (/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:1315:45)
    at buildResponseToResult (/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:943:7)
    at /Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:970:16
    at responseCallbacks.<computed> (/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:622:9)
    at handleIncomingPacket (/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:677:12)
    at Socket.readFromStdout (/Users/shinya/Workspaces/llrt/node_modules/esbuild/lib/main.js:600:7)
    at Socket.emit (node:events:519:28)
    at addChunk (node:internal/streams/readable:559:12) {
  errors: [Getter/Setter],
  warnings: [Getter/Setter]
}

Node.js v20.13.1

Perhaps this is why @aws-sdk/credential-provider-node cannot be added.

Currently, when building LLRT, the platform is browser. Would it make any difference if I set the platform of your application's bundler to browser?

@nabetti1720
Copy link
Contributor

Related to #40

@Sytten

This comment has been minimized.

@paul-uz
Copy link
Author

paul-uz commented Aug 2, 2024

Ha it is because it should be marked as external or whatever terminology your bundler uses so it doesn't try to resolve it at bundling time. It is provided at runtime.

This isn't a helpful comment.

@richarddavison
Copy link
Contributor

@paul-uz thanks for your comments. fromNodeProviderChain as the name implies assumes a Node.js environment. We could provide it but we're not supporting the required dependencies. What features are you looking for from fromNodeProviderChain? You should be able to use alternatives such as credential-provider-http, credential-provider-env, credential-provider-process etc

@paul-uz
Copy link
Author

paul-uz commented Aug 2, 2024

@paul-uz thanks for your comments. fromNodeProviderChain as the name implies assumes a Node.js environment. We could provide it but we're not supporting the required dependencies. What features are you looking for from fromNodeProviderChain? You should be able to use alternatives such as credential-provider-http, credential-provider-env, credential-provider-process etc

I ideally need the default provider from the other package, for signing requests.

Tbh I don't actually know which one I could use in its place as the one I was using tries various methods of finding the credentials and I don't know what lambda actually uses for node projects.

@richarddavison
Copy link
Contributor

@paul-uz can you share a bit of code? I need some more context to understand what you're after. Usually you don't have to deal with the credential process in the SDK.

@paul-uz
Copy link
Author

paul-uz commented Aug 21, 2024

@paul-uz can you share a bit of code? I need some more context to understand what you're after. Usually you don't have to deal with the credential process in the SDK.

Sure here you go

      const request = new HttpRequest({
        headers: {
          'Content-Type': 'application/json',
          'host': SEARCH_DOMAIN_ENDPOINT!,
        },
        hostname: SEARCH_DOMAIN_ENDPOINT!,
        method: 'GET',
        path: SEARCH_INDEX + '/_search',
        query: queryParams as any,
      });

      var signer = new SignatureV4({
        credentials: defaultProvider(),
        region: REGION,
        service: 'es',
        sha256: Sha256,
      });

      const signedRequest = await signer.sign(request);
      const { response } = await client.handle(signedRequest as HttpRequest);

@paul-uz
Copy link
Author

paul-uz commented Sep 26, 2024

@richarddavison any updates on this? It would be nice to get our app using the LLRT

@richarddavison
Copy link
Contributor

@richarddavison any updates on this? It would be nice to get our app using the LLRT

I will take a look at your example. I'm rather confident this would work with minimum modification!

@richarddavison
Copy link
Contributor

@richarddavison any updates on this? It would be nice to get our app using the LLRT

Here is a local working example:

import { HttpRequest } from "@smithy/protocol-http";
import { SignatureV4 } from "@smithy/signature-v4";
import { Sha256 } from "@aws-crypto/sha256-browser";

const CREDENTIALS = {
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  sessionToken: process.env.AWS_SESSION_TOKEN,
};

const REGION = process.env.AWS_REGION;

const SEARCH_DOMAIN_ENDPOINT = "https://www.example.com";
const SEARCH_INDEX = "index_name";
const queryParams = {
  example: "foobar",
};

const request = new HttpRequest({
  headers: {
    "Content-Type": "application/json",
    host: SEARCH_DOMAIN_ENDPOINT,
  },
  hostname: SEARCH_DOMAIN_ENDPOINT,
  method: "GET",
  path: SEARCH_INDEX + "/_search",
  query: queryParams,
});

var signer = new SignatureV4({
  credentials: CREDENTIALS,
  region: REGION,
  service: "es",
  sha256: Sha256,
});

const signedRequest = await signer.sign(request);

console.log(signedRequest);

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

@richarddavison any updates on this? It would be nice to get our app using the LLRT

Here is a local working example:

import { HttpRequest } from "@smithy/protocol-http";
import { SignatureV4 } from "@smithy/signature-v4";
import { Sha256 } from "@aws-crypto/sha256-browser";

const CREDENTIALS = {
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
  sessionToken: process.env.AWS_SESSION_TOKEN,
};

const REGION = process.env.AWS_REGION;

const SEARCH_DOMAIN_ENDPOINT = "https://www.example.com";
const SEARCH_INDEX = "index_name";
const queryParams = {
  example: "foobar",
};

const request = new HttpRequest({
  headers: {
    "Content-Type": "application/json",
    host: SEARCH_DOMAIN_ENDPOINT,
  },
  hostname: SEARCH_DOMAIN_ENDPOINT,
  method: "GET",
  path: SEARCH_INDEX + "/_search",
  query: queryParams,
});

var signer = new SignatureV4({
  credentials: CREDENTIALS,
  region: REGION,
  service: "es",
  sha256: Sha256,
});

const signedRequest = await signer.sign(request);

console.log(signedRequest);

Thank you for taking the time to reply, however, this code doesn't use the defaultProvider method which is what I need to use.

@richarddavison
Copy link
Contributor

No problem. I might be missing something here but why do you need the defaultProvider function?

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

No problem. I might be missing something here but why do you need the defaultProvider function?

Simply the fact that that method is what we have historically used to provide credentials inside our Lambdas when needed. Ideally, the less refactoring required, the more likely that we can start using LLRT for certain/all functions.

If there is no feasible way it can be used currently with the LLRT due to missing packages ie http/https, then we'd need an easy solution that takes little time to refactor.

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

@richarddavison I;ve just done a quick test, replacing defaultProvider() with the env vars, and it looks like that works fine as a replacement.

I'll retry bundling this function for the LLRT and give it another go.

For future ref, how can I handle any 3rd party package that requires http/https? I think the docs talk about overrides, but the information is lacking.

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

So I'm using @smithy/node-http-handler to handle the response from the signed http request, and that is failing. What can I replace it with? Code below for context

const client = new NodeHttpHandler();

...


const signedRequest = await signer.sign(request);
const { response } = await client.handle(signedRequest as HttpRequest);
const finalResponse = await this.getFinalResponse(response);

getFinalResponse = async (response: HttpResponse): Promise<any> => {
  var responseBody = '';
  return await new Promise((resolve) => {
    response.body.on('data', (chunk: any) => {
      responseBody += chunk;
    });
    response.body.on('end', () => {
      resolve(JSON.parse(responseBody));
    });
  }).catch((error) => {
    console.error('Error: ' + error);
  });
};

@richarddavison
Copy link
Contributor

For future ref, how can I handle any 3rd party package that requires http/https? I

This is a bit tricky. Depends on the third party package. Generally speaking, larger third party packages support bundling for browser which assume a fetch is used as http client. We are looking to bring in the lower level http & https packages clients to support more node packages.

So I'm using @aws-sdk/node-http-handler to handle the response from the signed http request, and that is failing. What can I replace it with? Code below for context

Use @smithy/fetch-http-handler.

Your code would be something like this then:

const client = new FetchHttpHandler();
...
const signedRequest = await signer.sign(request);
const { response } = await client.handle(signedRequest);
const str = JSON.parse(await response.Body.transformToString())

One thing to note though is that using the lower level APIs like this is not very common.

You probably have a very good reason for doing so but usually SDK integrations are done via the clients like shown in this example:
https://github.com/awslabs/llrt/blob/main/index.mjs

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

@richarddavison FYI const str = JSON.parse(await response.body.transformToString()) doesn't work.

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

You probably have a very good reason for doing so but usually SDK integrations are done via the clients like shown in this example:
https://github.com/awslabs/llrt/blob/main/index.mjs

Forgot to mention, in this case, its for OpenSearch. There is no AWS SDK for it, so we do it via a signed request. There is a OpenSearch NPM package I might look to move to, but i suspect it uses http/https and not fetch.

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

@richarddavison you'll be pleased to here that I got this function working finally.

Few tweaks here and there, and I've had to remove out internal SDK as that uses the node-http-handler.

Do you know if smithy/fetch-http-handler can be used even if we're not using the LLRT, but using Nodejs20 Lambdas?

@richarddavison
Copy link
Contributor

Do you know if smithy/fetch-http-handler can be used even if we're not using the LLRT, but using Nodejs20 Lambdas?

Yes, you can! Works in node 20 as well!

@richarddavison
Copy link
Contributor

Forgot to mention, in this case, its for OpenSearch. There is no AWS SDK for it, so we do it via a signed request. There is a OpenSearch NPM package I might look to move to, but i suspect it uses http/https and not fetch.

We do support OpenSearch:
https://www.npmjs.com/package/@aws-sdk/client-opensearch?activeTab=readme

We also support using fetch-http-handler for all SDKs. However, when using LLRT you can use the "full-sdk" release binary which includes OpenSearch client and don't worry about signing headers, credential providers, http handlers or parsing json from the raw response :)
https://github.com/awslabs/llrt/releases/download/v0.2.2-beta/llrt-lambda-arm64-full-sdk.zip

@paul-uz
Copy link
Author

paul-uz commented Sep 27, 2024

That client is for managing OpenSearch, not searching it ;)

@richarddavison
Copy link
Contributor

That client is for managing OpenSearch, not searching it ;)

Ahhhh right, makes sense! I suppose I would try then just use fetch as is then and pass the sigv4 response to it directly:

const res = await fetch(signedResponse)
await res.json()

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

No branches or pull requests

4 participants