@shotapi/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # ShotAPI SDK
2
+
3
+ Official Node.js SDK for [ShotAPI](https://shotapi.dev) - Screenshot API for Developers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @shotapi/sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import ShotAPI from '@shotapi/sdk';
15
+
16
+ const client = new ShotAPI({ apiKey: 'your-api-key' });
17
+
18
+ // Capture a screenshot
19
+ const result = await client.screenshot({
20
+ url: 'https://example.com'
21
+ });
22
+
23
+ console.log(result.url); // URL to the screenshot
24
+ ```
25
+
26
+ ## Features
27
+
28
+ - Full TypeScript support
29
+ - Automatic retries with exponential backoff
30
+ - Device presets (iPhone, iPad, Android, etc.)
31
+ - Batch screenshot capture
32
+ - Save directly to file
33
+ - Get screenshot as Buffer
34
+
35
+ ## Usage Examples
36
+
37
+ ### Basic Screenshot
38
+
39
+ ```typescript
40
+ const result = await client.screenshot({
41
+ url: 'https://example.com',
42
+ width: 1280,
43
+ height: 720
44
+ });
45
+ ```
46
+
47
+ ### Full Page Screenshot
48
+
49
+ ```typescript
50
+ const result = await client.screenshot({
51
+ url: 'https://example.com',
52
+ fullPage: true
53
+ });
54
+ ```
55
+
56
+ ### Device Preset
57
+
58
+ ```typescript
59
+ // Use iPhone 14 Pro dimensions
60
+ const result = await client.screenshot({
61
+ url: 'https://example.com',
62
+ device: 'iphone-14-pro'
63
+ });
64
+
65
+ // Available presets:
66
+ // desktop, laptop, tablet, mobile,
67
+ // iphone-14, iphone-14-pro, iphone-14-pro-max,
68
+ // ipad, ipad-pro, galaxy-s23, pixel-7
69
+ ```
70
+
71
+ ### Different Formats
72
+
73
+ ```typescript
74
+ // JPEG with quality
75
+ const jpeg = await client.screenshot({
76
+ url: 'https://example.com',
77
+ format: 'jpeg',
78
+ quality: 90
79
+ });
80
+
81
+ // WebP
82
+ const webp = await client.screenshot({
83
+ url: 'https://example.com',
84
+ format: 'webp',
85
+ quality: 85
86
+ });
87
+
88
+ // PDF
89
+ const pdf = await client.screenshot({
90
+ url: 'https://example.com',
91
+ format: 'pdf',
92
+ fullPage: true
93
+ });
94
+ ```
95
+
96
+ ### Wait for Content
97
+
98
+ ```typescript
99
+ // Wait for a specific element
100
+ const result = await client.screenshot({
101
+ url: 'https://example.com',
102
+ waitForSelector: '.main-content'
103
+ });
104
+
105
+ // Add delay before capture
106
+ const result2 = await client.screenshot({
107
+ url: 'https://example.com',
108
+ delay: 2000 // 2 seconds
109
+ });
110
+ ```
111
+
112
+ ### Premium Features
113
+
114
+ ```typescript
115
+ // Element screenshot
116
+ const element = await client.screenshot({
117
+ url: 'https://example.com',
118
+ selector: '#hero-section'
119
+ });
120
+
121
+ // Inject custom CSS
122
+ const styled = await client.screenshot({
123
+ url: 'https://example.com',
124
+ css: 'body { background: #f0f0f0; }'
125
+ });
126
+
127
+ // Execute JavaScript before capture
128
+ const dynamic = await client.screenshot({
129
+ url: 'https://example.com',
130
+ js: 'document.querySelector(".popup").remove();'
131
+ });
132
+
133
+ // Block ads
134
+ const clean = await client.screenshot({
135
+ url: 'https://example.com',
136
+ blockAds: true,
137
+ hideCookieBanners: true
138
+ });
139
+
140
+ // Generate thumbnail
141
+ const thumb = await client.screenshot({
142
+ url: 'https://example.com',
143
+ thumbnailWidth: 300
144
+ });
145
+ ```
146
+
147
+ ### Save to File
148
+
149
+ ```typescript
150
+ await client.screenshotToFile(
151
+ { url: 'https://example.com' },
152
+ './screenshot.png'
153
+ );
154
+ ```
155
+
156
+ ### Get as Buffer
157
+
158
+ ```typescript
159
+ const buffer = await client.screenshotBuffer({
160
+ url: 'https://example.com'
161
+ });
162
+
163
+ // Use buffer (e.g., upload to S3, send in response, etc.)
164
+ ```
165
+
166
+ ### Batch Screenshots
167
+
168
+ ```typescript
169
+ const urls = [
170
+ 'https://example.com',
171
+ 'https://google.com',
172
+ 'https://github.com'
173
+ ];
174
+
175
+ const results = await client.batch(urls, {
176
+ width: 1280,
177
+ height: 720
178
+ });
179
+ ```
180
+
181
+ ## Configuration
182
+
183
+ ```typescript
184
+ const client = new ShotAPI({
185
+ apiKey: 'your-api-key', // Required
186
+ baseUrl: 'https://shotapi.dev', // Optional (default)
187
+ timeout: 30000, // Request timeout in ms (default: 30000)
188
+ retries: 2 // Retry attempts (default: 2)
189
+ });
190
+ ```
191
+
192
+ ## Error Handling
193
+
194
+ ```typescript
195
+ import ShotAPI, { ShotAPIException } from '@shotapi/sdk';
196
+
197
+ try {
198
+ const result = await client.screenshot({
199
+ url: 'https://example.com'
200
+ });
201
+ } catch (error) {
202
+ if (error instanceof ShotAPIException) {
203
+ console.error('API Error:', error.message);
204
+ console.error('Error Code:', error.code);
205
+ console.error('Status Code:', error.statusCode);
206
+ }
207
+ }
208
+ ```
209
+
210
+ ## TypeScript
211
+
212
+ The SDK is written in TypeScript and includes full type definitions:
213
+
214
+ ```typescript
215
+ import ShotAPI, {
216
+ ScreenshotOptions,
217
+ ScreenshotResponse,
218
+ DevicePreset,
219
+ ImageFormat,
220
+ ShotAPIConfig
221
+ } from '@shotapi/sdk';
222
+ ```
223
+
224
+ ## Response Format
225
+
226
+ ```typescript
227
+ interface ScreenshotResponse {
228
+ url: string; // URL to the screenshot
229
+ thumbnailUrl?: string; // Thumbnail URL (if requested)
230
+ metadata: {
231
+ width: number;
232
+ height: number;
233
+ format: string;
234
+ size: number; // File size in bytes
235
+ };
236
+ creditsUsed: number;
237
+ creditsRemaining: number;
238
+ }
239
+ ```
240
+
241
+ ## Device Presets
242
+
243
+ | Preset | Width | Height | Mobile | Scale |
244
+ |--------|-------|--------|--------|-------|
245
+ | desktop | 1920 | 1080 | No | 1 |
246
+ | laptop | 1366 | 768 | No | 1 |
247
+ | tablet | 768 | 1024 | Yes | 2 |
248
+ | mobile | 375 | 812 | Yes | 3 |
249
+ | iphone-14 | 390 | 844 | Yes | 3 |
250
+ | iphone-14-pro | 393 | 852 | Yes | 3 |
251
+ | iphone-14-pro-max | 430 | 932 | Yes | 3 |
252
+ | ipad | 810 | 1080 | Yes | 2 |
253
+ | ipad-pro | 1024 | 1366 | Yes | 2 |
254
+ | galaxy-s23 | 360 | 780 | Yes | 3 |
255
+ | pixel-7 | 412 | 915 | Yes | 2.625 |
256
+
257
+ ## License
258
+
259
+ MIT
260
+
261
+ ## Links
262
+
263
+ - [Website](https://shotapi.dev)
264
+ - [Documentation](https://shotapi.dev/docs)
265
+ - [API Reference](https://shotapi.dev/docs/api)
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Device presets for responsive screenshots
3
+ */
4
+ type DevicePreset = 'desktop' | 'laptop' | 'tablet' | 'mobile' | 'iphone-14' | 'iphone-14-pro' | 'iphone-14-pro-max' | 'ipad' | 'ipad-pro' | 'galaxy-s23' | 'pixel-7';
5
+ /**
6
+ * Output format for screenshots
7
+ */
8
+ type ImageFormat = 'png' | 'jpeg' | 'webp' | 'pdf';
9
+ /**
10
+ * Screenshot options
11
+ */
12
+ interface ScreenshotOptions {
13
+ /**
14
+ * Target URL to capture
15
+ */
16
+ url: string;
17
+ /**
18
+ * Viewport width in pixels (default: 1280)
19
+ */
20
+ width?: number;
21
+ /**
22
+ * Viewport height in pixels (default: 720)
23
+ */
24
+ height?: number;
25
+ /**
26
+ * Use a device preset instead of custom width/height
27
+ */
28
+ device?: DevicePreset;
29
+ /**
30
+ * Whether to capture full page (default: false)
31
+ */
32
+ fullPage?: boolean;
33
+ /**
34
+ * Output format (default: 'png')
35
+ */
36
+ format?: ImageFormat;
37
+ /**
38
+ * Image quality 1-100 (only for jpeg/webp, default: 80)
39
+ */
40
+ quality?: number;
41
+ /**
42
+ * Device scale factor (default: 1)
43
+ */
44
+ scale?: number;
45
+ /**
46
+ * Delay in milliseconds before capture (default: 0)
47
+ */
48
+ delay?: number;
49
+ /**
50
+ * Wait for a specific CSS selector to appear
51
+ */
52
+ waitForSelector?: string;
53
+ /**
54
+ * CSS selector to capture (element screenshot)
55
+ * Premium feature
56
+ */
57
+ selector?: string;
58
+ /**
59
+ * Custom CSS to inject before capture
60
+ * Premium feature
61
+ */
62
+ css?: string;
63
+ /**
64
+ * Custom JavaScript to execute before capture
65
+ * Premium feature
66
+ */
67
+ js?: string;
68
+ /**
69
+ * Block ads and trackers (default: false)
70
+ * Premium feature
71
+ */
72
+ blockAds?: boolean;
73
+ /**
74
+ * Hide cookie banners (default: false)
75
+ * Premium feature
76
+ */
77
+ hideCookieBanners?: boolean;
78
+ /**
79
+ * Dark mode (default: false)
80
+ */
81
+ darkMode?: boolean;
82
+ /**
83
+ * Emulate mobile device (default: false)
84
+ */
85
+ mobile?: boolean;
86
+ /**
87
+ * Generate thumbnail with specified width
88
+ * Premium feature
89
+ */
90
+ thumbnailWidth?: number;
91
+ }
92
+ /**
93
+ * Screenshot response
94
+ */
95
+ interface ScreenshotResponse {
96
+ /**
97
+ * URL to the captured screenshot
98
+ */
99
+ url: string;
100
+ /**
101
+ * Thumbnail URL (if thumbnailWidth was specified)
102
+ */
103
+ thumbnailUrl?: string;
104
+ /**
105
+ * Screenshot metadata
106
+ */
107
+ metadata: {
108
+ width: number;
109
+ height: number;
110
+ format: ImageFormat;
111
+ size: number;
112
+ };
113
+ /**
114
+ * Credits used for this request
115
+ */
116
+ creditsUsed: number;
117
+ /**
118
+ * Remaining credits
119
+ */
120
+ creditsRemaining: number;
121
+ }
122
+ /**
123
+ * API Error response
124
+ */
125
+ interface ShotAPIError {
126
+ error: string;
127
+ code?: string;
128
+ details?: string;
129
+ }
130
+ /**
131
+ * SDK Configuration
132
+ */
133
+ interface ShotAPIConfig {
134
+ /**
135
+ * Your ShotAPI API key
136
+ */
137
+ apiKey: string;
138
+ /**
139
+ * Base URL for the API (default: https://shotapi.dev)
140
+ */
141
+ baseUrl?: string;
142
+ /**
143
+ * Request timeout in milliseconds (default: 30000)
144
+ */
145
+ timeout?: number;
146
+ /**
147
+ * Number of retry attempts on failure (default: 2)
148
+ */
149
+ retries?: number;
150
+ }
151
+
152
+ /**
153
+ * ShotAPI Error class
154
+ */
155
+ declare class ShotAPIException extends Error {
156
+ readonly code?: string;
157
+ readonly details?: string;
158
+ readonly statusCode?: number;
159
+ constructor(message: string, code?: string, details?: string, statusCode?: number);
160
+ }
161
+ /**
162
+ * ShotAPI - Screenshot API SDK
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * import ShotAPI from 'shotapi';
167
+ *
168
+ * const client = new ShotAPI({ apiKey: 'your-api-key' });
169
+ *
170
+ * // Basic screenshot
171
+ * const result = await client.screenshot({ url: 'https://example.com' });
172
+ * console.log(result.url);
173
+ *
174
+ * // Full page screenshot with custom options
175
+ * const result2 = await client.screenshot({
176
+ * url: 'https://example.com',
177
+ * fullPage: true,
178
+ * format: 'jpeg',
179
+ * quality: 90,
180
+ * });
181
+ * ```
182
+ */
183
+ declare class ShotAPI {
184
+ private readonly apiKey;
185
+ private readonly baseUrl;
186
+ private readonly timeout;
187
+ private readonly retries;
188
+ constructor(config: ShotAPIConfig);
189
+ /**
190
+ * Capture a screenshot of a URL
191
+ *
192
+ * @param options - Screenshot options
193
+ * @returns Screenshot response with URL and metadata
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const result = await client.screenshot({
198
+ * url: 'https://example.com',
199
+ * width: 1280,
200
+ * height: 720,
201
+ * fullPage: true,
202
+ * });
203
+ * ```
204
+ */
205
+ screenshot(options: ScreenshotOptions): Promise<ScreenshotResponse>;
206
+ /**
207
+ * Capture a screenshot and return as a Buffer
208
+ *
209
+ * @param options - Screenshot options
210
+ * @returns Screenshot as a Buffer
211
+ */
212
+ screenshotBuffer(options: ScreenshotOptions): Promise<Buffer>;
213
+ /**
214
+ * Capture a screenshot and save to a file
215
+ *
216
+ * @param options - Screenshot options
217
+ * @param filePath - Path to save the screenshot
218
+ */
219
+ screenshotToFile(options: ScreenshotOptions, filePath: string): Promise<ScreenshotResponse>;
220
+ /**
221
+ * Capture multiple screenshots in batch
222
+ *
223
+ * @param urls - Array of URLs to capture
224
+ * @param options - Common options for all screenshots
225
+ * @returns Array of screenshot responses
226
+ */
227
+ batch(urls: string[], options?: Omit<ScreenshotOptions, 'url'>): Promise<ScreenshotResponse[]>;
228
+ /**
229
+ * Get device preset dimensions
230
+ *
231
+ * @param device - Device preset name
232
+ * @returns Device dimensions
233
+ */
234
+ static getDevicePreset(device: DevicePreset): {
235
+ width: number;
236
+ height: number;
237
+ mobile: boolean;
238
+ scale: number;
239
+ };
240
+ /**
241
+ * List all available device presets
242
+ */
243
+ static get devicePresets(): DevicePreset[];
244
+ /**
245
+ * Build URL parameters from options
246
+ */
247
+ private buildParams;
248
+ /**
249
+ * Make an API request with retries
250
+ */
251
+ private request;
252
+ /**
253
+ * Fetch a URL as Buffer
254
+ */
255
+ private fetchBuffer;
256
+ /**
257
+ * Sleep for specified milliseconds
258
+ */
259
+ private sleep;
260
+ }
261
+
262
+ export { type DevicePreset, type ImageFormat, type ScreenshotOptions, type ScreenshotResponse, ShotAPI, type ShotAPIConfig, type ShotAPIError, ShotAPIException, ShotAPI as default };
@@ -0,0 +1,262 @@
1
+ /**
2
+ * Device presets for responsive screenshots
3
+ */
4
+ type DevicePreset = 'desktop' | 'laptop' | 'tablet' | 'mobile' | 'iphone-14' | 'iphone-14-pro' | 'iphone-14-pro-max' | 'ipad' | 'ipad-pro' | 'galaxy-s23' | 'pixel-7';
5
+ /**
6
+ * Output format for screenshots
7
+ */
8
+ type ImageFormat = 'png' | 'jpeg' | 'webp' | 'pdf';
9
+ /**
10
+ * Screenshot options
11
+ */
12
+ interface ScreenshotOptions {
13
+ /**
14
+ * Target URL to capture
15
+ */
16
+ url: string;
17
+ /**
18
+ * Viewport width in pixels (default: 1280)
19
+ */
20
+ width?: number;
21
+ /**
22
+ * Viewport height in pixels (default: 720)
23
+ */
24
+ height?: number;
25
+ /**
26
+ * Use a device preset instead of custom width/height
27
+ */
28
+ device?: DevicePreset;
29
+ /**
30
+ * Whether to capture full page (default: false)
31
+ */
32
+ fullPage?: boolean;
33
+ /**
34
+ * Output format (default: 'png')
35
+ */
36
+ format?: ImageFormat;
37
+ /**
38
+ * Image quality 1-100 (only for jpeg/webp, default: 80)
39
+ */
40
+ quality?: number;
41
+ /**
42
+ * Device scale factor (default: 1)
43
+ */
44
+ scale?: number;
45
+ /**
46
+ * Delay in milliseconds before capture (default: 0)
47
+ */
48
+ delay?: number;
49
+ /**
50
+ * Wait for a specific CSS selector to appear
51
+ */
52
+ waitForSelector?: string;
53
+ /**
54
+ * CSS selector to capture (element screenshot)
55
+ * Premium feature
56
+ */
57
+ selector?: string;
58
+ /**
59
+ * Custom CSS to inject before capture
60
+ * Premium feature
61
+ */
62
+ css?: string;
63
+ /**
64
+ * Custom JavaScript to execute before capture
65
+ * Premium feature
66
+ */
67
+ js?: string;
68
+ /**
69
+ * Block ads and trackers (default: false)
70
+ * Premium feature
71
+ */
72
+ blockAds?: boolean;
73
+ /**
74
+ * Hide cookie banners (default: false)
75
+ * Premium feature
76
+ */
77
+ hideCookieBanners?: boolean;
78
+ /**
79
+ * Dark mode (default: false)
80
+ */
81
+ darkMode?: boolean;
82
+ /**
83
+ * Emulate mobile device (default: false)
84
+ */
85
+ mobile?: boolean;
86
+ /**
87
+ * Generate thumbnail with specified width
88
+ * Premium feature
89
+ */
90
+ thumbnailWidth?: number;
91
+ }
92
+ /**
93
+ * Screenshot response
94
+ */
95
+ interface ScreenshotResponse {
96
+ /**
97
+ * URL to the captured screenshot
98
+ */
99
+ url: string;
100
+ /**
101
+ * Thumbnail URL (if thumbnailWidth was specified)
102
+ */
103
+ thumbnailUrl?: string;
104
+ /**
105
+ * Screenshot metadata
106
+ */
107
+ metadata: {
108
+ width: number;
109
+ height: number;
110
+ format: ImageFormat;
111
+ size: number;
112
+ };
113
+ /**
114
+ * Credits used for this request
115
+ */
116
+ creditsUsed: number;
117
+ /**
118
+ * Remaining credits
119
+ */
120
+ creditsRemaining: number;
121
+ }
122
+ /**
123
+ * API Error response
124
+ */
125
+ interface ShotAPIError {
126
+ error: string;
127
+ code?: string;
128
+ details?: string;
129
+ }
130
+ /**
131
+ * SDK Configuration
132
+ */
133
+ interface ShotAPIConfig {
134
+ /**
135
+ * Your ShotAPI API key
136
+ */
137
+ apiKey: string;
138
+ /**
139
+ * Base URL for the API (default: https://shotapi.dev)
140
+ */
141
+ baseUrl?: string;
142
+ /**
143
+ * Request timeout in milliseconds (default: 30000)
144
+ */
145
+ timeout?: number;
146
+ /**
147
+ * Number of retry attempts on failure (default: 2)
148
+ */
149
+ retries?: number;
150
+ }
151
+
152
+ /**
153
+ * ShotAPI Error class
154
+ */
155
+ declare class ShotAPIException extends Error {
156
+ readonly code?: string;
157
+ readonly details?: string;
158
+ readonly statusCode?: number;
159
+ constructor(message: string, code?: string, details?: string, statusCode?: number);
160
+ }
161
+ /**
162
+ * ShotAPI - Screenshot API SDK
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * import ShotAPI from 'shotapi';
167
+ *
168
+ * const client = new ShotAPI({ apiKey: 'your-api-key' });
169
+ *
170
+ * // Basic screenshot
171
+ * const result = await client.screenshot({ url: 'https://example.com' });
172
+ * console.log(result.url);
173
+ *
174
+ * // Full page screenshot with custom options
175
+ * const result2 = await client.screenshot({
176
+ * url: 'https://example.com',
177
+ * fullPage: true,
178
+ * format: 'jpeg',
179
+ * quality: 90,
180
+ * });
181
+ * ```
182
+ */
183
+ declare class ShotAPI {
184
+ private readonly apiKey;
185
+ private readonly baseUrl;
186
+ private readonly timeout;
187
+ private readonly retries;
188
+ constructor(config: ShotAPIConfig);
189
+ /**
190
+ * Capture a screenshot of a URL
191
+ *
192
+ * @param options - Screenshot options
193
+ * @returns Screenshot response with URL and metadata
194
+ *
195
+ * @example
196
+ * ```typescript
197
+ * const result = await client.screenshot({
198
+ * url: 'https://example.com',
199
+ * width: 1280,
200
+ * height: 720,
201
+ * fullPage: true,
202
+ * });
203
+ * ```
204
+ */
205
+ screenshot(options: ScreenshotOptions): Promise<ScreenshotResponse>;
206
+ /**
207
+ * Capture a screenshot and return as a Buffer
208
+ *
209
+ * @param options - Screenshot options
210
+ * @returns Screenshot as a Buffer
211
+ */
212
+ screenshotBuffer(options: ScreenshotOptions): Promise<Buffer>;
213
+ /**
214
+ * Capture a screenshot and save to a file
215
+ *
216
+ * @param options - Screenshot options
217
+ * @param filePath - Path to save the screenshot
218
+ */
219
+ screenshotToFile(options: ScreenshotOptions, filePath: string): Promise<ScreenshotResponse>;
220
+ /**
221
+ * Capture multiple screenshots in batch
222
+ *
223
+ * @param urls - Array of URLs to capture
224
+ * @param options - Common options for all screenshots
225
+ * @returns Array of screenshot responses
226
+ */
227
+ batch(urls: string[], options?: Omit<ScreenshotOptions, 'url'>): Promise<ScreenshotResponse[]>;
228
+ /**
229
+ * Get device preset dimensions
230
+ *
231
+ * @param device - Device preset name
232
+ * @returns Device dimensions
233
+ */
234
+ static getDevicePreset(device: DevicePreset): {
235
+ width: number;
236
+ height: number;
237
+ mobile: boolean;
238
+ scale: number;
239
+ };
240
+ /**
241
+ * List all available device presets
242
+ */
243
+ static get devicePresets(): DevicePreset[];
244
+ /**
245
+ * Build URL parameters from options
246
+ */
247
+ private buildParams;
248
+ /**
249
+ * Make an API request with retries
250
+ */
251
+ private request;
252
+ /**
253
+ * Fetch a URL as Buffer
254
+ */
255
+ private fetchBuffer;
256
+ /**
257
+ * Sleep for specified milliseconds
258
+ */
259
+ private sleep;
260
+ }
261
+
262
+ export { type DevicePreset, type ImageFormat, type ScreenshotOptions, type ScreenshotResponse, ShotAPI, type ShotAPIConfig, type ShotAPIError, ShotAPIException, ShotAPI as default };
package/dist/index.js ADDED
@@ -0,0 +1,245 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ ShotAPI: () => ShotAPI,
34
+ ShotAPIException: () => ShotAPIException,
35
+ default: () => index_default
36
+ });
37
+ module.exports = __toCommonJS(index_exports);
38
+ var ShotAPIException = class extends Error {
39
+ constructor(message, code, details, statusCode) {
40
+ super(message);
41
+ this.name = "ShotAPIException";
42
+ this.code = code;
43
+ this.details = details;
44
+ this.statusCode = statusCode;
45
+ }
46
+ };
47
+ var DEVICE_PRESETS = {
48
+ desktop: { width: 1920, height: 1080, mobile: false, scale: 1 },
49
+ laptop: { width: 1366, height: 768, mobile: false, scale: 1 },
50
+ tablet: { width: 768, height: 1024, mobile: true, scale: 2 },
51
+ mobile: { width: 375, height: 812, mobile: true, scale: 3 },
52
+ "iphone-14": { width: 390, height: 844, mobile: true, scale: 3 },
53
+ "iphone-14-pro": { width: 393, height: 852, mobile: true, scale: 3 },
54
+ "iphone-14-pro-max": { width: 430, height: 932, mobile: true, scale: 3 },
55
+ "ipad": { width: 810, height: 1080, mobile: true, scale: 2 },
56
+ "ipad-pro": { width: 1024, height: 1366, mobile: true, scale: 2 },
57
+ "galaxy-s23": { width: 360, height: 780, mobile: true, scale: 3 },
58
+ "pixel-7": { width: 412, height: 915, mobile: true, scale: 2.625 }
59
+ };
60
+ var ShotAPI = class {
61
+ constructor(config) {
62
+ if (!config.apiKey) {
63
+ throw new ShotAPIException("API key is required");
64
+ }
65
+ this.apiKey = config.apiKey;
66
+ this.baseUrl = config.baseUrl || "https://shotapi.dev";
67
+ this.timeout = config.timeout || 3e4;
68
+ this.retries = config.retries ?? 2;
69
+ }
70
+ /**
71
+ * Capture a screenshot of a URL
72
+ *
73
+ * @param options - Screenshot options
74
+ * @returns Screenshot response with URL and metadata
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const result = await client.screenshot({
79
+ * url: 'https://example.com',
80
+ * width: 1280,
81
+ * height: 720,
82
+ * fullPage: true,
83
+ * });
84
+ * ```
85
+ */
86
+ async screenshot(options) {
87
+ if (!options.url) {
88
+ throw new ShotAPIException("URL is required");
89
+ }
90
+ const params = this.buildParams(options);
91
+ return this.request("/api/v1/screenshot", params);
92
+ }
93
+ /**
94
+ * Capture a screenshot and return as a Buffer
95
+ *
96
+ * @param options - Screenshot options
97
+ * @returns Screenshot as a Buffer
98
+ */
99
+ async screenshotBuffer(options) {
100
+ const response = await this.screenshot(options);
101
+ const imageResponse = await fetch(response.url);
102
+ if (!imageResponse.ok) {
103
+ throw new ShotAPIException("Failed to fetch screenshot image");
104
+ }
105
+ const arrayBuffer = await imageResponse.arrayBuffer();
106
+ return Buffer.from(arrayBuffer);
107
+ }
108
+ /**
109
+ * Capture a screenshot and save to a file
110
+ *
111
+ * @param options - Screenshot options
112
+ * @param filePath - Path to save the screenshot
113
+ */
114
+ async screenshotToFile(options, filePath) {
115
+ const response = await this.screenshot(options);
116
+ const buffer = await this.fetchBuffer(response.url);
117
+ const fs = await import("fs/promises");
118
+ await fs.writeFile(filePath, buffer);
119
+ return response;
120
+ }
121
+ /**
122
+ * Capture multiple screenshots in batch
123
+ *
124
+ * @param urls - Array of URLs to capture
125
+ * @param options - Common options for all screenshots
126
+ * @returns Array of screenshot responses
127
+ */
128
+ async batch(urls, options) {
129
+ const promises = urls.map(
130
+ (url) => this.screenshot({ ...options, url })
131
+ );
132
+ return Promise.all(promises);
133
+ }
134
+ /**
135
+ * Get device preset dimensions
136
+ *
137
+ * @param device - Device preset name
138
+ * @returns Device dimensions
139
+ */
140
+ static getDevicePreset(device) {
141
+ return DEVICE_PRESETS[device];
142
+ }
143
+ /**
144
+ * List all available device presets
145
+ */
146
+ static get devicePresets() {
147
+ return Object.keys(DEVICE_PRESETS);
148
+ }
149
+ /**
150
+ * Build URL parameters from options
151
+ */
152
+ buildParams(options) {
153
+ const params = new URLSearchParams();
154
+ params.set("url", options.url);
155
+ params.set("api_key", this.apiKey);
156
+ if (options.device) {
157
+ const preset = DEVICE_PRESETS[options.device];
158
+ if (preset) {
159
+ params.set("width", preset.width.toString());
160
+ params.set("height", preset.height.toString());
161
+ if (preset.mobile) params.set("mobile", "true");
162
+ if (preset.scale !== 1) params.set("scale", preset.scale.toString());
163
+ }
164
+ } else {
165
+ if (options.width) params.set("width", options.width.toString());
166
+ if (options.height) params.set("height", options.height.toString());
167
+ }
168
+ if (options.fullPage) params.set("full_page", "true");
169
+ if (options.format) params.set("format", options.format);
170
+ if (options.quality) params.set("quality", options.quality.toString());
171
+ if (options.scale) params.set("scale", options.scale.toString());
172
+ if (options.delay) params.set("delay", options.delay.toString());
173
+ if (options.waitForSelector) params.set("wait_for", options.waitForSelector);
174
+ if (options.darkMode) params.set("dark_mode", "true");
175
+ if (options.mobile) params.set("mobile", "true");
176
+ if (options.selector) params.set("selector", options.selector);
177
+ if (options.css) params.set("css", options.css);
178
+ if (options.js) params.set("js", options.js);
179
+ if (options.blockAds) params.set("block_ads", "true");
180
+ if (options.hideCookieBanners) params.set("hide_cookie_banners", "true");
181
+ if (options.thumbnailWidth) params.set("thumbnail_width", options.thumbnailWidth.toString());
182
+ return params;
183
+ }
184
+ /**
185
+ * Make an API request with retries
186
+ */
187
+ async request(endpoint, params) {
188
+ const url = `${this.baseUrl}${endpoint}?${params.toString()}`;
189
+ let lastError = null;
190
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
191
+ try {
192
+ const controller = new AbortController();
193
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
194
+ const response = await fetch(url, {
195
+ method: "GET",
196
+ signal: controller.signal
197
+ });
198
+ clearTimeout(timeoutId);
199
+ const data = await response.json();
200
+ if (!response.ok) {
201
+ const error = data;
202
+ throw new ShotAPIException(
203
+ error.error || "Unknown error",
204
+ error.code,
205
+ error.details,
206
+ response.status
207
+ );
208
+ }
209
+ return data;
210
+ } catch (error) {
211
+ lastError = error;
212
+ if (error instanceof ShotAPIException && error.statusCode && error.statusCode < 500) {
213
+ throw error;
214
+ }
215
+ if (attempt < this.retries) {
216
+ await this.sleep(Math.pow(2, attempt) * 1e3);
217
+ }
218
+ }
219
+ }
220
+ throw lastError || new ShotAPIException("Request failed after retries");
221
+ }
222
+ /**
223
+ * Fetch a URL as Buffer
224
+ */
225
+ async fetchBuffer(url) {
226
+ const response = await fetch(url);
227
+ if (!response.ok) {
228
+ throw new ShotAPIException("Failed to fetch image");
229
+ }
230
+ const arrayBuffer = await response.arrayBuffer();
231
+ return Buffer.from(arrayBuffer);
232
+ }
233
+ /**
234
+ * Sleep for specified milliseconds
235
+ */
236
+ sleep(ms) {
237
+ return new Promise((resolve) => setTimeout(resolve, ms));
238
+ }
239
+ };
240
+ var index_default = ShotAPI;
241
+ // Annotate the CommonJS export names for ESM import in node:
242
+ 0 && (module.exports = {
243
+ ShotAPI,
244
+ ShotAPIException
245
+ });
package/dist/index.mjs ADDED
@@ -0,0 +1,209 @@
1
+ // src/index.ts
2
+ var ShotAPIException = class extends Error {
3
+ constructor(message, code, details, statusCode) {
4
+ super(message);
5
+ this.name = "ShotAPIException";
6
+ this.code = code;
7
+ this.details = details;
8
+ this.statusCode = statusCode;
9
+ }
10
+ };
11
+ var DEVICE_PRESETS = {
12
+ desktop: { width: 1920, height: 1080, mobile: false, scale: 1 },
13
+ laptop: { width: 1366, height: 768, mobile: false, scale: 1 },
14
+ tablet: { width: 768, height: 1024, mobile: true, scale: 2 },
15
+ mobile: { width: 375, height: 812, mobile: true, scale: 3 },
16
+ "iphone-14": { width: 390, height: 844, mobile: true, scale: 3 },
17
+ "iphone-14-pro": { width: 393, height: 852, mobile: true, scale: 3 },
18
+ "iphone-14-pro-max": { width: 430, height: 932, mobile: true, scale: 3 },
19
+ "ipad": { width: 810, height: 1080, mobile: true, scale: 2 },
20
+ "ipad-pro": { width: 1024, height: 1366, mobile: true, scale: 2 },
21
+ "galaxy-s23": { width: 360, height: 780, mobile: true, scale: 3 },
22
+ "pixel-7": { width: 412, height: 915, mobile: true, scale: 2.625 }
23
+ };
24
+ var ShotAPI = class {
25
+ constructor(config) {
26
+ if (!config.apiKey) {
27
+ throw new ShotAPIException("API key is required");
28
+ }
29
+ this.apiKey = config.apiKey;
30
+ this.baseUrl = config.baseUrl || "https://shotapi.dev";
31
+ this.timeout = config.timeout || 3e4;
32
+ this.retries = config.retries ?? 2;
33
+ }
34
+ /**
35
+ * Capture a screenshot of a URL
36
+ *
37
+ * @param options - Screenshot options
38
+ * @returns Screenshot response with URL and metadata
39
+ *
40
+ * @example
41
+ * ```typescript
42
+ * const result = await client.screenshot({
43
+ * url: 'https://example.com',
44
+ * width: 1280,
45
+ * height: 720,
46
+ * fullPage: true,
47
+ * });
48
+ * ```
49
+ */
50
+ async screenshot(options) {
51
+ if (!options.url) {
52
+ throw new ShotAPIException("URL is required");
53
+ }
54
+ const params = this.buildParams(options);
55
+ return this.request("/api/v1/screenshot", params);
56
+ }
57
+ /**
58
+ * Capture a screenshot and return as a Buffer
59
+ *
60
+ * @param options - Screenshot options
61
+ * @returns Screenshot as a Buffer
62
+ */
63
+ async screenshotBuffer(options) {
64
+ const response = await this.screenshot(options);
65
+ const imageResponse = await fetch(response.url);
66
+ if (!imageResponse.ok) {
67
+ throw new ShotAPIException("Failed to fetch screenshot image");
68
+ }
69
+ const arrayBuffer = await imageResponse.arrayBuffer();
70
+ return Buffer.from(arrayBuffer);
71
+ }
72
+ /**
73
+ * Capture a screenshot and save to a file
74
+ *
75
+ * @param options - Screenshot options
76
+ * @param filePath - Path to save the screenshot
77
+ */
78
+ async screenshotToFile(options, filePath) {
79
+ const response = await this.screenshot(options);
80
+ const buffer = await this.fetchBuffer(response.url);
81
+ const fs = await import("fs/promises");
82
+ await fs.writeFile(filePath, buffer);
83
+ return response;
84
+ }
85
+ /**
86
+ * Capture multiple screenshots in batch
87
+ *
88
+ * @param urls - Array of URLs to capture
89
+ * @param options - Common options for all screenshots
90
+ * @returns Array of screenshot responses
91
+ */
92
+ async batch(urls, options) {
93
+ const promises = urls.map(
94
+ (url) => this.screenshot({ ...options, url })
95
+ );
96
+ return Promise.all(promises);
97
+ }
98
+ /**
99
+ * Get device preset dimensions
100
+ *
101
+ * @param device - Device preset name
102
+ * @returns Device dimensions
103
+ */
104
+ static getDevicePreset(device) {
105
+ return DEVICE_PRESETS[device];
106
+ }
107
+ /**
108
+ * List all available device presets
109
+ */
110
+ static get devicePresets() {
111
+ return Object.keys(DEVICE_PRESETS);
112
+ }
113
+ /**
114
+ * Build URL parameters from options
115
+ */
116
+ buildParams(options) {
117
+ const params = new URLSearchParams();
118
+ params.set("url", options.url);
119
+ params.set("api_key", this.apiKey);
120
+ if (options.device) {
121
+ const preset = DEVICE_PRESETS[options.device];
122
+ if (preset) {
123
+ params.set("width", preset.width.toString());
124
+ params.set("height", preset.height.toString());
125
+ if (preset.mobile) params.set("mobile", "true");
126
+ if (preset.scale !== 1) params.set("scale", preset.scale.toString());
127
+ }
128
+ } else {
129
+ if (options.width) params.set("width", options.width.toString());
130
+ if (options.height) params.set("height", options.height.toString());
131
+ }
132
+ if (options.fullPage) params.set("full_page", "true");
133
+ if (options.format) params.set("format", options.format);
134
+ if (options.quality) params.set("quality", options.quality.toString());
135
+ if (options.scale) params.set("scale", options.scale.toString());
136
+ if (options.delay) params.set("delay", options.delay.toString());
137
+ if (options.waitForSelector) params.set("wait_for", options.waitForSelector);
138
+ if (options.darkMode) params.set("dark_mode", "true");
139
+ if (options.mobile) params.set("mobile", "true");
140
+ if (options.selector) params.set("selector", options.selector);
141
+ if (options.css) params.set("css", options.css);
142
+ if (options.js) params.set("js", options.js);
143
+ if (options.blockAds) params.set("block_ads", "true");
144
+ if (options.hideCookieBanners) params.set("hide_cookie_banners", "true");
145
+ if (options.thumbnailWidth) params.set("thumbnail_width", options.thumbnailWidth.toString());
146
+ return params;
147
+ }
148
+ /**
149
+ * Make an API request with retries
150
+ */
151
+ async request(endpoint, params) {
152
+ const url = `${this.baseUrl}${endpoint}?${params.toString()}`;
153
+ let lastError = null;
154
+ for (let attempt = 0; attempt <= this.retries; attempt++) {
155
+ try {
156
+ const controller = new AbortController();
157
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
158
+ const response = await fetch(url, {
159
+ method: "GET",
160
+ signal: controller.signal
161
+ });
162
+ clearTimeout(timeoutId);
163
+ const data = await response.json();
164
+ if (!response.ok) {
165
+ const error = data;
166
+ throw new ShotAPIException(
167
+ error.error || "Unknown error",
168
+ error.code,
169
+ error.details,
170
+ response.status
171
+ );
172
+ }
173
+ return data;
174
+ } catch (error) {
175
+ lastError = error;
176
+ if (error instanceof ShotAPIException && error.statusCode && error.statusCode < 500) {
177
+ throw error;
178
+ }
179
+ if (attempt < this.retries) {
180
+ await this.sleep(Math.pow(2, attempt) * 1e3);
181
+ }
182
+ }
183
+ }
184
+ throw lastError || new ShotAPIException("Request failed after retries");
185
+ }
186
+ /**
187
+ * Fetch a URL as Buffer
188
+ */
189
+ async fetchBuffer(url) {
190
+ const response = await fetch(url);
191
+ if (!response.ok) {
192
+ throw new ShotAPIException("Failed to fetch image");
193
+ }
194
+ const arrayBuffer = await response.arrayBuffer();
195
+ return Buffer.from(arrayBuffer);
196
+ }
197
+ /**
198
+ * Sleep for specified milliseconds
199
+ */
200
+ sleep(ms) {
201
+ return new Promise((resolve) => setTimeout(resolve, ms));
202
+ }
203
+ };
204
+ var index_default = ShotAPI;
205
+ export {
206
+ ShotAPI,
207
+ ShotAPIException,
208
+ index_default as default
209
+ };
package/package.json ADDED
@@ -0,0 +1,53 @@
1
+ {
2
+ "name": "@shotapi/sdk",
3
+ "version": "1.0.0",
4
+ "description": "Official Node.js SDK for ShotAPI - Screenshot API for Developers",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.mjs",
12
+ "require": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "scripts": {
19
+ "build": "tsup src/index.ts --format cjs,esm --dts --clean",
20
+ "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
21
+ "test": "vitest",
22
+ "prepublishOnly": "npm run build"
23
+ },
24
+ "keywords": [
25
+ "screenshot",
26
+ "api",
27
+ "web",
28
+ "capture",
29
+ "puppeteer",
30
+ "headless",
31
+ "browser",
32
+ "shotapi"
33
+ ],
34
+ "author": "ShotAPI",
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "https://github.com/gaurav-aryal/shotapi-sdk"
39
+ },
40
+ "homepage": "https://shotapi.dev",
41
+ "bugs": {
42
+ "url": "https://github.com/gaurav-aryal/shotapi-sdk/issues"
43
+ },
44
+ "devDependencies": {
45
+ "@types/node": "^20.10.0",
46
+ "tsup": "^8.0.0",
47
+ "typescript": "^5.3.0",
48
+ "vitest": "^1.0.0"
49
+ },
50
+ "engines": {
51
+ "node": ">=18.0.0"
52
+ }
53
+ }