npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

wot-uploader-cf

v0.1.9

Published

A wot-design-uni uploader component for Cloudflare R2 style image uploads.

Downloads

413

Readme

wotUploaderCF

A reusable uni-app upload component built on wot-design-uni for Cloudflare R2 style image uploads.

It wraps wd-upload and handles:

  • image file validation for H5 and mini program runtimes
  • H5 image compression through browser-image-compression, with an injected compressImage override when needed
  • default uni.uploadFile upload to a Cloudflare Worker/R2 endpoint
  • Cloudflare-style upload responses like { "key": "image-key" }
  • optional async media/security check after upload
  • v-model state shaped for post/comment image publishing

Install

pnpm add wot-uploader-cf

vue is a peer dependency. [email protected] is a direct dependency because the component intentionally uses its wd-upload UI.

Basic Usage

<script setup lang="ts">
import { ref } from 'vue'
import { WotUploaderCF, type WotUploaderFile } from 'wot-uploader-cf'

const images = ref<WotUploaderFile[]>([])
</script>

<template>
  <WotUploaderCF
    v-model="images"
    upload-url="https://api.example.com/r2/upload"
    :max-count="9"
  />
</template>

The upload endpoint should accept multipart form data and return:

{
  "key": "abc123"
}

Uploaded items will include imageKey, so you can submit only keys to your API:

const imageKeys = images.value
  .filter(item => item.status === 'success' && item.imageKey)
  .map(item => item.imageKey)

With WeChat Media Check

<WotUploaderCF
  v-model="images"
  upload-url="https://api.example.com/r2/upload"
  security-check-url="https://api.example.com/wechat/imagecheck"
  :openid="openid"
/>

The default security check posts:

{
  "image": "abc123",
  "openid": "user-openid"
}

For custom APIs, pass securityCheckRequest.

Custom Upload Request

<script setup lang="ts">
import type { UploadRequest } from 'wot-uploader-cf'

const uploadRequest: UploadRequest = async ({ filePath, file }) => {
  const imageMediaId = await uploadProductImageForProduct(productId, {
    filePath,
    name: file.name || 'product-image',
    type: file.type || 'application/octet-stream',
    size: file.size || 0,
  })

  return { imageMediaId }
}
</script>

<template>
  <WotUploaderCF
    v-model="images"
    :max-count="1"
    :multiple="false"
    :upload-request="uploadRequest"
  />
</template>

When uploadRequest is provided, the component follows the same flow as the built-in upload:

  • it validates the selected local image
  • it runs compressImage(filePath) first
  • it passes the compressed filePath, name, size, and type into your custom request
  • it skips only the default uni.uploadFile
  • it accepts upload results shaped as { key }, { imageKey }, { imageMediaId }, { id }, JSON strings, or a plain string id

Frontend Presigned R2 Upload

For direct browser-to-R2 uploads, keep secrets on your API. Your app should first request a short-lived upload policy from your backend, then use uploadToPresignedUrl to PUT the file bytes to R2:

import { uploadToPresignedUrl, type UploadRequest } from 'wot-uploader-cf'

const uploadRequest: UploadRequest = async ({ filePath, file }) => {
  const policy = await requestUploadPolicy({
    fileName: file.name || 'image.png',
    mimeType: file.type || 'application/octet-stream',
    fileSize: file.size || 0,
  })

  const body = await fetch(filePath).then(res => res.blob())
  await uploadToPresignedUrl({
    uploadUrl: policy.uploadUrl,
    headers: policy.headers,
    contentType: file.type || 'application/octet-stream',
    body,
  })

  await confirmUpload({
    mediaId: policy.mediaId,
    objectKey: policy.objectKey,
    uploadMode: policy.uploadMode,
  })

  return { imageKey: policy.mediaId }
}

uploadToPresignedUrl intentionally removes any app Authorization header before PUT. R2 signed URLs authenticate through the URL signature, and adding your app bearer token can break CORS/preflight. Empty successful PUT responses are treated as success.

For edit forms, pass existing files into v-model with their public preview URL:

images.value = [{
  url: mediaPublicUrl,
  thumb: mediaPublicUrl,
  status: 'success',
  imageKey: mediaId,
}]

Optional Compression

<WotUploaderCF
  v-model="images"
  :compress-options="{ maxSizeMB: 0.3, maxWidthOrHeight: 1600, initialQuality: 0.8 }"
/>

By default, H5 uploads use browser-image-compression only when the selected image is larger than 300KB or its longest side is larger than 1600px. The default compression target is longest side 1600, initial quality 0.8, target size 0.3MB.

On H5, the default compressor uses browser-image-compression. On WeChat mini program and other uni runtimes with uni.getImageInfo, uni.getFileInfo, and uni.compressImage, it checks the same 300KB / 1600px thresholds and uploads the compressed temp file path when compression is needed. You can still pass compressImage to override the compression pipeline; it receives the local file path and should return the path to upload.

Props

| Prop | Type | Default | Description | | --- | --- | --- | --- | | modelValue | WotUploaderFile[] | [] | Uploaded file state for v-model. | | maxCount | number | 9 | Maximum image count. | | multiple | boolean | true | Whether Wot allows selecting multiple files. Use false for one-image product uploaders. | | variant | 'default' \| 'moments' | 'default' | moments hides the Wot limit counter. | | uploadUrl | string | '/r2/upload' | Default uni.uploadFile target URL. | | uploadName | string | 'file' | Multipart file field name. | | formData | Record<string, unknown> | {} | Extra upload form data. | | headers | Record<string, string> | {} | Upload request headers. | | securityCheckUrl | string | '' | Optional post-upload security check URL. | | openid | string | '' | Optional openid sent to the default security check. | | validateImage | boolean | true | Validate PNG/JPEG file headers before uploading. | | compressOptions | CompressOptions | { maxSizeMB: 0.3, maxWidthOrHeight: 1600, initialQuality: 0.8, useWebWorker: true } | Built-in compression options for H5 and uni mini program runtimes. | | compressImage | (filePath: string) => Promise<string> | undefined | Optional custom compressor. Overrides the built-in compression. | | uploadRequest | UploadRequest | undefined | Fully custom upload implementation. | | securityCheckRequest | SecurityCheckRequest | undefined | Fully custom post-upload check. | | successStatus | number | 200 | Status passed to Wot onSuccess and success-status. |

Events

| Event | Payload | | --- | --- | | update:modelValue | WotUploaderFile[] | | update:uploading | boolean | | upload-success | WotUploaderFile[] | | upload-error | unknown | | beforeUpload | WotUploaderFile[] |

Development

pnpm install
pnpm check
pnpm test
pnpm build