Integrations

FiveM resource

CDNForge provides an official FiveM server-side resource for uploads, structured logs, and file helpers. Install from the GitHub repository or release ZIP, set scoped API keys as server convars, then call exports from your own resources.

Install

Official distribution: github.com/CDNForge/cdnforge. The repository root is the FiveM resource.

Option 1: Download the release

  1. Open the latest release and download cdnforge.zip.
  2. Extract into your FXServer resources folder so you have resources/cdnforge/fxmanifest.lua.
  3. Add the convars below to server.cfg, then ensure cdnforge.

Option 2: Git clone

bash
cd resources
git clone https://github.com/CDNForge/cdnforge.git
server.cfg
set cdnforge_url "https://app.back2rp.org"

set cdnforge_key_image "cnf_img_..."
set cdnforge_key_video "cnf_vid_..."
set cdnforge_key_audio "cnf_aud_..."
set cdnforge_key_file "cnf_fil_..."
set cdnforge_key_logs "cnf_log_..."

ensure cdnforge

Keys stay on the server

Use server-only set (not replicated setr). Never put API keys in client scripts, NUI, or shared scripts.

Resource order

Start cdnforge before any resource that calls exports.cdnforge. This resource has no client_scripts.

Convars

  • cdnforge_url — CDNForge app origin (for example https://app.back2rp.org). Legacy fallback: gamestack_url.
  • cdnforge_key_image — cnf_img_ (legacy gsk_img_ also accepted)
  • cdnforge_key_video — cnf_vid_
  • cdnforge_key_audio — cnf_aud_
  • cdnforge_key_file — cnf_fil_ for generic uploads, GetFile, and DeleteFile
  • cdnforge_key_logs — cnf_log_
  • cdnforge_api_key — logs-only legacy fallback if cdnforge_key_logs is unset (must still be a logs key). Legacy name: gamestack_api_key.

Keys with the wrong prefix are rejected. Defaults to http://localhost:3000 only when cdnforge_url is empty.

Exports

  • UploadImage(data, metadata, callback, progressCallback)
  • UploadVideo(data, metadata, callback, progressCallback)
  • UploadAudio(data, metadata, callback, progressCallback)
  • UploadFile(data, metadata, callback, progressCallback)
  • LogMessage(level, message, metadata, logFileName)
  • GetFile(fileId, callback)
  • DeleteFile(fileId, callback)

Upload, GetFile, and DeleteFile callbacks use (result, err). On success err is nil. Upload success fields include id, url, publicId, size, mimeType, and originalName. Errors include code, message, and status.

LogMessage is fire-and-forget: it has no callback. Failures are printed to the server console.

Data input

  • Raw binary Lua string
  • Base64 with base64: prefix, a data:...;base64,... URL, or metadata.encoding = "base64"
  • Server-readable path via metadata.path, metadata.fromPath = true (including relative paths), or an absolute path string with / or \

Prefer explicit base64 or path flags. Heuristic base64 only applies to longer ASCII-looking strings and will not decode short raw binary.

Metadata

  • filename — upload file name
  • folder — folder path on the CDNForge side
  • folderId — existing dashboard folder id
  • playerSource — stored with uploads and logs
  • path / fromPath / encoding — input helpers (not sent as API metadata)
  • Any other fields are forwarded as JSON metadata

Upload routing

  • Image ≤ 3.5 MB → POST /api/v1/upload
  • Image > 3.5 MB → /api/v1/upload/chunked/*
  • Video → always /api/v1/upload/chunked/*
  • Audio → always /api/v1/upload/chunked/*
  • Generic file ≤ 3.5 MB → POST /api/v1/file
  • Generic file > 3.5 MB → /api/v1/file/chunked/*

The 3.5 MB cutoff is this resource's client threshold (to stay under typical serverless body limits), not a separate hard limit on the API. Maximum upload size is 100 MB. Chunk size: 4 MB. At most two uploads run at once; extras queue. Full HTTP protocol: large files & chunked uploads.

Chunked uploads

  1. Init returns a server-issued uploadId (and other session fields the client does not need to trust for completion).
  2. Each part is uploaded with multipart fields uploadId, partNumber, and chunk.
  3. Complete sends only { uploadId }. The API loads publicId, storage bucket, and MIME from the upload session. Do not send client-chosen bucket or public id.

Sessions expire after about one hour (server TTL). Common statuses: 404 (missing/wrong org), 409 (already completed), 410 (expired), 413 (too large).

Progress callbacks

Shape: progressCallback(partNumber, totalParts, bytesUploaded, totalBytes).

  • FiveM PerformHttpRequest does not expose true byte-level upload progress during a single request.
  • Direct uploads call (0, 1, 0, size) when the request starts, then (1, 1, size, size) only after a successful response. Failures never report 100%.
  • Chunked uploads report after each finished part except the last. Full progress (bytesUploaded = totalBytes) is reported only after complete succeeds.

Retries and errors

  • HTTP 429 and 5xx are retried up to three times with exponential backoff
  • Other 4xx responses are not retried
  • Missing or wrong-prefix keys return MISSING_KEY to upload/file callbacks

LogMessage

  • Levels: debug, info, warn, error
  • Optional 4th argument logFileName sets the log dataset name (or use metadata.name)
  • Requires a logs key (cnf_log_)
  • Invalid levels are rejected locally and printed to console

GetFile / DeleteFile

This resource uses the file-scoped key (cdnforge_key_file). GetFile returns the file object from GET /api/v1/files/{id}. DeleteFile expects { ok: true } from DELETE /api/v1/files/{id}. Organization and scope checks happen on the server.

Security

  • API keys must remain server-side only
  • Do not use replicated convars or client events to pass keys
  • Use scoped keys: cnf_img_, cnf_vid_, cnf_aud_, cnf_fil_, cnf_log_
  • Validate player actions in your resource before calling uploads
  • Do not trust player-supplied paths for metadata.path / fromPath
  • Chunked sessions are bound server-side; complete uses only the init uploadId
  • For browser or NUI capture without server bytes, use presigned uploads instead of embedding keys in client code

Examples

Call exports from your own server scripts after validating the player action.

LogMessage
exports.cdnforge:LogMessage(
    "info",
    "Player connecting: " .. name,
    { playerSource = src, action = "connect" },
    "player-events"
)
UploadImage
exports.cdnforge:UploadImage(imageBytes, {
    filename = "shot-" .. src .. ".png",
    playerSource = src,
    folder = "screenshots",
}, function(result, err)
    if err then print(err.message) return end
    print(result.url)
end)
UploadVideo from a server path
exports.cdnforge:UploadVideo("/path/on/server/clip.mp4", {
    fromPath = true,
    filename = "clip.mp4",
    folder = "clips",
}, function(result, err)
    if err then print(err.message) return end
    print(result.id)
end, function(part, total, uploaded, totalBytes)
    print(part, total, uploaded, totalBytes)
end)
UploadFile
exports.cdnforge:UploadFile(fileBytes, {
    filename = "backup.zip",
    folder = "backups",
}, function(result, err)
    if err then print(err.message) return end
    print(result.url)
end)
GetFile / DeleteFile
exports.cdnforge:GetFile("fil_...", function(file, err)
    if err then print(err.message) return end
    print(file.url)
end)

exports.cdnforge:DeleteFile("fil_...", function(result, err)
    if err then print(err.message) return end
    print(result.ok)
end)

Updating

  • Download the latest release, replace resources/cdnforge, and restart the resource.
  • Or run git pull inside resources/cdnforge, then restart.

Related