Installation

Initialization

import ApexxCloud from "@apexxcloud/sdk-js";

const storage = new ApexxCloud({
  baseUrl: "https://api.apexxcloud.com", // optional
});

Backend Implementation

Your backend needs to implement an endpoint that generates signed URLs. Here’s an example using Node.js:

const ApexxCloud = require("@apexxcloud/sdk-node");

const storage = new ApexxCloud({
  accessKey: process.env.APEXXCLOUD_ACCESS_KEY,
  secretKey: process.env.APEXXCLOUD_SECRET_KEY,
  region: "bucket-region",
  bucket: "bucket-name",
});

app.post("/api/get-signed-url/:type", async (req, res) => {
  try {
    const { type } = req.params;
    const params = req.body; // Contains key, mimeType, totalParts, etc.

    const signedUrl = await storage.getSignedUrl(
      "your-bucket-name",
      params.key,
      {
        type: type,
        ...params,
      }
    );

    res.send(signedUrl);
  } catch (error) {
    res.status(500).send(error.message);
  }
});

The endpoint should handle these types of requests:

TypeDescriptionRequired ParametersExample Response
uploadSingle file uploadkey, mimeTypehttps://api.apexxcloud.com/upload?signature=...
start-multipartStart multipart uploadkey, totalParts, mimeTypehttps://api.apexxcloud.com/multipart/start?signature=...
uploadpartUpload individual partuploadId, partNumber, key, totalPartshttps://api.apexxcloud.com/multipart/{uploadId}/upload?signature=...
completemultipartComplete multipart uploaduploadId, keyhttps://api.apexxcloud.com/multipart/{uploadId}/complete?signature=...
cancelmultipartCancel multipart uploaduploadId, keyhttps://api.apexxcloud.com/multipart/{uploadId}/cancel?signature=...

File Upload

Basic Upload

const controller = new AbortController();

// Function to get signed URLs from your backend
const getSignedUrl = async (type, params) => {
  const response = await fetch(`/api/get-signed-url/${type}`, {
    method: "POST",
    body: JSON.stringify(params),
  });
  return response.text();
};

try {
  const result = await storage.files.upload(getSignedUrl, file, {
    signal: controller.signal,

    onStart: (event) => {
      console.log("Upload started:", event);
      // event.type: 'start'
      // event.timestamp: Start time
      // event.file: {
      //   name: string,
      //   size: number,
      //   type: string
      // }
    },

    onProgress: (event) => {
      console.log(`Upload progress: ${event.progress}%`);
      // event.loaded: Bytes uploaded
      // event.total: Total bytes
      // event.progress: Percentage complete (0-100)
      // event.type: 'progress'
    },

    onComplete: (event) => {
      console.log("Upload completed:", event);
      // event.type: 'complete'
      // event.response: Server response
      // event.timestamp: Completion time
      // event.file: File metadata
    },

    onError: (event) => {
      console.error("Upload failed:", event);
      // event.type: 'error' | 'abort'
      // event.error: Error object
      // event.timestamp: Error time
      // event.status?: HTTP status code (if applicable)
    },
  });
} catch (error) {
  console.error("Upload failed:", error);
}

// To cancel the upload:
controller.abort();

Multipart Upload

const controller = new AbortController();

try {
  const result = await storage.files.uploadMultipart(getSignedUrl, file, {
    signal: controller.signal,
    partSize: 5 * 1024 * 1024, // 5MB chunks (optional)
    concurrency: 3, // Number of concurrent uploads (optional)

    onProgress: (event) => {
      console.log(`Total progress: ${event.progress}%`);
      console.log(
        `Part ${event.part.number} progress: ${event.part.progress}%`
      );
      // event.loaded: Total bytes uploaded
      // event.total: Total file size
      // event.progress: Overall percentage
      // event.part: {
      //   number: Current part number
      //   progress: Current part progress (0-100)
      // }
    },

    onPartComplete: (part) => {
      console.log("Part completed:", part);
      // part.ETag: Part ETag from server
      // part.PartNumber: Completed part number
    },

    onComplete: (event) => {
      console.log("Upload completed:", event);
      // event.type: 'complete'
      // event.response: Server response
      // event.timestamp: Completion time
      // event.file: File metadata
    },

    onError: (event) => {
      console.error("Upload error:", event);
      // event.type: 'error' | 'abort'
      // event.error: Error object
      // event.phase: 'start' | 'upload' | 'complete' | 'cancel'
      // event.status?: HTTP status code (if applicable)
      // event.timestamp: Error time
    },
  });
} catch (error) {
  console.error("Upload failed:", error);
}

