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(orproject:admin)
Request
Multipart form data:
| Field | Type | Description |
|---|---|---|
file | file | The .map or .js.map file |
version | string | Release version (e.g., "1.2.3") |
filename | string | Original 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:
- Go to your project
- Click "Source Maps"
- Enter the version
- Drag and drop
.mapfiles
Matching Source Maps
Source maps are matched to errors by:
- Version - The
releasevalue in SDK init - 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:
- Provider-agnostic blob storage interfaces.
- S3-compatible adapters (AWS S3, R2, MinIO, and similar providers).
- Presigned upload/download URL helpers.
- 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
- Upload during CI/CD - Automate uploads in your build pipeline
- Match versions - Use the same version string in SDK and upload
- Keep source maps private - Use
hidden-source-mapto avoid exposing them in production - Clean up old versions - Delete source maps for old releases you no longer support