tiktokads
Advanced tools
Comparing version 1.0.21 to 1.1.0
@@ -19,3 +19,8 @@ { | ||
"require-jsdoc": 0 | ||
} | ||
} | ||
}, | ||
"ignorePatterns": [ | ||
"/*", | ||
"/*/", | ||
"!/src/" | ||
] | ||
} |
{ | ||
"name": "tiktokads", | ||
"version": "1.0.21", | ||
"version": "1.1.0", | ||
"description": "Wrapper for the tiktok ads api.", | ||
@@ -18,6 +18,4 @@ "license": "MIT", | ||
"scripts": { | ||
"build": "microbundle build", | ||
"dev": "microbundle watch --raw --cwd", | ||
"test": "node test.js", | ||
"prepublishOnly": "yarn build" | ||
"build": "tsc -p .", | ||
"dev": "npm run build -- -w" | ||
}, | ||
@@ -29,2 +27,3 @@ "dependencies": { | ||
"devDependencies": { | ||
"@types/node-fetch": "^2.6.2", | ||
"@typescript-eslint/eslint-plugin": "^5.30.6", | ||
@@ -31,0 +30,0 @@ "@typescript-eslint/parser": "^5.30.6", |
@@ -1,40 +0,40 @@ | ||
import { post, getText } from './api' | ||
import {post, getText} from './api'; | ||
async function getLongTermAccessToken(auth_code: string) { | ||
const data = { | ||
"app_id": process.env.TIKTOK_APP_ID, | ||
"auth_code": auth_code, | ||
"secret": process.env.TIKTOK_APP_SECRET | ||
} | ||
async function getLongTermAccessToken(authCode: string) { | ||
const data = { | ||
'app_id': process.env.TIKTOK_APP_ID, | ||
'auth_code': authCode, | ||
'secret': process.env.TIKTOK_APP_SECRET, | ||
}; | ||
return await post("", "/oauth2/access_token/", data); | ||
return await post('', '/oauth2/access_token/', data); | ||
} | ||
async function getAccounts(access_token: string) { | ||
const params = { | ||
access_token: access_token, | ||
app_id: process.env.TIKTOK_APP_ID, | ||
secret: process.env.TIKTOK_APP_SECRET | ||
}; | ||
async function getAccounts(refreshToken: string) { | ||
const params = { | ||
access_token: refreshToken, | ||
app_id: process.env.TIKTOK_APP_ID, | ||
secret: process.env.TIKTOK_APP_SECRET, | ||
}; | ||
const res = await getText("/oauth2/advertiser/get", {}, params); | ||
const advertisers = JSON.parse(res).data.list; | ||
const res = await getText('/oauth2/advertiser/get', {}, params); | ||
const advertisers = JSON.parse(res).data.list; | ||
var str = res; | ||
const str = res; | ||
// Manually read from the json to extract the ids as strings | ||
const stringIds = str.split('advertiser_id": ').map(el => { | ||
return el.substring(0, el.indexOf(",")) | ||
}) | ||
// Manually read from the json to extract the ids as strings | ||
const stringIds = str.split('advertiser_id": ').map((el) => { | ||
return el.substring(0, el.indexOf(',')); | ||
}); | ||
for (var i = 0; i < advertisers.length; i++) { | ||
advertisers[i]["advertiser_id"] = stringIds[1 + i]; | ||
} | ||
for (let i = 0; i < advertisers.length; i++) { | ||
advertisers[i]['advertiser_id'] = stringIds[1 + i]; | ||
} | ||
return advertisers; | ||
return advertisers; | ||
} | ||
export { | ||
getLongTermAccessToken, | ||
getAccounts | ||
} | ||
getLongTermAccessToken, | ||
getAccounts, | ||
}; |
124
src/api.ts
@@ -1,65 +0,85 @@ | ||
import fetch from 'node-fetch' | ||
import { baseUrl } from './constants' | ||
import fetch from 'node-fetch'; | ||
import {baseUrl} from './constants'; | ||
export const get = async (end_point: string, headers: object, params): Promise<any> => { | ||
return new Promise | ||
( | ||
export const get = async ( | ||
endPoint: string, | ||
headers?: { [key: string]: string; }, | ||
params?: any, | ||
): Promise<any> => { | ||
return new Promise( | ||
(resolve, reject) => { | ||
const params_url = (p: string | number | boolean) => | ||
Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&"); | ||
const paramsUrl = (p: string | number | boolean) => | ||
Object.entries(p).map( | ||
(kv) => kv.map(encodeURIComponent).join('='), | ||
).join('&'); | ||
const url = baseUrl + end_point + "?" + params_url(params) | ||
const url = baseUrl + endPoint + '?' + paramsUrl(params); | ||
fetch(url, | ||
{ | ||
method: "GET", | ||
headers: headers | ||
}) | ||
.then(res => res.json()) | ||
.then(data => { resolve(data) }) | ||
.catch(res => { reject(res) }) | ||
} | ||
) | ||
} | ||
{ | ||
method: 'GET', | ||
headers: headers, | ||
}) | ||
.then((res) => res.json()) | ||
.then((data) => { | ||
resolve(data); | ||
}) | ||
.catch((res) => { | ||
reject(res); | ||
}); | ||
}, | ||
); | ||
}; | ||
export const getText = async (end_point: string, headers: object, params): Promise<string> => { | ||
return new Promise | ||
( | ||
export const getText = async ( | ||
endPoint: string, | ||
headers?: { [key: string]: string; }, | ||
params?: any, | ||
): Promise<string> => { | ||
return new Promise( | ||
(resolve, reject) => { | ||
const params_url = (p: string | number | boolean) => | ||
Object.entries(p).map(kv => kv.map(encodeURIComponent).join("=")).join("&"); | ||
const paramsUrl = (p: string | number | boolean) => | ||
Object.entries(p).map( | ||
(kv) => kv.map(encodeURIComponent).join('='), | ||
).join('&'); | ||
const url = baseUrl + end_point + "?" + params_url(params) | ||
const url = baseUrl + endPoint + '?' + paramsUrl(params); | ||
fetch(url, | ||
{ | ||
method: "GET", | ||
headers: headers | ||
}) | ||
.then(res => res.text()) | ||
.then(data => { resolve(data) }) | ||
.catch(res => { reject(res) }) | ||
} | ||
) | ||
} | ||
{ | ||
method: 'GET', | ||
headers: headers, | ||
}) | ||
.then((res) => res.text()) | ||
.then((data) => { | ||
resolve(data); | ||
}) | ||
.catch((res) => { | ||
reject(res); | ||
}); | ||
}, | ||
); | ||
}; | ||
export const post = async (access_token: string, end_point: string, data: object): Promise<any> => { | ||
export const post = async (access_token: string, endPoint: string, data: object): Promise<any> => { | ||
return new Promise | ||
( | ||
( | ||
(resolve, reject) => { | ||
const url = baseUrl + end_point | ||
const url = baseUrl + endPoint; | ||
fetch(url, | ||
{ | ||
headers: { | ||
'Access-Token': access_token, | ||
'Accept': 'application/json', | ||
'Content-Type': 'application/json' | ||
}, | ||
method: "POST", | ||
body: JSON.stringify(data) | ||
}) | ||
.then(res => res.json()) | ||
.then(data => resolve(data)) | ||
.catch(res => { reject(res.json()) }) | ||
} | ||
) | ||
} | ||
{ | ||
headers: { | ||
'Access-Token': access_token, | ||
'Accept': 'application/json', | ||
'Content-Type': 'application/json', | ||
}, | ||
method: 'POST', | ||
body: JSON.stringify(data), | ||
}) | ||
.then((res) => res.json()) | ||
.then((data) => resolve(data)) | ||
.catch((res) => { | ||
reject(res.json()); | ||
}); | ||
}, | ||
); | ||
}; |
import {get} from './api.js'; | ||
export async function getCampaign(access_token: string, advertiser_id: string, campaign_id: string) { | ||
export async function getCampaign(refreshToken: string, advertiser_id: string, campaign_id: string) { | ||
const data = { | ||
@@ -13,3 +13,3 @@ 'advertiser_id': advertiser_id, | ||
'/campaign/get/', | ||
{'Access-Token': access_token}, | ||
{'Access-Token': refreshToken}, | ||
data, | ||
@@ -27,3 +27,3 @@ ); | ||
export async function getAdGroup(access_token: string, advertiser_id: string, campaign_id: string) { | ||
export async function getAdGroup(refreshToken: string, advertiser_id: string, campaign_id: string) { | ||
const data = { | ||
@@ -37,3 +37,3 @@ 'advertiser_id': advertiser_id, | ||
'/adgroup/get/', | ||
{'Access-Token': access_token}, | ||
{'Access-Token': refreshToken}, | ||
data, | ||
@@ -51,8 +51,11 @@ ); | ||
export async function getAd(access_token: string, advertiser_id: string, campaign_id: string) { | ||
export async function getAd( | ||
refreshToken: string, | ||
advertiserId: string | ||
) { | ||
const data = { | ||
'advertiser_id': advertiser_id, | ||
'advertiser_id': advertiserId, | ||
'page': 1, | ||
'page_size': 1, | ||
'filtering': JSON.stringify({'campaign_ids': [campaign_id]}), | ||
'filtering': JSON.stringify({'campaign_ids': [advertiserId]}), | ||
@@ -62,3 +65,3 @@ }; | ||
'/ad/get/', | ||
{'Access-Token': access_token}, | ||
{'Access-Token': refreshToken}, | ||
data, | ||
@@ -76,6 +79,9 @@ ); | ||
export async function getAllCampaigns(access_token: string, advertiser_id: string) { | ||
export async function getAllCampaigns( | ||
refreshToken: string, | ||
advertiserId: string, | ||
) { | ||
let isMore = true; | ||
let page = 1; | ||
let li = []; | ||
let li: any = []; | ||
@@ -85,5 +91,5 @@ while (isMore) { | ||
'/campaign/get/', | ||
{'Access-Token': access_token}, | ||
{'Access-Token': refreshToken}, | ||
{ | ||
'advertiser_id': advertiser_id, | ||
'advertiser_id': advertiserId, | ||
'page': page, | ||
@@ -90,0 +96,0 @@ 'page_size': 1000, |
@@ -1,17 +0,17 @@ | ||
import { get } from './api.js' | ||
import {get} from './api.js'; | ||
export async function getIdentities(refreshToken: string, advertiserId: string) { | ||
let res, data; | ||
export async function getIdentities( | ||
refreshToken: string, | ||
advertiserId: string) { | ||
const data = { | ||
advertiser_id: advertiserId, | ||
}; | ||
data = { | ||
advertiser_id: advertiserId, | ||
}; | ||
const res = await get('/identity/get/', {'Access-Token': refreshToken}, data); | ||
res = await get('/identity/get/', { 'Access-Token': refreshToken }, data); | ||
if (res.code != 0) { | ||
throw new Error(res.message); | ||
} | ||
if (res.code != 0) { | ||
throw new Error(res.message); | ||
} | ||
return res.data.list; | ||
} | ||
return res.data.list; | ||
} |
@@ -1,12 +0,12 @@ | ||
import {get, getText, post} from './api'; | ||
import {getLongTermAccessToken, getAccounts} from './accounts'; | ||
import {getRegions} from './regions'; | ||
import {getInterests} from './interests'; | ||
import {getIdentities} from './identity'; | ||
import {getCampaign, getAdGroup, getAd, getAllCampaigns} from './campaigns'; | ||
import {suggestThumbnail, getPostThumbnail} from './thumbnail'; | ||
import {getMetrics} from './metrics'; | ||
import {uploadVideo, getVideos} from './videos'; | ||
import {getPixels, getEvents} from './pixels'; | ||
import {authPost, applyAuth} from './spark'; | ||
import {get, getText, post} from './api.js'; | ||
import {getLongTermAccessToken, getAccounts} from './accounts.js'; | ||
import {getRegions} from './regions.js'; | ||
import {getInterests} from './interests.js'; | ||
import {getIdentities} from './identity.js'; | ||
import {getCampaign, getAdGroup, getAd, getAllCampaigns} from './campaigns.js'; | ||
import {suggestThumbnail, getPostThumbnail} from './thumbnail.js'; | ||
import {getMetrics} from './metrics.js'; | ||
import {uploadVideo, getVideos} from './videos.js'; | ||
import {getPixels, getEvents} from './pixels.js'; | ||
import {authPost, applyAuth} from './spark.js'; | ||
@@ -13,0 +13,0 @@ class TiktokAdsClient { |
@@ -1,25 +0,29 @@ | ||
import { get } from './api.js' | ||
import {get} from './api.js'; | ||
// TODO: store results in a semi permanent manner | ||
export async function getInterests(query, access_token, advertiser_id) { | ||
const res = await get( | ||
'/tools/interest_keyword/recommend/', | ||
{ 'Access-Token': access_token }, | ||
{ | ||
'advertiser_id': advertiser_id, | ||
'keywords': `["${query}"]`, | ||
} | ||
) | ||
export async function getInterests( | ||
query: string, | ||
refreshToken: string, | ||
advertiserId: string, | ||
) { | ||
const res = await get( | ||
'/tools/interest_keyword/recommend/', | ||
{'Access-Token': refreshToken}, | ||
{ | ||
'advertiser_id': advertiserId, | ||
'keywords': `["${query}"]`, | ||
}, | ||
); | ||
// const region_names = []; | ||
// const region_obj = {}; | ||
// const region_names = []; | ||
// const region_obj = {}; | ||
// res.data.region_info.forEach(element => { | ||
// region_names.push(element.name); | ||
// region_obj[element.name] = element; | ||
// }) | ||
// res.data.region_info.forEach(element => { | ||
// region_names.push(element.name); | ||
// region_obj[element.name] = element; | ||
// }) | ||
// region_names.sort() | ||
// region_names.sort() | ||
return res; | ||
return res; | ||
} |
@@ -1,72 +0,74 @@ | ||
import { getText } from './api.js' | ||
import {getText} from './api.js'; | ||
export async function getPixels(access_token: string, advertiser_id: string) { | ||
const data = { | ||
'advertiser_id': advertiser_id, | ||
'page_size': 20 | ||
} | ||
const resText = await getText( | ||
'/pixel/list/', | ||
{ 'Access-Token': access_token }, | ||
data | ||
) | ||
export async function getPixels( | ||
refreshToken: string, | ||
advertiserId: string, | ||
) { | ||
const data = { | ||
'advertiser_id': advertiserId, | ||
'page_size': 20, | ||
}; | ||
const resText = await getText( | ||
'/pixel/list/', | ||
{'Access-Token': refreshToken}, | ||
data, | ||
); | ||
const res = JSON.parse(resText); | ||
const res = JSON.parse(resText); | ||
if (res.code != 0) { | ||
throw new Error(res.message); | ||
} | ||
if (res.code != 0) { | ||
throw new Error(res.message); | ||
} | ||
const pixels = res.data.pixels; | ||
const pixels = res.data.pixels; | ||
if (pixels.length > 0) { | ||
const pixelIds = resText.split('pixel_id": ').map(el => { | ||
return el.match(/[0-9]+/)[0] | ||
}) | ||
pixelIds.shift(); | ||
pixels.forEach((val, i: number) => { | ||
val.pixel_id = pixelIds[i]; | ||
}); | ||
const eventIds = resText.split('event_id": ').map(el => { | ||
return el.substring(0, el.indexOf(",")) | ||
}) | ||
eventIds.shift(); | ||
if (pixels.length > 0) { | ||
const pixelIds = resText.split('pixel_id": ').map((el) => { | ||
return el.match(/[0-9]+/)![0]; | ||
}); | ||
pixelIds.shift(); | ||
pixels.forEach((val: any, i: number) => { | ||
val.pixel_id = pixelIds[i]; | ||
}); | ||
let index = 0; | ||
pixels.forEach((pixel) => { | ||
pixel.events.forEach((event) => { | ||
event.event_id = eventIds[index]; | ||
index++; | ||
}); | ||
}); | ||
const eventIds = resText.split('event_id": ').map((el) => { | ||
return el.substring(0, el.indexOf(',')); | ||
}); | ||
eventIds.shift(); | ||
return pixels; | ||
} | ||
else { | ||
return [] | ||
} | ||
let index = 0; | ||
pixels.forEach((pixel: any) => { | ||
pixel.events.forEach((event:any) => { | ||
event.event_id = eventIds[index]; | ||
index++; | ||
}); | ||
}); | ||
return pixels; | ||
} else { | ||
return []; | ||
} | ||
} | ||
export async function getEvents(access_token: string, advertiser_id: string) { | ||
const data = { | ||
'advertiser_id': advertiser_id, | ||
'placement': ["PLACEMENT_TIKTOK"], | ||
'objective': "CONVERSIONS", | ||
'optimizeGoal': "CONVERT", | ||
} | ||
const resText = await getText( | ||
'/app/external_action/', | ||
{ 'Access-Token': access_token }, | ||
data | ||
) | ||
export async function getEvents(refreshToken: string, advertiserId: string) { | ||
const data = { | ||
'advertiser_id': advertiserId, | ||
'placement': ['PLACEMENT_TIKTOK'], | ||
'objective': 'CONVERSIONS', | ||
'optimizeGoal': 'CONVERT', | ||
}; | ||
const resText = await getText( | ||
'/app/external_action/', | ||
{'Access-Token': refreshToken}, | ||
data, | ||
); | ||
const res = JSON.parse(resText); | ||
const res = JSON.parse(resText); | ||
if (res.code != 0) { | ||
throw new Error(res.message); | ||
} | ||
if (res.code != 0) { | ||
throw new Error(res.message); | ||
} | ||
return res; | ||
} | ||
return res; | ||
} |
@@ -1,43 +0,53 @@ | ||
import { get } from './api.js' | ||
import {get} from './api.js'; | ||
// TODO: store results in a semi permanent manner | ||
export async function getRegions(query, access_token, advertiser_id, objective_type) { | ||
const [region_names, region_obj] = await getRegionsLists(access_token, advertiser_id, objective_type); | ||
export async function getRegions( | ||
query: string, | ||
refreshToken: string, | ||
advertiserId: string, | ||
objectiveType: string, | ||
) { | ||
const [regionNames, regionObj] = await getRegionsLists( | ||
refreshToken, advertiserId, objectiveType); | ||
const res = []; | ||
const queryUpper = query.toUpperCase(); | ||
const res:any[] = []; | ||
const queryUpper = query.toUpperCase(); | ||
region_names.forEach(element => { | ||
if (element.toUpperCase().includes(queryUpper)) { | ||
res.push(region_obj[element]); | ||
} | ||
}) | ||
regionNames.forEach((element) => { | ||
if (element.toUpperCase().includes(queryUpper)) { | ||
res.push(regionObj[element]); | ||
} | ||
}); | ||
return res; | ||
return res; | ||
} | ||
async function getRegionsLists(access_token, advertiser_id, objective_type): Promise<[string[], any]> { | ||
// https://ads.tiktok.com/open_api/v1.2/tools/regions/?advertiser_id=7075631377437229057&placement=[%22PLACEMENT_TIKTOK%22]&objective_type=TRAFFIC | ||
async function getRegionsLists( | ||
refreshToken: string, | ||
advertiserId: string, | ||
objectiveType: string, | ||
): Promise<[string[], any]> { | ||
// https://ads.tiktok.com/open_api/v1.2/tools/regions/?advertiser_id=7075631377437229057&placement=[%22PLACEMENT_TIKTOK%22]&objective_type=TRAFFIC | ||
const res = await get( | ||
'/tools/regions/', | ||
{ 'Access-Token': access_token }, | ||
{ | ||
'advertiser_id': advertiser_id, | ||
'placement': '["PLACEMENT_TIKTOK"]', | ||
'objective_type': objective_type | ||
} | ||
) | ||
const res = await get( | ||
'/tools/regions/', | ||
{'Access-Token': refreshToken}, | ||
{ | ||
'advertiser_id': advertiserId, | ||
'placement': '["PLACEMENT_TIKTOK"]', | ||
'objective_type': objectiveType, | ||
}, | ||
); | ||
const region_names = []; | ||
const region_obj = {}; | ||
const regionNames:string[] = []; | ||
const regionObj:any = {}; | ||
res.data.region_info.forEach(element => { | ||
region_names.push(element.name); | ||
region_obj[element.name] = element; | ||
}) | ||
res.data.region_info.forEach((element: any) => { | ||
regionNames.push(element.name); | ||
regionObj[element.name] = element; | ||
}); | ||
region_names.sort() | ||
regionNames.sort(); | ||
return [region_names, region_obj]; | ||
} | ||
return [regionNames, regionObj]; | ||
} |
@@ -26,3 +26,3 @@ import {get, getText, post} from './api.js'; | ||
const stringIds = resText.split('"item_id": ').map((el) => { | ||
return el.match(/[0-9]+/)[0]; | ||
return el.match(/[0-9]+/)![0]; | ||
}); | ||
@@ -38,6 +38,8 @@ | ||
export async function applyAuth(refreshToken: string, advertiserId: string, authCode: string) { | ||
let data; let res; | ||
data = { | ||
export async function applyAuth( | ||
refreshToken: string, | ||
advertiserId: string, | ||
authCode: string, | ||
) { | ||
const data = { | ||
'advertiser_id': advertiserId, | ||
@@ -47,3 +49,3 @@ 'auth_code': authCode, | ||
res = await post( | ||
const res = await post( | ||
refreshToken, '/tt_video/authorize/', data, | ||
@@ -50,0 +52,0 @@ ); |
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Network access
Supply chain riskThis module accesses the network.
Found 1 instance in 1 package
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
1098
1
5
39675
7
33
4