Skip to main content

Source Maps API

Upload source maps for stack trace symbolication.

Why Source Maps?

Production JavaScript is minified. Without source maps, stack traces look like:

Error at e.handleClick (main.abc123.js:1:2345)

With source maps:

Error at handleClick (src/components/Button.tsx:42:8)

Endpoints

POST /api/organizations/{organizationId}/projects/{projectId}/source-maps
GET /api/organizations/{organizationId}/projects/{projectId}/source-maps

Authentication

This endpoint supports:

  • dashboard session auth, or
  • project API key with source_maps:write (or project:admin)

Request

Multipart form data:

FieldTypeDescription
filefileThe .map or .js.map file
versionstringRelease version (e.g., "1.2.3")
filenamestringOriginal filename

Example: cURL

curl -X POST \
"https://syntropy.chat/api/organizations/{orgId}/projects/{projectId}/source-maps" \
-H "Authorization: Bearer syn_sk_xxx" \
-F "file=@dist/main.js.map" \
-F "version=1.2.3" \
-F "filename=main.js.map"

Example: SDK API Client

import { createSyntropyApiClient } from "@eclosion-tech/syntropy-node";

const api = createSyntropyApiClient({
baseUrl: "https://syntropy.chat/api",
apiKey: process.env.SYNTROPY_API_KEY,
});

await api.sourceMaps.upload(
{ organizationId: "org_uuid", projectId: "project_uuid" },
{
file,
version: "1.2.3",
filename: "main.js.map",
}
);

const { sourceMaps } = await api.sourceMaps.list({
organizationId: "org_uuid",
projectId: "project_uuid",
});

Example: Build Script

// upload-sourcemaps.js
const fs = require('fs');
const path = require('path');
const FormData = require('form-data');

async function uploadSourceMaps(distPath, version) {
const files = fs.readdirSync(distPath).filter(f => f.endsWith('.map'));

for (const file of files) {
const form = new FormData();
form.append('file', fs.createReadStream(path.join(distPath, file)));
form.append('version', version);
form.append('filename', file);

await fetch(
`https://syntropy.chat/api/organizations/${ORG_ID}/projects/${PROJECT_ID}/source-maps`,
{
method: 'POST',
headers: { Authorization: `Bearer ${API_KEY}` },
body: form,
}
);

console.log(`Uploaded ${file}`);
}
}

uploadSourceMaps('./dist', process.env.npm_package_version);

Dashboard Upload

You can also upload source maps through the dashboard:

  1. Go to your project
  2. Click "Source Maps"
  3. Enter the version
  4. Drag and drop .map files

Matching Source Maps

Source maps are matched to errors by:

  1. Version - The release value in SDK init
  2. Filename - The filename in the stack trace

Ensure your release matches the version used during upload.

Storage Backend For Self-Hosted Deployments

For self-hosted Syntropy or shared internal tooling, use:

@eclosion-tech/syntropy-blob-storage

This package provides:

  1. Provider-agnostic blob storage interfaces.
  2. S3-compatible adapters (AWS S3, R2, MinIO, and similar providers).
  3. Presigned upload/download URL helpers.
  4. UploadThing-style typed route helpers for secure direct uploads.

See Blob Storage Module for setup and examples.

Generating Source Maps

Webpack

// webpack.config.js
module.exports = {
devtool: 'source-map',
// or 'hidden-source-map' to not expose in production
};

Vite

// vite.config.js
export default {
build: {
sourcemap: true,
// or 'hidden' for production
},
};

Next.js

// next.config.js
module.exports = {
productionBrowserSourceMaps: true,
};

Expo/Metro

Source maps are generated automatically. Find them in your build output.

Best Practices

  1. Upload during CI/CD - Automate uploads in your build pipeline
  2. Match versions - Use the same version string in SDK and upload
  3. Keep source maps private - Use hidden-source-map to avoid exposing them in production
  4. Clean up old versions - Delete source maps for old releases you no longer support