Error Handling

The SDK provides detailed error information through the onError callback:

try {
  await storage.files.upload(getSignedUrl, file, {
    onError: (event) => {
      if (event.type === "abort") {
        console.log("Upload was cancelled");
      } else {
        console.error("Upload failed:", event.error.message);
        if (event.status) {
          console.error("HTTP Status:", event.status);
        }
        if (event.phase) {
          // For multipart uploads
          console.error("Failed during phase:", event.phase);
        }
      }
    },
  });
} catch (error) {
  console.error("Upload failed:", error.message);
}

Multipart Upload Phases

The multipart upload process includes different phases where errors might occur:

PhaseDescription
startDuring the initialization of multipart upload
uploadDuring the upload of individual parts
completeDuring the completion of multipart upload
cancelDuring attempt to cancel a failed upload

Image Transformations

The SDK provides a powerful image transformation API that allows you to modify images on-the-fly:

const storage = new ApexxCloud({
  accessId: "your-access-id",
  cdnUrl: "https://cdn.apexxcloud.com", // optional
});

// Basic transformations
const url = storage.transformimage
  .width(800)
  .height(600)
  .crop("fill")
  .quality("auto:good")
  .buildUrl("path/to/image.jpg");

// Chaining multiple transformations
const complexUrl = storage.transformimage
  .width(800)
  .height(600)
  .crop("fill")
  .chain()
  .blur(20)
  .grayscale()
  .buildUrl("path/to/image.jpg");

// Text overlay
const withText = storage.transformimage
  .text("Hello World", {
    font: "Arial",
    size: 32,
    color: "#FFFFFF",
    gravity: "center",
    opacity: 100,
  })
  .buildUrl("path/to/image.jpg");

// Image overlay
const withImage = storage.transformimage
  .overlay("path/to/logo.png", {
    type: "image",
    gravity: "southeast",
    x: 20,
    y: 20,
    width: 100,
    opacity: 80,
  })
  .buildUrl("path/to/image.jpg");

Available Image Transformations

TransformationMethodParametersExample
Widthwidth(value)1-5000px.width(800)
Heightheight(value)1-5000px.height(600)
Cropcrop(mode)’fill’, ‘fit’, ‘scale’.crop('fill')
Qualityquality(value)1-100 or auto modes.quality('auto:good')
Formatformat(type)’auto’, ‘webp’, ‘jpeg’.format('webp')
Blurblur(radius)1-100.blur(20)
Grayscalegrayscale()-.grayscale()
Backgroundbackground(color)hex or ‘transparent’.background('#ff0000')
Borderborder(width, style, color)width, style, color.border(2, 'solid', '#000')
Radiusradius(value)pixels or array.radius(10)
Opacityopacity(value)0-100.opacity(50)
Text Overlaytext(text, options)text, options.text('Hello', options)
Image Overlayoverlay(path, options)path, options.overlay('logo.png', options)

Overlay Options

OptionTypeDescriptionSupported Types
typestring’image’ or ‘video’Video only
gravitystringPosition on targetAll
xnumberHorizontal offsetAll
ynumberVertical offsetAll
scalenumberScale factorImage, Video
widthnumberWidth in pixelsImage, Video
heightnumberHeight in pixelsImage, Video
opacitynumberOpacity (0-100)All
aspectRatiostringAspect ratioImage, Video

