shorter.sh 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/dist/index.js ADDED
@@ -0,0 +1,281 @@
1
+ // src/errors.ts
2
+ var ShorterError = class extends Error {
3
+ status;
4
+ code;
5
+ constructor(message, status, code) {
6
+ super(message);
7
+ this.name = "ShorterError";
8
+ this.status = status;
9
+ this.code = code;
10
+ }
11
+ };
12
+ var ValidationError = class extends ShorterError {
13
+ constructor(message, code = "VALIDATION_ERROR") {
14
+ super(message, 400, code);
15
+ this.name = "ValidationError";
16
+ }
17
+ };
18
+ var AuthenticationError = class extends ShorterError {
19
+ constructor(message, code = "AUTH_REQUIRED") {
20
+ super(message, 401, code);
21
+ this.name = "AuthenticationError";
22
+ }
23
+ };
24
+ var ForbiddenError = class extends ShorterError {
25
+ constructor(message, code = "FORBIDDEN") {
26
+ super(message, 403, code);
27
+ this.name = "ForbiddenError";
28
+ }
29
+ };
30
+ var NotFoundError = class extends ShorterError {
31
+ constructor(message, code = "NOT_FOUND") {
32
+ super(message, 404, code);
33
+ this.name = "NotFoundError";
34
+ }
35
+ };
36
+ var RateLimitError = class extends ShorterError {
37
+ constructor(message, code = "RATE_LIMITED") {
38
+ super(message, 429, code);
39
+ this.name = "RateLimitError";
40
+ }
41
+ };
42
+ var ServerError = class extends ShorterError {
43
+ constructor(message, code = "SERVER_ERROR") {
44
+ super(message, 500, code);
45
+ this.name = "ServerError";
46
+ }
47
+ };
48
+ var NetworkError = class extends ShorterError {
49
+ constructor(message) {
50
+ super(message, 0, "NETWORK_ERROR");
51
+ this.name = "NetworkError";
52
+ }
53
+ };
54
+ function mapStatusToError(status, message, code) {
55
+ switch (status) {
56
+ case 400:
57
+ return new ValidationError(message, code);
58
+ case 401:
59
+ return new AuthenticationError(message, code);
60
+ case 403:
61
+ return new ForbiddenError(message, code);
62
+ case 404:
63
+ return new NotFoundError(message, code);
64
+ case 429:
65
+ return new RateLimitError(message, code);
66
+ default:
67
+ if (status >= 500) return new ServerError(message, code);
68
+ return new ShorterError(message, status, code);
69
+ }
70
+ }
71
+
72
+ // src/fetch-wrapper.ts
73
+ var FetchWrapper = class {
74
+ baseUrl;
75
+ apiKey;
76
+ fetchFn;
77
+ constructor(baseUrl, apiKey, fetchFn) {
78
+ this.baseUrl = baseUrl.replace(/\/+$/, "");
79
+ this.apiKey = apiKey;
80
+ this.fetchFn = fetchFn;
81
+ }
82
+ async request(path, options = {}) {
83
+ const { method = "GET", body, params } = options;
84
+ let url = `${this.baseUrl}${path}`;
85
+ if (params) {
86
+ const searchParams = new URLSearchParams();
87
+ for (const [key, value] of Object.entries(params)) {
88
+ if (value !== void 0) {
89
+ searchParams.set(key, String(value));
90
+ }
91
+ }
92
+ const qs = searchParams.toString();
93
+ if (qs) url += `?${qs}`;
94
+ }
95
+ const headers = {
96
+ "Authorization": `Bearer ${this.apiKey}`,
97
+ "Accept": "application/json"
98
+ };
99
+ const init = { method, headers };
100
+ if (body) {
101
+ headers["Content-Type"] = "application/json";
102
+ init.body = JSON.stringify(body);
103
+ }
104
+ let response;
105
+ try {
106
+ response = await this.fetchFn(url, init);
107
+ } catch (err) {
108
+ throw new NetworkError(
109
+ err instanceof Error ? err.message : "Network request failed"
110
+ );
111
+ }
112
+ const data = await response.json();
113
+ if (!response.ok || data.success === false) {
114
+ throw mapStatusToError(
115
+ response.status,
116
+ data.message || `Request failed with status ${response.status}`,
117
+ data.code || "UNKNOWN_ERROR"
118
+ );
119
+ }
120
+ return data;
121
+ }
122
+ };
123
+
124
+ // src/analytics.ts
125
+ function mapTimeseries(raw) {
126
+ return raw.map((p) => ({
127
+ period: p.period,
128
+ clicks: p.clicks,
129
+ uniqueVisitors: p.unique_visitors
130
+ }));
131
+ }
132
+ function mapTopUrl(raw) {
133
+ return {
134
+ shortCode: raw.short_code,
135
+ shortUrl: raw.short_url,
136
+ originalUrl: raw.original_url,
137
+ clicks: raw.clicks
138
+ };
139
+ }
140
+ var AnalyticsClient = class {
141
+ fetch;
142
+ constructor(fetchWrapper) {
143
+ this.fetch = fetchWrapper;
144
+ }
145
+ async overview(options) {
146
+ const raw = await this.fetch.request("/api/v1/analytics/overview", {
147
+ params: {
148
+ start: options?.start !== void 0 ? String(options.start) : void 0,
149
+ end: options?.end !== void 0 ? String(options.end) : void 0
150
+ }
151
+ });
152
+ const timeseries = raw.timeseries;
153
+ const topUrls = raw.topUrls;
154
+ return {
155
+ totalClicks: raw.totalClicks,
156
+ uniqueVisitors: raw.uniqueVisitors,
157
+ prevPeriodClicks: raw.prevPeriodClicks,
158
+ prevPeriodUnique: raw.prevPeriodUnique,
159
+ timeseries: {
160
+ granularity: timeseries.granularity,
161
+ data: mapTimeseries(timeseries.data)
162
+ },
163
+ topUrls: topUrls.map(mapTopUrl),
164
+ countryBreakdown: raw.countryBreakdown,
165
+ deviceBreakdown: raw.deviceBreakdown,
166
+ browserBreakdown: raw.browserBreakdown,
167
+ osBreakdown: raw.osBreakdown,
168
+ referrerBreakdown: raw.referrerBreakdown
169
+ };
170
+ }
171
+ async url(shortCode, options) {
172
+ const raw = await this.fetch.request(`/api/v1/analytics/${shortCode}`, {
173
+ params: {
174
+ start: options?.start !== void 0 ? String(options.start) : void 0,
175
+ end: options?.end !== void 0 ? String(options.end) : void 0,
176
+ dimension: options?.dimension,
177
+ limit: options?.limit,
178
+ detail: options?.detail ? "true" : void 0
179
+ }
180
+ });
181
+ const timeseries = raw.timeseries;
182
+ const mappedTimeseries = {
183
+ granularity: timeseries.granularity,
184
+ data: mapTimeseries(timeseries.data)
185
+ };
186
+ if (options?.detail) {
187
+ return {
188
+ url: raw.url,
189
+ summary: raw.summary,
190
+ timeseries: mappedTimeseries,
191
+ breakdowns: raw.breakdowns
192
+ };
193
+ }
194
+ const result = {
195
+ summary: raw.summary,
196
+ timeseries: mappedTimeseries
197
+ };
198
+ if (raw.breakdown) {
199
+ result.breakdown = raw.breakdown;
200
+ }
201
+ return result;
202
+ }
203
+ };
204
+
205
+ // src/client.ts
206
+ function mapUrl(raw) {
207
+ return {
208
+ id: raw.id,
209
+ shortCode: raw.short_code,
210
+ shortUrl: raw.short_url,
211
+ originalUrl: raw.original_url,
212
+ clickCount: raw.click_count,
213
+ createdAt: new Date(raw.created_at).toISOString()
214
+ };
215
+ }
216
+ var ShorterClient = class {
217
+ analytics;
218
+ fetch;
219
+ constructor(options) {
220
+ const apiKey = options?.apiKey || (typeof process !== "undefined" ? process.env.SHORTER_API_KEY : void 0);
221
+ if (!apiKey) {
222
+ throw new AuthenticationError(
223
+ "API key is required. Pass it as options.apiKey or set SHORTER_API_KEY environment variable.",
224
+ "AUTH_REQUIRED"
225
+ );
226
+ }
227
+ if (!apiKey.startsWith("sk_")) {
228
+ throw new AuthenticationError(
229
+ 'Invalid API key format. Keys must start with "sk_".',
230
+ "INVALID_API_KEY"
231
+ );
232
+ }
233
+ const baseUrl = options?.baseUrl || "https://shorter.sh";
234
+ const fetchFn = options?.fetch || globalThis.fetch;
235
+ this.fetch = new FetchWrapper(baseUrl, apiKey, fetchFn);
236
+ this.analytics = new AnalyticsClient(this.fetch);
237
+ }
238
+ async shorten(url) {
239
+ const data = await this.fetch.request("/api/v1/shorten", {
240
+ method: "POST",
241
+ body: { url }
242
+ });
243
+ return {
244
+ shortCode: data.shortCode,
245
+ shortUrl: data.shortUrl,
246
+ originalUrl: data.originalUrl
247
+ };
248
+ }
249
+ async list(options) {
250
+ const data = await this.fetch.request("/api/v1/urls", {
251
+ params: {
252
+ page: options?.page,
253
+ limit: options?.limit
254
+ }
255
+ });
256
+ return {
257
+ urls: data.data.map(mapUrl),
258
+ pagination: data.pagination,
259
+ totalClicks: data.totalClicks
260
+ };
261
+ }
262
+ async delete(shortCode) {
263
+ const data = await this.fetch.request(`/api/v1/urls/${shortCode}`, {
264
+ method: "DELETE"
265
+ });
266
+ return { message: data.message };
267
+ }
268
+ };
269
+ export {
270
+ AnalyticsClient,
271
+ AuthenticationError,
272
+ ForbiddenError,
273
+ NetworkError,
274
+ NotFoundError,
275
+ RateLimitError,
276
+ ServerError,
277
+ ShorterClient,
278
+ ShorterError,
279
+ ValidationError
280
+ };
281
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/errors.ts","../src/fetch-wrapper.ts","../src/analytics.ts","../src/client.ts"],"sourcesContent":["export class ShorterError extends Error {\n readonly status: number;\n readonly code: string;\n\n constructor(message: string, status: number, code: string) {\n super(message);\n this.name = 'ShorterError';\n this.status = status;\n this.code = code;\n }\n}\n\nexport class ValidationError extends ShorterError {\n constructor(message: string, code: string = 'VALIDATION_ERROR') {\n super(message, 400, code);\n this.name = 'ValidationError';\n }\n}\n\nexport class AuthenticationError extends ShorterError {\n constructor(message: string, code: string = 'AUTH_REQUIRED') {\n super(message, 401, code);\n this.name = 'AuthenticationError';\n }\n}\n\nexport class ForbiddenError extends ShorterError {\n constructor(message: string, code: string = 'FORBIDDEN') {\n super(message, 403, code);\n this.name = 'ForbiddenError';\n }\n}\n\nexport class NotFoundError extends ShorterError {\n constructor(message: string, code: string = 'NOT_FOUND') {\n super(message, 404, code);\n this.name = 'NotFoundError';\n }\n}\n\nexport class RateLimitError extends ShorterError {\n constructor(message: string, code: string = 'RATE_LIMITED') {\n super(message, 429, code);\n this.name = 'RateLimitError';\n }\n}\n\nexport class ServerError extends ShorterError {\n constructor(message: string, code: string = 'SERVER_ERROR') {\n super(message, 500, code);\n this.name = 'ServerError';\n }\n}\n\nexport class NetworkError extends ShorterError {\n constructor(message: string) {\n super(message, 0, 'NETWORK_ERROR');\n this.name = 'NetworkError';\n }\n}\n\nexport function mapStatusToError(status: number, message: string, code: string): ShorterError {\n switch (status) {\n case 400: return new ValidationError(message, code);\n case 401: return new AuthenticationError(message, code);\n case 403: return new ForbiddenError(message, code);\n case 404: return new NotFoundError(message, code);\n case 429: return new RateLimitError(message, code);\n default:\n if (status >= 500) return new ServerError(message, code);\n return new ShorterError(message, status, code);\n }\n}\n","import { mapStatusToError, NetworkError } from './errors.js';\n\nexport interface RequestOptions {\n method?: string;\n body?: Record<string, unknown>;\n params?: Record<string, string | number | boolean | undefined>;\n}\n\nexport class FetchWrapper {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly fetchFn: typeof globalThis.fetch;\n\n constructor(baseUrl: string, apiKey: string, fetchFn: typeof globalThis.fetch) {\n this.baseUrl = baseUrl.replace(/\\/+$/, '');\n this.apiKey = apiKey;\n this.fetchFn = fetchFn;\n }\n\n async request<T>(path: string, options: RequestOptions = {}): Promise<T> {\n const { method = 'GET', body, params } = options;\n\n let url = `${this.baseUrl}${path}`;\n if (params) {\n const searchParams = new URLSearchParams();\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n searchParams.set(key, String(value));\n }\n }\n const qs = searchParams.toString();\n if (qs) url += `?${qs}`;\n }\n\n const headers: Record<string, string> = {\n 'Authorization': `Bearer ${this.apiKey}`,\n 'Accept': 'application/json',\n };\n\n const init: RequestInit = { method, headers };\n\n if (body) {\n headers['Content-Type'] = 'application/json';\n init.body = JSON.stringify(body);\n }\n\n let response: Response;\n try {\n response = await this.fetchFn(url, init);\n } catch (err) {\n throw new NetworkError(\n err instanceof Error ? err.message : 'Network request failed'\n );\n }\n\n const data = await response.json() as Record<string, unknown>;\n\n if (!response.ok || data.success === false) {\n throw mapStatusToError(\n response.status,\n (data.message as string) || `Request failed with status ${response.status}`,\n (data.code as string) || 'UNKNOWN_ERROR'\n );\n }\n\n return data as T;\n }\n}\n","import type { FetchWrapper } from './fetch-wrapper.js';\nimport type {\n TimeRange,\n OverviewAnalyticsResult,\n UrlAnalyticsOptions,\n UrlAnalyticsResult,\n UrlAnalyticsDetailResult,\n TimeSeriesPoint,\n TopUrl,\n RawTimeSeriesPoint,\n RawTopUrl,\n} from './types.js';\n\nfunction mapTimeseries(raw: RawTimeSeriesPoint[]): TimeSeriesPoint[] {\n return raw.map((p) => ({\n period: p.period,\n clicks: p.clicks,\n uniqueVisitors: p.unique_visitors,\n }));\n}\n\nfunction mapTopUrl(raw: RawTopUrl): TopUrl {\n return {\n shortCode: raw.short_code,\n shortUrl: raw.short_url,\n originalUrl: raw.original_url,\n clicks: raw.clicks,\n };\n}\n\nexport class AnalyticsClient {\n private readonly fetch: FetchWrapper;\n\n constructor(fetchWrapper: FetchWrapper) {\n this.fetch = fetchWrapper;\n }\n\n async overview(options?: TimeRange): Promise<OverviewAnalyticsResult> {\n const raw = await this.fetch.request<Record<string, unknown>>('/api/v1/analytics/overview', {\n params: {\n start: options?.start !== undefined ? String(options.start) : undefined,\n end: options?.end !== undefined ? String(options.end) : undefined,\n },\n });\n\n const timeseries = raw.timeseries as { granularity: string; data: RawTimeSeriesPoint[] };\n const topUrls = raw.topUrls as RawTopUrl[];\n\n return {\n totalClicks: raw.totalClicks as number,\n uniqueVisitors: raw.uniqueVisitors as number | null,\n prevPeriodClicks: raw.prevPeriodClicks as number,\n prevPeriodUnique: raw.prevPeriodUnique as number | null,\n timeseries: {\n granularity: timeseries.granularity,\n data: mapTimeseries(timeseries.data),\n },\n topUrls: topUrls.map(mapTopUrl),\n countryBreakdown: raw.countryBreakdown as OverviewAnalyticsResult['countryBreakdown'],\n deviceBreakdown: raw.deviceBreakdown as OverviewAnalyticsResult['deviceBreakdown'],\n browserBreakdown: raw.browserBreakdown as OverviewAnalyticsResult['browserBreakdown'],\n osBreakdown: raw.osBreakdown as OverviewAnalyticsResult['osBreakdown'],\n referrerBreakdown: raw.referrerBreakdown as OverviewAnalyticsResult['referrerBreakdown'],\n };\n }\n\n async url(shortCode: string, options?: UrlAnalyticsOptions & { detail: true }): Promise<UrlAnalyticsDetailResult>;\n async url(shortCode: string, options?: UrlAnalyticsOptions): Promise<UrlAnalyticsResult>;\n async url(shortCode: string, options?: UrlAnalyticsOptions): Promise<UrlAnalyticsResult | UrlAnalyticsDetailResult> {\n const raw = await this.fetch.request<Record<string, unknown>>(`/api/v1/analytics/${shortCode}`, {\n params: {\n start: options?.start !== undefined ? String(options.start) : undefined,\n end: options?.end !== undefined ? String(options.end) : undefined,\n dimension: options?.dimension,\n limit: options?.limit,\n detail: options?.detail ? 'true' : undefined,\n },\n });\n\n const timeseries = raw.timeseries as { granularity: string; data: RawTimeSeriesPoint[] };\n const mappedTimeseries = {\n granularity: timeseries.granularity,\n data: mapTimeseries(timeseries.data),\n };\n\n if (options?.detail) {\n // detail=true: server returns url object (already camelCase) + breakdowns\n return {\n url: raw.url as UrlAnalyticsDetailResult['url'],\n summary: raw.summary as UrlAnalyticsDetailResult['summary'],\n timeseries: mappedTimeseries,\n breakdowns: raw.breakdowns as UrlAnalyticsDetailResult['breakdowns'],\n };\n }\n\n const result: UrlAnalyticsResult = {\n summary: raw.summary as UrlAnalyticsResult['summary'],\n timeseries: mappedTimeseries,\n };\n\n if (raw.breakdown) {\n result.breakdown = raw.breakdown as UrlAnalyticsResult['breakdown'];\n }\n\n return result;\n }\n}\n","import { FetchWrapper } from './fetch-wrapper.js';\nimport { AnalyticsClient } from './analytics.js';\nimport { AuthenticationError } from './errors.js';\nimport type {\n ShorterClientOptions,\n ShortenResult,\n ListUrlsOptions,\n ListUrlsResult,\n DeleteResult,\n RawUrlItem,\n ShorterUrl,\n} from './types.js';\n\nfunction mapUrl(raw: RawUrlItem): ShorterUrl {\n return {\n id: raw.id,\n shortCode: raw.short_code,\n shortUrl: raw.short_url,\n originalUrl: raw.original_url,\n clickCount: raw.click_count,\n createdAt: new Date(raw.created_at).toISOString(),\n };\n}\n\nexport class ShorterClient {\n readonly analytics: AnalyticsClient;\n private readonly fetch: FetchWrapper;\n\n constructor(options?: ShorterClientOptions) {\n const apiKey = options?.apiKey || (typeof process !== 'undefined' ? process.env.SHORTER_API_KEY : undefined);\n if (!apiKey) {\n throw new AuthenticationError(\n 'API key is required. Pass it as options.apiKey or set SHORTER_API_KEY environment variable.',\n 'AUTH_REQUIRED'\n );\n }\n if (!apiKey.startsWith('sk_')) {\n throw new AuthenticationError(\n 'Invalid API key format. Keys must start with \"sk_\".',\n 'INVALID_API_KEY'\n );\n }\n\n const baseUrl = options?.baseUrl || 'https://shorter.sh';\n const fetchFn = options?.fetch || globalThis.fetch;\n\n this.fetch = new FetchWrapper(baseUrl, apiKey, fetchFn);\n this.analytics = new AnalyticsClient(this.fetch);\n }\n\n async shorten(url: string): Promise<ShortenResult> {\n const data = await this.fetch.request<{\n success: boolean;\n shortCode: string;\n shortUrl: string;\n originalUrl: string;\n }>('/api/v1/shorten', {\n method: 'POST',\n body: { url },\n });\n\n return {\n shortCode: data.shortCode,\n shortUrl: data.shortUrl,\n originalUrl: data.originalUrl,\n };\n }\n\n async list(options?: ListUrlsOptions): Promise<ListUrlsResult> {\n const data = await this.fetch.request<{\n success: boolean;\n data: RawUrlItem[];\n pagination: ListUrlsResult['pagination'];\n totalClicks: number;\n }>('/api/v1/urls', {\n params: {\n page: options?.page,\n limit: options?.limit,\n },\n });\n\n return {\n urls: data.data.map(mapUrl),\n pagination: data.pagination,\n totalClicks: data.totalClicks,\n };\n }\n\n async delete(shortCode: string): Promise<DeleteResult> {\n const data = await this.fetch.request<{\n success: boolean;\n message: string;\n }>(`/api/v1/urls/${shortCode}`, {\n method: 'DELETE',\n });\n\n return { message: data.message };\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,62 @@
1
+ {
2
+ "name": "shorter.sh",
3
+ "version": "1.0.0",
4
+ "description": "CLI and SDK for the shorter.sh URL shortener",
5
+ "author": "ShorterSH",
6
+ "homepage": "https://shorter.sh",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/ShorterSH/js-sdk.git"
10
+ },
11
+ "bugs": {
12
+ "url": "https://github.com/ShorterSH/js-sdk/issues"
13
+ },
14
+ "type": "module",
15
+ "main": "./dist/index.cjs",
16
+ "module": "./dist/index.js",
17
+ "types": "./dist/index.d.ts",
18
+ "exports": {
19
+ ".": {
20
+ "import": {
21
+ "types": "./dist/index.d.ts",
22
+ "default": "./dist/index.js"
23
+ },
24
+ "require": {
25
+ "types": "./dist/index.d.cts",
26
+ "default": "./dist/index.cjs"
27
+ }
28
+ }
29
+ },
30
+ "bin": {
31
+ "shorter": "dist/cli.js"
32
+ },
33
+ "files": [
34
+ "dist"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "test": "vitest run",
40
+ "test:watch": "vitest",
41
+ "lint": "tsc --noEmit",
42
+ "prepublishOnly": "npm run build"
43
+ },
44
+ "engines": {
45
+ "node": ">=18.0.0"
46
+ },
47
+ "keywords": [
48
+ "url-shortener",
49
+ "link-shortener",
50
+ "short-url",
51
+ "shorter.sh",
52
+ "cli",
53
+ "sdk"
54
+ ],
55
+ "license": "MIT",
56
+ "devDependencies": {
57
+ "@types/node": "^25.5.0",
58
+ "tsup": "^8.0.0",
59
+ "typescript": "^5.3.0",
60
+ "vitest": "^2.0.0"
61
+ }
62
+ }