Npm modules on server only and pick which ones in Cordova

Hi,

We’re trying to use AWS SDK (S3Client) but it makes the client grow by 800kb (and it makes the app not load on old iPhones).

So 2 questions:

1-How can we install the npm package so it goes into the server package only (and not the client/cordova)
2-How can I check what gets included in the Cordova package (and client as well)

Best regards,

Burni

Hi @burni13 may I please ask what do you need S3 for? Do you only need it to upload something to S3?

hi @paulishca
Sorry for the delay.

We’re using S3 to upload Excel files we create on the server.
We’d also like to use it for our users to upload their documents directly from the client and not through the server.

Regards,
Burni

Ok so as I understand, what you need is a server side upload and a “sling” upload from the client.

You can start from here: GitHub - activitree/s3up-meta
You will need to polish the code a bit, I haven’t touched it in a while. You will need to remove this.unblock() where you find it (no longer required in the async env)
You will need to install NPM @aws-sdk/client-s3 as a direct dependency in your project. This package has 2-3 updates every week and I didn’t want to have it hooked into the Meteor package and then struggle to update the package every week.

Here is an example of a server side method that takes an image url and saves the image to S3 with a cacheing configuration:

import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'

new ValidatedMethod({
  name: 'saveLinkPreviewToAWS',
  validate: new SimpleSchema({
    url: String,
    key: String
  }).validator(),
  async run ({ url, key }) {
    if (!this.userId) { throw new Meteor.Error('not-authorized') }

    const s3 = new S3Client({
      region: process.env.AWS_S3_REGION || 'eu-central-1',
      sslEnabled: true, // optional
      httpOptions: {
        timeout: 6000,
        agent: false
      }
    })

    const putFromUrl = async url => {
      try {
        const response = await fetch(url, { method: 'get' }) // fetch the image
        const command = new PutObjectCommand({
          Bucket: process.env.AWS_S3_BUCKET,
          Key: `postsProxy/${this.userId}/${key}.jpg`, // path to where you want it saved in your S3 bucket
          ContentType: response.headers.get('Content-Type'),
          ContentLength: response.headers.get('Content-Length'),
          // Expires: 'Thu, 15 Dec 2050 04:08:00 GMT',
          CacheControl: 'max-age=8460000',
          Body: await response.buffer() // buffer
        })

        s3.send(command, err => {
          if (err) { console.error('Could not upload photo to S3, ', err) }
        })
      } catch (error) {
        if (error /* instanceof fetch.AbortError */) {
          console.error('Could not upload General Post photo to S3, ', error)
        }
      }
    }

    putFromUrl(url)
      .catch(err => console.log(err))
  }
})

Ahhh nice! thanks @paulishca !!

Regards,

Burni

One more mention. In this setup you should have no import of S3 components onto the client.
The way it works, the client requests an authorization from the Meteor server and proceeds with an XMLHttpRequest() directly to S3.

At this line, you capture the status of the upload (10% …20% …etc)