tly-api 1.0.0 → 1.0.1

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/index.js CHANGED
@@ -96,9 +96,96 @@ class TlyClient {
96
96
  return response.data;
97
97
  }
98
98
 
99
- async getStats(shortUrl) {
99
+ async bulkUpdateLinks(data) {
100
+ // data: { links, tags, pixels }
101
+ const response = await this.client.post('/api/v1/link/bulk/update', data);
102
+ return response.data;
103
+ }
104
+
105
+ async getStats(shortUrl, params = {}) {
100
106
  const response = await this.client.get('/api/v1/link/stats', {
101
- params: { short_url: shortUrl },
107
+ params: {
108
+ short_url: shortUrl,
109
+ ...params,
110
+ },
111
+ });
112
+ return response.data;
113
+ }
114
+
115
+ // ===== OneLink Management =====
116
+
117
+ async getOneLinkStats(shortUrl, params = {}) {
118
+ const response = await this.client.get('/api/v1/onelink/stats', {
119
+ params: {
120
+ short_url: shortUrl,
121
+ ...params,
122
+ },
123
+ });
124
+ return response.data;
125
+ }
126
+
127
+ async deleteOneLinkStats(data) {
128
+ // data: { short_url }
129
+ const response = await this.client.delete('/api/v1/onelink/stat', { data });
130
+ return response.data;
131
+ }
132
+
133
+ async listOneLinks(params = {}) {
134
+ const response = await this.client.get('/api/v1/onelink/list', { params });
135
+ return response.data;
136
+ }
137
+
138
+ // ===== UTM Preset Management =====
139
+
140
+ async createUtmPreset(data) {
141
+ // data: { name, source, medium, campaign, content, term }
142
+ const response = await this.client.post('/api/v1/link/utm-preset', data);
143
+ return response.data;
144
+ }
145
+
146
+ async listUtmPresets() {
147
+ const response = await this.client.get('/api/v1/link/utm-preset');
148
+ return response.data;
149
+ }
150
+
151
+ async getUtmPreset(id) {
152
+ const response = await this.client.get(`/api/v1/link/utm-preset/${id}`);
153
+ return response.data;
154
+ }
155
+
156
+ async updateUtmPreset(id, data) {
157
+ // data: { name, source, medium, campaign, content, term }
158
+ const response = await this.client.put(`/api/v1/link/utm-preset/${id}`, data);
159
+ return response.data;
160
+ }
161
+
162
+ async deleteUtmPreset(id) {
163
+ const response = await this.client.delete(`/api/v1/link/utm-preset/${id}`);
164
+ return response.data;
165
+ }
166
+
167
+ // ===== QR Code Management =====
168
+
169
+ async getQrCode(params = {}, config = {}) {
170
+ const response = await this.client.get('/api/v1/link/qr-code', {
171
+ ...config,
172
+ params,
173
+ });
174
+ return response.data;
175
+ }
176
+
177
+ async updateQrCode(data) {
178
+ // data: { short_url, image, background_color, corner_dots_color, dots_color, dots_style, corner_style }
179
+ const response = await this.client.put('/api/v1/link/qr-code', data);
180
+ return response.data;
181
+ }
182
+
183
+ async getLinkStats(shortUrl, params = {}) {
184
+ const response = await this.client.get('/api/v1/link/stats', {
185
+ params: {
186
+ short_url: shortUrl,
187
+ ...params,
188
+ },
102
189
  });
103
190
  return response.data;
104
191
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "tly-api",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
4
  "description": "A Node.js client for the T.ly URL Shortener API",
5
5
  "main": "index.js",
6
6
  "scripts": {
7
- "test": "echo \"No tests specified\""
7
+ "test": "node --test"
8
8
  },
9
9
  "keywords": [
10
10
  "t.ly",
package/readme.md CHANGED
@@ -1,14 +1,17 @@
1
1
  # T.LY API Client
2
2
 
3
- A Node.js client for the [T.LY URL Shortener](https://t.ly/) API. This package provides convenient methods to manage short links, tags, and pixels through T.LY's API.
3
+ A Node.js client for the [T.LY URL Shortener](https://t.ly/) API. This package provides convenient methods to manage short links, OneLinks, UTM presets, QR codes, tags, and pixels through T.LY's API.
4
4
 
5
5
  ## Table of Contents
6
6
 
7
7
  - [Installation](#installation)
8
8
  - [Getting Started](#getting-started)
9
9
  - [API Reference](#api-reference)
10
- - [Pixel Management](#pixel-management)
11
10
  - [Short Link Management](#short-link-management)
11
+ - [OneLink Management](#onelink-management)
12
+ - [UTM Preset Management](#utm-preset-management)
13
+ - [QR Code Management](#qr-code-management)
14
+ - [Pixel Management](#pixel-management)
12
15
  - [Tag Management](#tag-management)
13
16
  - [Example](#example)
14
17
  - [License](#license)
@@ -42,42 +45,6 @@ npm install tly-api
42
45
 
43
46
  Below is a summary of the methods available on the `TlyClient` class. For detailed parameter structures, refer to the inline code comments.
44
47
 
45
- ### Pixel Management
46
-
47
- - **createPixel(data)**
48
- Creates a new pixel.
49
- _Example `data`:_
50
-
51
- ```js
52
- {
53
- name: 'My Facebook Pixel',
54
- pixel_id: '123456789',
55
- pixel_type: 'facebook'
56
- }
57
- ```
58
-
59
- - **listPixels()**
60
- Retrieves a list of all pixels.
61
-
62
- - **getPixel(id)**
63
- Retrieves a single pixel by its ID.
64
-
65
- - **updatePixel(id, data)**
66
- Updates the pixel's attributes.
67
- _Example `data`:_
68
-
69
- ```js
70
- {
71
- id: 123,
72
- name: 'Updated Pixel',
73
- pixel_id: '987654321',
74
- pixel_type: 'facebook'
75
- }
76
- ```
77
-
78
- - **deletePixel(id)**
79
- Deletes the pixel by its ID.
80
-
81
48
  ### Short Link Management
82
49
 
83
50
  - **createShortLink(data)**
@@ -153,8 +120,71 @@ Below is a summary of the methods available on the `TlyClient` class. For detail
153
120
  }
154
121
  ```
155
122
 
156
- - **getStats(shortUrl)**
157
- Retrieves analytics data for a given short URL.
123
+ - **bulkUpdateLinks(data)**
124
+ Updates multiple short links in a single request.
125
+
126
+ - **getStats(shortUrl, params)**
127
+ Retrieves analytics data for a short URL (`/api/v1/link/stats`).
128
+
129
+ - **getLinkStats(shortUrl, params)**
130
+ Alias of `getStats`.
131
+
132
+ ### OneLink Management
133
+
134
+ - **getOneLinkStats(shortUrl, params)**
135
+ Retrieves OneLink analytics (`/api/v1/onelink/stats`).
136
+ Optional params include `start_date` and `end_date`.
137
+
138
+ - **deleteOneLinkStats(data)**
139
+ Deletes OneLink stats (`/api/v1/onelink/stat`).
140
+ `data` should include `short_url`.
141
+
142
+ - **listOneLinks(params)**
143
+ Lists OneLinks (`/api/v1/onelink/list`).
144
+ Optional params include `page`.
145
+
146
+ ### UTM Preset Management
147
+
148
+ - **createUtmPreset(data)**
149
+ Creates a UTM preset.
150
+
151
+ - **listUtmPresets()**
152
+ Lists UTM presets.
153
+
154
+ - **getUtmPreset(id)**
155
+ Retrieves one UTM preset by ID.
156
+
157
+ - **updateUtmPreset(id, data)**
158
+ Updates a UTM preset by ID.
159
+
160
+ - **deleteUtmPreset(id)**
161
+ Deletes a UTM preset by ID.
162
+
163
+ ### QR Code Management
164
+
165
+ - **getQrCode(params, config)**
166
+ Gets a QR code (`/api/v1/link/qr-code`).
167
+ Use params like `short_url`, `output`, and `format`.
168
+
169
+ - **updateQrCode(data)**
170
+ Updates QR code options (`/api/v1/link/qr-code`).
171
+
172
+ ### Pixel Management
173
+
174
+ - **createPixel(data)**
175
+ Creates a new pixel.
176
+
177
+ - **listPixels()**
178
+ Retrieves a list of all pixels.
179
+
180
+ - **getPixel(id)**
181
+ Retrieves a single pixel by its ID.
182
+
183
+ - **updatePixel(id, data)**
184
+ Updates the pixel's attributes.
185
+
186
+ - **deletePixel(id)**
187
+ Deletes the pixel by its ID.
158
188
 
159
189
  ### Tag Management
160
190
 
@@ -0,0 +1,181 @@
1
+ const assert = require('node:assert/strict');
2
+ const test = require('node:test');
3
+ const axios = require('axios');
4
+ const TlyClient = require('../index');
5
+
6
+ function createClientWithRecorder() {
7
+ const calls = [];
8
+
9
+ const fakeHttpClient = {
10
+ get: async (url, config) => {
11
+ calls.push({ method: 'get', url, config });
12
+ return { data: { ok: true, method: 'get', url, config } };
13
+ },
14
+ post: async (url, data, config) => {
15
+ calls.push({ method: 'post', url, data, config });
16
+ return { data: { ok: true, method: 'post', url, data, config } };
17
+ },
18
+ put: async (url, data, config) => {
19
+ calls.push({ method: 'put', url, data, config });
20
+ return { data: { ok: true, method: 'put', url, data, config } };
21
+ },
22
+ delete: async (url, config) => {
23
+ calls.push({ method: 'delete', url, config });
24
+ return { data: { ok: true, method: 'delete', url, config } };
25
+ },
26
+ };
27
+
28
+ const originalCreate = axios.create;
29
+ axios.create = () => fakeHttpClient;
30
+
31
+ const client = new TlyClient('token');
32
+ axios.create = originalCreate;
33
+
34
+ return { client, calls };
35
+ }
36
+
37
+ test('constructor requires api token', () => {
38
+ assert.throws(() => new TlyClient(), /API token is required/);
39
+ });
40
+
41
+ test('short link methods map to documented endpoints', async () => {
42
+ const { client, calls } = createClientWithRecorder();
43
+
44
+ await client.createShortLink({ long_url: 'https://example.com' });
45
+ await client.getShortLink('https://t.ly/abc');
46
+ await client.updateShortLink({ short_url: 'https://t.ly/abc', description: 'updated' });
47
+ await client.deleteShortLink({ short_url: 'https://t.ly/abc' });
48
+ await client.expandShortLink({ short_url: 'https://t.ly/abc', password: 'secret' });
49
+ await client.listShortLinks({ search: 'example', page: 2 });
50
+ await client.bulkShortenLinks({ links: [{ LongUrl: 'https://example.com' }] });
51
+ await client.bulkUpdateLinks({ links: [{ ShortURL: 'https://t.ly/abc' }] });
52
+ await client.getStats('https://t.ly/abc', { start_date: '2024-01-01', end_date: '2024-01-31' });
53
+ await client.getLinkStats('https://t.ly/xyz');
54
+
55
+ assert.deepEqual(calls.map((call) => `${call.method.toUpperCase()} ${call.url}`), [
56
+ 'POST /api/v1/link/shorten',
57
+ 'GET /api/v1/link',
58
+ 'PUT /api/v1/link',
59
+ 'DELETE /api/v1/link',
60
+ 'POST /api/v1/link/expand',
61
+ 'GET /api/v1/link/list',
62
+ 'POST /api/v1/link/bulk',
63
+ 'POST /api/v1/link/bulk/update',
64
+ 'GET /api/v1/link/stats',
65
+ 'GET /api/v1/link/stats',
66
+ ]);
67
+
68
+ assert.deepEqual(calls[1].config, {
69
+ params: { short_url: 'https://t.ly/abc' },
70
+ });
71
+ assert.deepEqual(calls[3].config, {
72
+ data: { short_url: 'https://t.ly/abc' },
73
+ });
74
+ assert.deepEqual(calls[8].config, {
75
+ params: {
76
+ short_url: 'https://t.ly/abc',
77
+ start_date: '2024-01-01',
78
+ end_date: '2024-01-31',
79
+ },
80
+ });
81
+ assert.deepEqual(calls[9].config, {
82
+ params: {
83
+ short_url: 'https://t.ly/xyz',
84
+ },
85
+ });
86
+ });
87
+
88
+ test('tag and pixel methods map to documented endpoints', async () => {
89
+ const { client, calls } = createClientWithRecorder();
90
+
91
+ await client.listTags();
92
+ await client.createTag({ tag: 'news' });
93
+ await client.getTag(123);
94
+ await client.updateTag(123, { tag: 'updates' });
95
+ await client.deleteTag(123);
96
+
97
+ await client.createPixel({ name: 'pixel', pixel_id: 'abc', pixel_type: 'facebook' });
98
+ await client.listPixels();
99
+ await client.getPixel(55);
100
+ await client.updatePixel(55, { name: 'pixel2', pixel_id: 'xyz', pixel_type: 'googleTagManager' });
101
+ await client.deletePixel(55);
102
+
103
+ assert.deepEqual(calls.map((call) => `${call.method.toUpperCase()} ${call.url}`), [
104
+ 'GET /api/v1/link/tag',
105
+ 'POST /api/v1/link/tag',
106
+ 'GET /api/v1/link/tag/123',
107
+ 'PUT /api/v1/link/tag/123',
108
+ 'DELETE /api/v1/link/tag/123',
109
+ 'POST /api/v1/link/pixel',
110
+ 'GET /api/v1/link/pixel',
111
+ 'GET /api/v1/link/pixel/55',
112
+ 'PUT /api/v1/link/pixel/55',
113
+ 'DELETE /api/v1/link/pixel/55',
114
+ ]);
115
+ });
116
+
117
+ test('onelink, utm preset, and qr methods map to documented endpoints', async () => {
118
+ const { client, calls } = createClientWithRecorder();
119
+
120
+ await client.getOneLinkStats('https://t.ly/one', { start_date: '2024-06-01', end_date: '2024-06-08' });
121
+ await client.deleteOneLinkStats({ short_url: 'https://t.ly/one' });
122
+ await client.listOneLinks({ page: 3 });
123
+
124
+ await client.createUtmPreset({
125
+ name: 'Newsletter Launch',
126
+ source: 'newsletter',
127
+ medium: 'email',
128
+ campaign: 'fall_launch',
129
+ content: 'hero-cta',
130
+ term: 'running-shoes',
131
+ });
132
+ await client.listUtmPresets();
133
+ await client.getUtmPreset(10);
134
+ await client.updateUtmPreset(10, { name: 'Updated Preset' });
135
+ await client.deleteUtmPreset(10);
136
+
137
+ await client.getQrCode({
138
+ short_url: 'https://t.ly/c55j',
139
+ output: 'base64',
140
+ format: 'eps',
141
+ });
142
+ await client.updateQrCode({
143
+ short_url: 'https://t.ly/c55j',
144
+ background_color: '#ffffff',
145
+ dots_color: '#000000',
146
+ });
147
+
148
+ assert.deepEqual(calls.map((call) => `${call.method.toUpperCase()} ${call.url}`), [
149
+ 'GET /api/v1/onelink/stats',
150
+ 'DELETE /api/v1/onelink/stat',
151
+ 'GET /api/v1/onelink/list',
152
+ 'POST /api/v1/link/utm-preset',
153
+ 'GET /api/v1/link/utm-preset',
154
+ 'GET /api/v1/link/utm-preset/10',
155
+ 'PUT /api/v1/link/utm-preset/10',
156
+ 'DELETE /api/v1/link/utm-preset/10',
157
+ 'GET /api/v1/link/qr-code',
158
+ 'PUT /api/v1/link/qr-code',
159
+ ]);
160
+
161
+ assert.deepEqual(calls[0].config, {
162
+ params: {
163
+ short_url: 'https://t.ly/one',
164
+ start_date: '2024-06-01',
165
+ end_date: '2024-06-08',
166
+ },
167
+ });
168
+ assert.deepEqual(calls[1].config, {
169
+ data: { short_url: 'https://t.ly/one' },
170
+ });
171
+ assert.deepEqual(calls[2].config, {
172
+ params: { page: 3 },
173
+ });
174
+ assert.deepEqual(calls[8].config, {
175
+ params: {
176
+ short_url: 'https://t.ly/c55j',
177
+ output: 'base64',
178
+ format: 'eps',
179
+ },
180
+ });
181
+ });