@dat-platform/advertiser
Version:
An SDK for advertisers to track user actions, such as Telegram channel or bot joins, and notify publishers upon completion.
447 lines (433 loc) • 19.9 kB
JavaScript
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol, Iterator */
var extendStatics = function(d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
function __extends(d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
}
function __awaiter(thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
}
function __generator(thisArg, body) {
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
function verb(n) { return function (v) { return step([n, v]); }; }
function step(op) {
if (f) throw new TypeError("Generator is already executing.");
while (g && (g = 0, op[0] && (_ = 0)), _) try {
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
if (y = 0, t) op = [op[0] & 2, t.value];
switch (op[0]) {
case 0: case 1: t = op; break;
case 4: _.label++; return { value: op[1], done: false };
case 5: _.label++; y = op[1]; op = [0]; continue;
case 7: op = _.ops.pop(); _.trys.pop(); continue;
default:
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
if (t[2]) _.ops.pop();
_.trys.pop(); continue;
}
op = body.call(thisArg, _);
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
}
}
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
/** @class */ ((function (_super) {
__extends(APIError, _super);
function APIError(message, code, details) {
var _this = _super.call(this, message) || this;
_this.code = code;
_this.details = details;
_this.name = 'APIError';
return _this;
}
return APIError;
})(Error));
var DEFAULT_BASE_URL = 'https://cms.datplatform.com';
var AuthManager = /** @class */ (function () {
function AuthManager(config) {
this.token = null;
this.userId = null;
this.tokenExpiration = null;
this.apiKey = config.apiKey;
this.baseURL = config.baseURL || DEFAULT_BASE_URL;
}
AuthManager.prototype.parseJwt = function (token) {
try {
var base64Url = token.split('.')[1];
var base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
var jsonPayload = decodeURIComponent(atob(base64).split('').map(function (c) {
return '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2);
}).join(''));
return JSON.parse(jsonPayload);
}
catch (error) {
console.warn('Error parsing JWT token:', error);
return {};
}
};
AuthManager.prototype.setAuthData = function (response) {
if (!response.results || !response.results.token) {
throw new Error('Invalid authentication response');
}
this.token = response.results.token;
this.userId = response.results.user_id;
if (this.token) {
var decoded = this.parseJwt(this.token);
if (decoded.exp) {
this.tokenExpiration = decoded.exp * 1000;
}
else {
// Set a default expiration of 1 hour if not provided
this.tokenExpiration = Date.now() + (60 * 60 * 1000);
}
// Debug log
// console.log('Token set successfully:', {
// hasToken: !!this.token,
// hasUserId: !!this.userId,
// expiration: new Date(this.tokenExpiration || 0).toISOString()
// });
}
};
AuthManager.prototype.isTokenExpired = function () {
if (!this.tokenExpiration)
return false;
// Add 5-second buffer to prevent edge cases
return Date.now() > (this.tokenExpiration - 5000);
};
AuthManager.prototype.initialize = function () {
var _a;
return __awaiter(this, void 0, void 0, function () {
var result, response, error_1;
return __generator(this, function (_b) {
switch (_b.label) {
case 0:
_b.trys.push([0, 3, , 4]);
return [4 /*yield*/, fetch("".concat(this.baseURL, "/auth/verify"), {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey
}
})];
case 1:
result = _b.sent();
if (!result.ok) {
if (result.status === 401 || result.status === 403) {
this.clearAuth();
throw new Error('Invalid API key');
}
throw new Error("HTTP error! status: ".concat(result.status));
}
return [4 /*yield*/, result.json()];
case 2:
response = _b.sent();
if (response.status === 200 && ((_a = response.results) === null || _a === void 0 ? void 0 : _a.token)) {
this.setAuthData(response);
return [2 /*return*/, true];
}
return [2 /*return*/, false];
case 3:
error_1 = _b.sent();
this.clearAuth();
throw new Error("Authentication failed: ".concat(error_1 instanceof Error ? error_1.message : 'Unknown error'));
case 4: return [2 /*return*/];
}
});
});
};
AuthManager.prototype.refreshTokenIfNeeded = function () {
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
if (this.isTokenExpired()) {
return [2 /*return*/, this.initialize()];
}
return [2 /*return*/, true];
});
});
};
AuthManager.prototype.getValidToken = function () {
return __awaiter(this, void 0, void 0, function () {
var error_2;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
if (!(!this.token || this.isTokenExpired())) return [3 /*break*/, 2];
console.log('Token needs refresh...');
return [4 /*yield*/, this.initialize()];
case 1:
_a.sent();
_a.label = 2;
case 2:
if (!this.token) {
throw new Error('Unable to obtain valid token');
}
return [2 /*return*/, this.token];
case 3:
error_2 = _a.sent();
console.error('Token validation error:', error_2);
throw error_2;
case 4: return [2 /*return*/];
}
});
});
};
AuthManager.prototype.getUserId = function () {
if (!this.userId) {
throw new Error('User ID not available');
}
return this.userId;
};
AuthManager.prototype.getToken = function () {
return this.token;
};
AuthManager.prototype.isAuthenticated = function () {
return this.token !== null && !this.isTokenExpired();
};
AuthManager.prototype.clearAuth = function () {
this.token = null;
this.userId = null;
this.tokenExpiration = null;
};
return AuthManager;
}());
var AdsManager = /** @class */ (function () {
function AdsManager(config) {
this.apiKey = config.apiKey;
this.baseURL = config.baseURL || DEFAULT_BASE_URL;
}
AdsManager.prototype.getAds = function () {
return __awaiter(this, void 0, void 0, function () {
var adv_creative;
return __generator(this, function (_a) {
try {
adv_creative = {
creative: [
{
creative_id: 1,
icon: "https://example.com/icons/video-icon.png",
title: "Watch an ad today 📺",
description: "Watch an ad and earn. It's that simple.",
rewardContent: "1 coins",
clickTaskTrackingUrl: "https://adnetwork.com/v?id=[taskid]",
redirectlink: "https://adnetwork.com/c?id=[taskid]"
}
]
};
return [2 /*return*/, adv_creative];
//---remove this code after testing END
}
catch (error) {
throw new Error("Failed to fetch ads: ".concat(error instanceof Error ? error.message : 'Unknown error'));
}
return [2 /*return*/];
});
});
};
AdsManager.prototype.showAd = function (adId) {
return __awaiter(this, void 0, void 0, function () {
var result, response, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 3, , 4]);
return [4 /*yield*/, fetch("".concat(this.baseURL, "/ads/").concat(adId, "/show"), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': this.apiKey
}
})];
case 1:
result = _a.sent();
return [4 /*yield*/, result.json()];
case 2:
response = _a.sent();
return [2 /*return*/, response.success];
case 3:
error_1 = _a.sent();
throw new Error("Failed to show ad: ".concat(error_1 instanceof Error ? error_1.message : 'Unknown error'));
case 4: return [2 /*return*/];
}
});
});
};
return AdsManager;
}());
var OfferManager = /** @class */ (function () {
function OfferManager(config) {
this.apiKey = config.apiKey;
this.baseURL = config.baseURL || DEFAULT_BASE_URL;
this.authManager = new AuthManager(config);
}
OfferManager.prototype.isWebAppAvailable = function () {
return typeof window !== 'undefined' &&
window.Telegram !== undefined &&
window.Telegram.WebApp !== undefined;
};
OfferManager.prototype.getTelegramUserId = function () {
var _a, _b, _c, _d;
if (!this.isWebAppAvailable()) {
return null;
}
return ((_d = (_c = (_b = (_a = window.Telegram) === null || _a === void 0 ? void 0 : _a.WebApp) === null || _b === void 0 ? void 0 : _b.initDataUnsafe) === null || _c === void 0 ? void 0 : _c.user) === null || _d === void 0 ? void 0 : _d.id) || null;
};
OfferManager.prototype.markActionComplete = function (advertiserId, idToken, autoClose) {
if (autoClose === void 0) { autoClose = false; }
return __awaiter(this, void 0, void 0, function () {
var result, responseText, response, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
_a.trys.push([0, 4, , 5]);
return [4 /*yield*/, this.authManager.getValidToken()];
case 1:
_a.sent();
return [4 /*yield*/, fetch("".concat(this.baseURL, "/advertiser/completionRewardWebhook"), {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
advertiserId: advertiserId,
idToken: idToken
})
})];
case 2:
result = _a.sent();
return [4 /*yield*/, result.text()];
case 3:
responseText = _a.sent();
response = JSON.parse(responseText);
// Update success check based on API response
if (response.status !== 200) ;
if (autoClose) {
setTimeout(function () {
//auto close current window tab and navigate to previous history link
window.close();
// window.history.back();
}, 1000);
}
return [2 /*return*/, response.results];
case 4:
error_1 = _a.sent();
throw new Error("Failed to send rewards: ".concat(error_1 instanceof Error ? error_1.message : 'Unknown error'));
case 5: return [2 /*return*/];
}
});
});
};
return OfferManager;
}());
var K2SDK = /** @class */ (function () {
function K2SDK(config) {
this.initialized = false;
if (!config.apiKey) {
throw new Error('API Key is required');
}
this.authManager = new AuthManager(config);
this.adsManager = new AdsManager(config);
this.offerManager = new OfferManager(config);
}
K2SDK.initialize = function (config) {
return __awaiter(this, void 0, void 0, function () {
var isAuthenticated, error_1;
return __generator(this, function (_a) {
switch (_a.label) {
case 0:
if (!!K2SDK.instance) return [3 /*break*/, 4];
K2SDK.instance = new K2SDK(config);
_a.label = 1;
case 1:
_a.trys.push([1, 3, , 4]);
return [4 /*yield*/, K2SDK.instance.authManager.initialize()];
case 2:
isAuthenticated = _a.sent();
if (!isAuthenticated) {
throw new Error('Authentication failed');
}
K2SDK.instance.initialized = true;
return [3 /*break*/, 4];
case 3:
error_1 = _a.sent();
K2SDK.instance = null;
throw new Error("SDK initialization failed: ".concat(error_1 instanceof Error ? error_1.message : 'Unknown error'));
case 4: return [2 /*return*/, K2SDK.instance];
}
});
});
};
K2SDK.getInstance = function () {
if (!K2SDK.instance || !K2SDK.instance.initialized) {
throw new Error('SDK not initialized. Call K2SDK.initialize(config) first');
}
return K2SDK.instance;
};
K2SDK.prototype.getTelegramUserId = function () {
var userId = this.offerManager.getTelegramUserId();
if (!userId) {
throw new Error('Telegram platform not detected. Run this on Telegram to get ID');
}
return userId;
};
K2SDK.prototype.isTelegramWebAppAvailable = function () {
return this.offerManager.isWebAppAvailable();
};
K2SDK.prototype.isInitialized = function () {
return this.initialized;
};
K2SDK.reset = function () {
K2SDK.instance = null;
};
K2SDK.prototype.markActionComplete = function (advertiserId, idToken, autoClose) {
if (autoClose === void 0) { autoClose = false; }
return __awaiter(this, void 0, void 0, function () {
return __generator(this, function (_a) {
switch (_a.label) {
case 0: return [4 /*yield*/, this.offerManager.markActionComplete(advertiserId, idToken, autoClose)];
case 1: return [2 /*return*/, _a.sent()];
}
});
});
};
K2SDK.instance = null;
return K2SDK;
}());
if (typeof module !== 'undefined' && module.exports) {
module.exports = K2SDK;
}
export { K2SDK as default };
//# sourceMappingURL=index.esm.js.map