Text-specific options:

OptionTypeDescription
fontstringFont family name
sizenumberFont size in pixels
colorstringText color (hex)

Video Transformations

Similar to images, you can transform videos:

// Basic video transformation
const videoUrl = storage.transformvideo
  .width(1280)
  .height(720)
  .format("mp4")
  .buildUrl("path/to/video.mp4");

// Generate video thumbnail
const thumbnailUrl = storage.transformvideo
  .thumbnail(5.0) // Seek to 5 seconds
  .width(400)
  .height(300)
  .crop("fill")
  .buildUrl("path/to/video.mp4");

// Text overlay
const withText = storage.transformvideo
  .text("Hello World", {
    font: "Arial",
    size: 32,
    color: "#FFFFFF",
    gravity: "center",
    opacity: 100,
  })
  .buildUrl("path/to/video.mp4");

// Image overlay
const withImage = storage.transformvideo
  .overlay("path/to/logo.png", {
    type: "image",
    gravity: "southeast",
    x: 20,
    y: 20,
    width: 100,
    opacity: 80,
  })
  .buildUrl("path/to/video.mp4");

// Video overlay (for videos only)
const withVideoOverlay = storage.transformvideo
  .overlay("path/to/overlay.mp4", {
    type: "video",
    gravity: "center",
    width: 200,
    height: 200,
    opacity: 70,
  })
  .buildUrl("path/to/video.mp4");

Available Video Transformations

TransformationMethodParametersExample
Widthwidth(value)1-5000px.width(1280)
Heightheight(value)1-5000px.height(720)
Formatformat(type)’mp4’, ‘webm’, ‘mov’.format('mp4')
Thumbnailthumbnail(seekOffset)seconds.thumbnail(5.0)
Cropcrop(mode)’crop’, ‘fill’, ‘fit’.crop('fill')
Backgroundbackground(color)hex or ‘blur’.background('blur')
Text Overlaytext(text, options)text, options.text('Title', options)
Image Overlayoverlay(path, options)path, options.overlay('logo.png', imageOpts)
Video Overlayoverlay(path, options)path, options.overlay('intro.mp4', videoOpts)

Overlay Options

OptionTypeDescriptionSupported Types
typestring’image’ or ‘video’Video only
gravitystringPosition on targetAll
xnumberHorizontal offsetAll
ynumberVertical offsetAll
scalenumberScale factorImage, Video
widthnumberWidth in pixelsImage, Video
heightnumberHeight in pixelsImage, Video
opacitynumberOpacity (0-100)All
aspectRatiostringAspect ratioImage, Video

Text-specific options:

OptionTypeDescription
fontstringFont family name
sizenumberFont size in pixels
colorstringText color (hex)

Document Transformations

Transform and convert documents:

// Convert document format
const pdfUrl = storage.transformdocument
  .format("pdf")
  .quality("auto:high")
  .buildUrl("path/to/document.docx");

// Generate document thumbnail
const thumbnailUrl = storage.transformdocument
  .thumbnail(1) // First page
  .width(800)
  .height(1200)
  .buildUrl("path/to/document.pdf");

Available Document Transformations

TransformationMethodParametersExample
Formatformat(type)’pdf’, ‘docx’, ‘xlsx’, ‘pptx’.format('pdf')
Qualityquality(mode)’auto:high’, ‘auto:standard’, ‘auto:low’.quality('auto:high')
Compresscompress(mode)’high’, ‘medium’, ‘low’.compress('medium')
Pagespages(range)number or range (‘1-3,5-7’).pages('1-3')
Thumbnailthumbnail(page)Page number.thumbnail(1)

Chaining Transformations

You can chain multiple transformations together using the chain() method:

const url = storage.transformimage
  .width(800)
  .height(600)
  .crop("fill")
  .chain()
  .blur(20)
  .grayscale()
  .buildUrl("path/to/image.jpg");

Each transformation chain is applied sequentially, allowing for complex transformation pipelines.