Skip to content

Commit 4b78e61

Browse files
committed
feat: Initial commit
0 parents  commit 4b78e61

27 files changed

Lines changed: 9280 additions & 0 deletions

.cursorignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
.env*

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
node_modules/
2+
dist/
3+
*.tsbuildinfo
4+
.env*

LICENSE

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2026 Bartosz Prusinowski
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

README.md

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
# @szum-io/sdk
2+
3+
Official TypeScript SDK for [szum](https://szum.io), a chart image API.
4+
5+
Turn a JSON config into an SVG or PNG. Embed it in transactional emails, weekly digests, PDF reports, Slack messages, dashboards – anywhere an `<img>` tag works. No headless browser, no canvas, no client-side JavaScript.
6+
7+
![szum chart example](assets/hero.png)
8+
9+
## Install
10+
11+
```bash
12+
npm install @szum-io/sdk
13+
```
14+
15+
> **Server-side only.** The SDK sends your API key on every request. Never import it into browser code – generate signed URLs server-side and pass them to the client.
16+
17+
## Quick start
18+
19+
```typescript
20+
import { Szum } from "@szum-io/sdk";
21+
22+
const szum = new Szum({ apiKey: process.env.SZUM_KEY! });
23+
24+
const png = await szum.render({
25+
format: "png",
26+
theme: "editorial",
27+
title: "Quarterly Revenue",
28+
subtitle: "By region, FY 2025",
29+
marks: [
30+
{
31+
type: "barY",
32+
data: [
33+
{ x: "Q1", y: 4.2, region: "Americas" },
34+
{ x: "Q2", y: 5.1, region: "Americas" },
35+
{ x: "Q1", y: 2.1, region: "EMEA" },
36+
{ x: "Q2", y: 2.8, region: "EMEA" },
37+
],
38+
fill: "region",
39+
},
40+
],
41+
});
42+
```
43+
44+
## A few marks
45+
46+
| barY | line | dot |
47+
| ----------------------- | ------------------------ | ---------------------- |
48+
| ![barY](assets/bar.png) | ![line](assets/line.png) | ![dot](assets/dot.png) |
49+
50+
## Signed URLs
51+
52+
Generate authenticated `<img>` embed URLs (Pro plan):
53+
54+
```typescript
55+
const url = await szum.signedUrl({
56+
format: "svg",
57+
theme: "editorial",
58+
marks: [
59+
{
60+
type: "barY",
61+
data: [
62+
{ x: "Q1", y: 42 },
63+
{ x: "Q2", y: 58 },
64+
],
65+
},
66+
],
67+
});
68+
69+
// Use in HTML: <img src={url} />
70+
```
71+
72+
## Configuration
73+
74+
```typescript
75+
const szum = new Szum({
76+
apiKey: process.env.SZUM_KEY!,
77+
timeout: 30_000, // ms, default 30s
78+
maxRetries: 2, // default 2; retries 429, 502, 503, 504, and network errors
79+
});
80+
```
81+
82+
Every method accepts an optional second argument for per-call overrides:
83+
84+
```typescript
85+
const controller = new AbortController();
86+
87+
await szum.render(config, {
88+
timeout: 60_000, // override client timeout
89+
signal: controller.signal, // caller-initiated cancellation
90+
});
91+
```
92+
93+
Set `SZUM_DEBUG=true` in your environment to log every request, response status, timing, and retry attempt to stderr.
94+
95+
## Error handling
96+
97+
Errors are typed by category. Match by subclass instead of status codes:
98+
99+
```typescript
100+
import {
101+
Szum,
102+
SzumError,
103+
SzumAuthenticationError,
104+
SzumRateLimitError,
105+
SzumInvalidRequestError,
106+
SzumConnectionError,
107+
} from "@szum-io/sdk";
108+
109+
try {
110+
await szum.render(config);
111+
} catch (err) {
112+
if (err instanceof SzumAuthenticationError) {
113+
// 401 – bad or missing API key
114+
} else if (err instanceof SzumRateLimitError) {
115+
// 429 – wait err.retryAfter seconds
116+
} else if (err instanceof SzumInvalidRequestError) {
117+
// 400 / 413 – bad config
118+
} else if (err instanceof SzumConnectionError) {
119+
// timeout or network error
120+
} else if (err instanceof SzumError) {
121+
console.error(err.code); // "api_error", "invalid_request", etc.
122+
console.error(err.message);
123+
console.error(err.status); // HTTP status
124+
console.error(err.retryAfter); // seconds (on 429)
125+
console.error(err.requestId); // from x-vercel-id – include in support tickets
126+
}
127+
}
128+
```
129+
130+
All errors serialize cleanly via `JSON.stringify(err)` (they implement `toJSON`), so they work with Sentry, Datadog, and standard loggers.
131+
132+
## Exports
133+
134+
| Export | Description |
135+
| ------------------------- | ------------------------------------------------------------------- |
136+
| `Szum` | Client class (`render`, `signedUrl`) |
137+
| `SzumOptions` | Constructor options (`apiKey`, `timeout`, `maxRetries`, …) |
138+
| `RequestOptions` | Per-call options (`timeout`, `signal`) |
139+
| `SzumError` | Base error (`code`, `status`, `message`, `retryAfter`, `requestId`) |
140+
| `SzumAuthenticationError` | 401 |
141+
| `SzumPermissionError` | 403 |
142+
| `SzumInvalidRequestError` | 400 / 413 |
143+
| `SzumRateLimitError` | 429 |
144+
| `SzumAPIError` | 5xx |
145+
| `SzumConnectionError` | Timeout / network |
146+
| `ChartConfig` | Config type for SDK methods (`version` optional) |
147+
| `ChartConfigInput` | Full config type including required `version` |
148+
| `SCHEMA_VERSION` | Schema version this SDK was built against |
149+
150+
## Documentation
151+
152+
Full reference at [szum.io/docs](https://szum.io/docs).

assets/bar.png

46.3 KB
Loading

assets/dot.png

60.7 KB
Loading

assets/hero.png

65.2 KB
Loading

assets/line.png

59.6 KB
Loading

knip.config.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import type { KnipConfig } from "knip";
2+
3+
const config: KnipConfig = {};
4+
5+
export default config;

package.json

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
{
2+
"name": "@szum-io/sdk",
3+
"version": "0.0.0",
4+
"description": "Render charts from a JSON config – SVG or PNG, embeddable in emails, PDFs, Slack, or any <img> tag. Official TypeScript SDK for szum.",
5+
"type": "module",
6+
"main": "./dist/index.cjs",
7+
"module": "./dist/index.js",
8+
"types": "./dist/index.d.ts",
9+
"exports": {
10+
".": {
11+
"import": {
12+
"types": "./dist/index.d.ts",
13+
"default": "./dist/index.js"
14+
},
15+
"require": {
16+
"types": "./dist/index.d.cts",
17+
"default": "./dist/index.cjs"
18+
}
19+
}
20+
},
21+
"files": [
22+
"dist",
23+
"README.md",
24+
"LICENSE"
25+
],
26+
"publishConfig": {
27+
"access": "public"
28+
},
29+
"sideEffects": false,
30+
"author": "Bartosz Prusinowski",
31+
"license": "MIT",
32+
"repository": {
33+
"type": "git",
34+
"url": "https://github.com/szum-io/sdk.git"
35+
},
36+
"bugs": {
37+
"url": "https://github.com/szum-io/sdk/issues"
38+
},
39+
"homepage": "https://szum.io/docs",
40+
"keywords": [
41+
"chart",
42+
"charts",
43+
"chart-image",
44+
"chart-api",
45+
"chart-image-api",
46+
"chart-generator",
47+
"chart-in-email",
48+
"email-chart",
49+
"data-visualization",
50+
"dataviz",
51+
"svg",
52+
"png",
53+
"server-side-rendering",
54+
"grammar-of-graphics",
55+
"typescript",
56+
"szum"
57+
],
58+
"engines": {
59+
"node": ">=22"
60+
},
61+
"browser": false,
62+
"scripts": {
63+
"build": "tsup",
64+
"typecheck": "tsc --noEmit",
65+
"test": "vitest run",
66+
"knip": "knip",
67+
"version": "node scripts/sync-version.mjs && git add src/version.ts",
68+
"prepublishOnly": "node scripts/check-version.mjs && pnpm test && pnpm typecheck && pnpm build",
69+
"postpublish": "git push && git push --tags"
70+
},
71+
"devDependencies": {
72+
"@types/node": "^25.6.0",
73+
"knip": "^6.4.1",
74+
"tsup": "^8.5.1",
75+
"typescript": "^6.0.3",
76+
"vitest": "^4.1.4"
77+
},
78+
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
79+
}

0 commit comments

Comments
 (0)