TikTok api
This commit is contained in:
98
server/lib/tiktok.js
Normal file
98
server/lib/tiktok.js
Normal file
@@ -0,0 +1,98 @@
|
||||
const { get, run } = require('./postgres');
|
||||
|
||||
const TIKTOK_ACCOUNT_KEY = 'hermes-agent';
|
||||
|
||||
const saveTiktokTokens = async (db, tokens) => {
|
||||
const now = Date.now();
|
||||
const accessExpiresAt = new Date(now + Number(tokens.expires_in || 0) * 1000);
|
||||
const refreshExpiresAt = tokens.refresh_expires_in
|
||||
? new Date(now + Number(tokens.refresh_expires_in) * 1000)
|
||||
: null;
|
||||
|
||||
await run(
|
||||
db,
|
||||
`INSERT INTO tiktok_tokens (account_key, open_id, access_token, refresh_token, scope, access_token_expires_at, refresh_token_expires_at, updated_at)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP)
|
||||
ON CONFLICT (account_key) DO UPDATE SET
|
||||
open_id = EXCLUDED.open_id,
|
||||
access_token = EXCLUDED.access_token,
|
||||
refresh_token = EXCLUDED.refresh_token,
|
||||
scope = EXCLUDED.scope,
|
||||
access_token_expires_at = EXCLUDED.access_token_expires_at,
|
||||
refresh_token_expires_at = EXCLUDED.refresh_token_expires_at,
|
||||
updated_at = CURRENT_TIMESTAMP`,
|
||||
[
|
||||
TIKTOK_ACCOUNT_KEY,
|
||||
tokens.open_id,
|
||||
tokens.access_token,
|
||||
tokens.refresh_token,
|
||||
tokens.scope || null,
|
||||
accessExpiresAt,
|
||||
refreshExpiresAt,
|
||||
],
|
||||
);
|
||||
};
|
||||
|
||||
const getTiktokTokens = async (db) =>
|
||||
get(db, `SELECT * FROM tiktok_tokens WHERE account_key = ?`, [TIKTOK_ACCOUNT_KEY]);
|
||||
|
||||
const exchangeCodeForTokens = async ({ code, clientKey, clientSecret, redirectUri }) => {
|
||||
const response = await fetch('https://open.tiktokapis.com/v2/oauth/token/', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
client_key: clientKey,
|
||||
client_secret: clientSecret,
|
||||
code,
|
||||
grant_type: 'authorization_code',
|
||||
redirect_uri: redirectUri,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (!response.ok || data.error) {
|
||||
const message = data.error_description || data.error || 'TikTok token exchange failed.';
|
||||
const error = new Error(message);
|
||||
error.status = 502;
|
||||
throw error;
|
||||
}
|
||||
return data;
|
||||
};
|
||||
|
||||
const refreshTiktokTokens = async (db, { clientKey, clientSecret }) => {
|
||||
const existing = await getTiktokTokens(db);
|
||||
if (!existing) {
|
||||
const error = new Error('No TikTok account connected.');
|
||||
error.status = 404;
|
||||
throw error;
|
||||
}
|
||||
|
||||
const response = await fetch('https://open.tiktokapis.com/v2/oauth/token/', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
||||
body: new URLSearchParams({
|
||||
client_key: clientKey,
|
||||
client_secret: clientSecret,
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: existing.refresh_token,
|
||||
}),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
if (!response.ok || data.error) {
|
||||
const message = data.error_description || data.error || 'TikTok token refresh failed.';
|
||||
const error = new Error(message);
|
||||
error.status = 502;
|
||||
throw error;
|
||||
}
|
||||
|
||||
await saveTiktokTokens(db, data);
|
||||
return getTiktokTokens(db);
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
exchangeCodeForTokens,
|
||||
getTiktokTokens,
|
||||
refreshTiktokTokens,
|
||||
saveTiktokTokens,
|
||||
};
|
||||
Reference in New Issue
Block a user