@adstelo/sdk 0.1.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/README.md ADDED
@@ -0,0 +1,76 @@
1
+ # @adstelo/sdk
2
+
3
+ Adstelo JS SDK for Telegram bots. Supports Telegraf, grammY, and manual event reporting.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @adstelo/sdk
9
+ ```
10
+
11
+ ## Quick Start (One-liner)
12
+
13
+ ```js
14
+ import { Bot } from "grammy";
15
+ import { adstelo } from "@adstelo/sdk";
16
+
17
+ const bot = new Bot(process.env.BOT_TOKEN);
18
+
19
+ bot.use(
20
+ adstelo.grammy({
21
+ botSecret: process.env.ADSTELO_BOT_SECRET,
22
+ apiKey: process.env.ADSTELO_API_KEY,
23
+ cooldownSeconds: 2
24
+ })
25
+ );
26
+ ```
27
+
28
+ ## Optional Explicit Init
29
+
30
+ ```js
31
+ import { adstelo, init } from "@adstelo/sdk";
32
+
33
+ init({ botSecret: "bs-...", apiKey: "sk-..." });
34
+
35
+ bot.use(adstelo.grammy());
36
+ ```
37
+
38
+ ## Telegraf
39
+
40
+ ```js
41
+ import { Telegraf } from "telegraf";
42
+ import { adstelo } from "@adstelo/sdk";
43
+
44
+ const bot = new Telegraf(process.env.BOT_TOKEN);
45
+
46
+ bot.use(
47
+ adstelo.telegraf({
48
+ botSecret: process.env.ADSTELO_BOT_SECRET,
49
+ apiKey: process.env.ADSTELO_API_KEY
50
+ })
51
+ );
52
+ ```
53
+
54
+ ## Manual Hook (no middleware)
55
+
56
+ ```js
57
+ import { init, reportEvent } from "@adstelo/sdk";
58
+
59
+ init({ botSecret: "bs-...", apiKey: "sk-..." });
60
+
61
+ // In your update handler:
62
+ reportEvent({
63
+ chatId: msg.chat.id,
64
+ userId: msg.from.id,
65
+ event: "message",
66
+ isStart: msg.text === "/start"
67
+ });
68
+ ```
69
+
70
+ ## API
71
+
72
+ - `init({ botSecret, apiKey, cooldownSeconds })`
73
+ - `validateInitCredentials()`
74
+ - `reportEvent({ chatId, userId, event, isStart })`
75
+ - `adstelo.telegraf(options?)`
76
+ - `adstelo.grammy(options?)`
package/dist/index.cjs ADDED
@@ -0,0 +1,228 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+
30
+ // src/index.ts
31
+ var index_exports = {};
32
+ __export(index_exports, {
33
+ _internal: () => _internal,
34
+ adstelo: () => adstelo,
35
+ init: () => init,
36
+ reportEvent: () => reportEvent,
37
+ validateInitCredentials: () => validateInitCredentials
38
+ });
39
+ module.exports = __toCommonJS(index_exports);
40
+ var import_node_crypto = __toESM(require("crypto"), 1);
41
+ var DEFAULT_BASE_URL = "https://sdk.adstelo.com";
42
+ var config = {
43
+ apiKey: null,
44
+ botSecret: null,
45
+ endpoint: `${DEFAULT_BASE_URL}/event`,
46
+ validateEndpoint: `${DEFAULT_BASE_URL}/event/validate`,
47
+ cooldownSeconds: 2
48
+ };
49
+ var initialized = false;
50
+ var validationPromise = null;
51
+ var cooldownMap = /* @__PURE__ */ new Map();
52
+ function buildHeaders(payloadBytes) {
53
+ const headers = {
54
+ "Content-Type": "application/json",
55
+ "ngrok-skip-browser-warning": "true"
56
+ };
57
+ if (config.apiKey) {
58
+ headers["X-Api-Key"] = config.apiKey;
59
+ const signature = import_node_crypto.default.createHmac("sha256", config.apiKey).update(payloadBytes).digest("hex");
60
+ headers["X-Signature"] = signature;
61
+ }
62
+ return headers;
63
+ }
64
+ function nowSeconds() {
65
+ return Math.floor(Date.now() / 1e3);
66
+ }
67
+ function cooldownKey(userId, event) {
68
+ return `${userId}:${event}`;
69
+ }
70
+ function allowEvent(userId, event) {
71
+ const key = cooldownKey(userId, event);
72
+ const current = nowSeconds();
73
+ const last = cooldownMap.get(key) ?? 0;
74
+ if (current - last < config.cooldownSeconds) {
75
+ return false;
76
+ }
77
+ cooldownMap.set(key, current);
78
+ return true;
79
+ }
80
+ function init(options) {
81
+ if (!options || !options.botSecret || !options.apiKey) {
82
+ throw new Error("botSecret and apiKey are required");
83
+ }
84
+ config.botSecret = options.botSecret;
85
+ config.apiKey = options.apiKey;
86
+ config.cooldownSeconds = options.cooldownSeconds ?? 2;
87
+ const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
88
+ config.endpoint = `${baseUrl.replace(/\/$/, "")}/event`;
89
+ config.validateEndpoint = `${baseUrl.replace(/\/$/, "")}/event/validate`;
90
+ initialized = true;
91
+ }
92
+ function ensureInit(options) {
93
+ if (initialized) return;
94
+ if (!options?.botSecret || !options?.apiKey) {
95
+ throw new Error("Missing botSecret or apiKey. Pass them to adstelo.grammy/adstelo.telegraf or call init().");
96
+ }
97
+ init(options);
98
+ if (!validationPromise) {
99
+ validationPromise = validateInitCredentials().then(({ ok, detail }) => {
100
+ if (!ok) {
101
+ console.error("[adstelo] init validation failed:", detail);
102
+ process.exit(1);
103
+ }
104
+ console.log("[adstelo] init validation ok");
105
+ }).catch((err) => {
106
+ console.error("[adstelo] init validation failed:", err?.message || err);
107
+ process.exit(1);
108
+ });
109
+ }
110
+ }
111
+ async function validateInitCredentials() {
112
+ if (!config.botSecret) {
113
+ return { ok: false, detail: "Missing botSecret" };
114
+ }
115
+ if (!config.apiKey) {
116
+ return { ok: false, detail: "Missing apiKey" };
117
+ }
118
+ const payload = { secret: config.botSecret };
119
+ const payloadBytes = JSON.stringify(payload);
120
+ const res = await fetch(config.validateEndpoint, {
121
+ method: "POST",
122
+ headers: buildHeaders(payloadBytes),
123
+ body: payloadBytes
124
+ });
125
+ if (res.ok) {
126
+ return { ok: true, detail: "ok" };
127
+ }
128
+ let detail = `HTTP ${res.status}`;
129
+ try {
130
+ const data = await res.json();
131
+ if (data && typeof data.detail === "string") {
132
+ detail = data.detail;
133
+ }
134
+ } catch {
135
+ }
136
+ return { ok: false, detail };
137
+ }
138
+ async function reportEvent(input) {
139
+ if (!config.botSecret || !config.apiKey) {
140
+ throw new Error("SDK not initialized. Call init() first.");
141
+ }
142
+ if (!input?.userId || !input?.event) {
143
+ return { ok: false, detail: "Missing userId or event" };
144
+ }
145
+ if (!allowEvent(input.userId, input.event)) {
146
+ return { ok: true, detail: "cooldown" };
147
+ }
148
+ const payload = {
149
+ chat_id: input.chatId,
150
+ user_id: input.userId,
151
+ event: input.event,
152
+ ts: Date.now() / 1e3,
153
+ is_start: Boolean(input.isStart),
154
+ secret: config.botSecret
155
+ };
156
+ const payloadBytes = JSON.stringify(payload);
157
+ const res = await fetch(config.endpoint, {
158
+ method: "POST",
159
+ headers: buildHeaders(payloadBytes),
160
+ body: payloadBytes
161
+ });
162
+ return { ok: res.ok, status: res.status };
163
+ }
164
+ function inferEventFromMessage(message) {
165
+ if (!message) return "message";
166
+ if (message.photo?.length) return "photo";
167
+ if (message.video) return "video";
168
+ if (message.sticker) return "sticker";
169
+ if (message.animation) return "media";
170
+ return "message";
171
+ }
172
+ function adsteloTelegrafMiddleware(options) {
173
+ ensureInit(options);
174
+ return async (ctx, next) => {
175
+ try {
176
+ const event = ctx?.callbackQuery ? "button" : ctx?.inlineQuery ? "inline_query" : inferEventFromMessage(ctx?.message);
177
+ const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;
178
+ const userId = ctx?.from?.id;
179
+ const isStart = typeof ctx?.message?.text === "string" && ctx.message.text.startsWith("/start");
180
+ if (chatId && userId) {
181
+ await reportEvent({ chatId, userId, event, isStart });
182
+ }
183
+ } catch {
184
+ }
185
+ if (next) {
186
+ await next();
187
+ }
188
+ };
189
+ }
190
+ function adsteloGrammyMiddleware(options) {
191
+ ensureInit(options);
192
+ return async (ctx, next) => {
193
+ try {
194
+ const event = ctx?.callbackQuery ? "button" : ctx?.inlineQuery ? "inline_query" : inferEventFromMessage(ctx?.message);
195
+ const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;
196
+ const userId = ctx?.from?.id;
197
+ const isStart = typeof ctx?.message?.text === "string" && ctx.message.text.startsWith("/start");
198
+ if (chatId && userId) {
199
+ await reportEvent({ chatId, userId, event, isStart });
200
+ }
201
+ } catch {
202
+ }
203
+ if (next) {
204
+ await next();
205
+ }
206
+ };
207
+ }
208
+ var adstelo = {
209
+ init,
210
+ reportEvent,
211
+ validateInitCredentials,
212
+ telegraf: adsteloTelegrafMiddleware,
213
+ grammy: adsteloGrammyMiddleware
214
+ };
215
+ var _internal = {
216
+ buildHeaders,
217
+ allowEvent,
218
+ inferEventFromMessage
219
+ };
220
+ // Annotate the CommonJS export names for ESM import in node:
221
+ 0 && (module.exports = {
222
+ _internal,
223
+ adstelo,
224
+ init,
225
+ reportEvent,
226
+ validateInitCredentials
227
+ });
228
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nexport type InitOptions = {\n botSecret: string;\n apiKey: string;\n cooldownSeconds?: number;\n baseUrl?: string;\n};\n\nexport type ReportEventInput = {\n chatId: number | string;\n userId: number | string;\n event: string;\n isStart?: boolean;\n};\n\ntype Config = {\n apiKey: string | null;\n botSecret: string | null;\n endpoint: string;\n validateEndpoint: string;\n cooldownSeconds: number;\n};\n\nconst DEFAULT_BASE_URL = \"https://sdk.adstelo.com\";\n\nconst config: Config = {\n apiKey: null,\n botSecret: null,\n endpoint: `${DEFAULT_BASE_URL}/event`,\n validateEndpoint: `${DEFAULT_BASE_URL}/event/validate`,\n cooldownSeconds: 2\n};\n\nlet initialized = false;\nlet validationPromise: Promise<void> | null = null;\nconst cooldownMap = new Map<string, number>();\n\nfunction buildHeaders(payloadBytes: string) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"ngrok-skip-browser-warning\": \"true\"\n };\n\n if (config.apiKey) {\n headers[\"X-Api-Key\"] = config.apiKey;\n const signature = crypto\n .createHmac(\"sha256\", config.apiKey)\n .update(payloadBytes)\n .digest(\"hex\");\n headers[\"X-Signature\"] = signature;\n }\n\n return headers;\n}\n\nfunction nowSeconds() {\n return Math.floor(Date.now() / 1000);\n}\n\nfunction cooldownKey(userId: string | number, event: string) {\n return `${userId}:${event}`;\n}\n\nfunction allowEvent(userId: string | number, event: string) {\n const key = cooldownKey(userId, event);\n const current = nowSeconds();\n const last = cooldownMap.get(key) ?? 0;\n if (current - last < config.cooldownSeconds) {\n return false;\n }\n cooldownMap.set(key, current);\n return true;\n}\n\nexport function init(options: InitOptions) {\n if (!options || !options.botSecret || !options.apiKey) {\n throw new Error(\"botSecret and apiKey are required\");\n }\n\n config.botSecret = options.botSecret;\n config.apiKey = options.apiKey;\n config.cooldownSeconds = options.cooldownSeconds ?? 2;\n\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n config.endpoint = `${baseUrl.replace(/\\/$/, \"\")}/event`;\n config.validateEndpoint = `${baseUrl.replace(/\\/$/, \"\")}/event/validate`;\n initialized = true;\n}\n\nfunction ensureInit(options?: InitOptions) {\n if (initialized) return;\n if (!options?.botSecret || !options?.apiKey) {\n throw new Error(\"Missing botSecret or apiKey. Pass them to adstelo.grammy/adstelo.telegraf or call init().\");\n }\n init(options);\n if (!validationPromise) {\n validationPromise = validateInitCredentials()\n .then(({ ok, detail }) => {\n if (!ok) {\n console.error(\"[adstelo] init validation failed:\", detail);\n process.exit(1);\n }\n console.log(\"[adstelo] init validation ok\");\n })\n .catch((err) => {\n console.error(\"[adstelo] init validation failed:\", err?.message || err);\n process.exit(1);\n });\n }\n}\n\nexport async function validateInitCredentials() {\n if (!config.botSecret) {\n return { ok: false, detail: \"Missing botSecret\" };\n }\n if (!config.apiKey) {\n return { ok: false, detail: \"Missing apiKey\" };\n }\n\n const payload = { secret: config.botSecret };\n const payloadBytes = JSON.stringify(payload);\n const res = await fetch(config.validateEndpoint, {\n method: \"POST\",\n headers: buildHeaders(payloadBytes),\n body: payloadBytes\n });\n\n if (res.ok) {\n return { ok: true, detail: \"ok\" };\n }\n\n let detail = `HTTP ${res.status}`;\n try {\n const data = await res.json();\n if (data && typeof data.detail === \"string\") {\n detail = data.detail;\n }\n } catch {\n // ignore\n }\n return { ok: false, detail };\n}\n\nexport async function reportEvent(input: ReportEventInput) {\n if (!config.botSecret || !config.apiKey) {\n throw new Error(\"SDK not initialized. Call init() first.\");\n }\n if (!input?.userId || !input?.event) {\n return { ok: false, detail: \"Missing userId or event\" };\n }\n\n if (!allowEvent(input.userId, input.event)) {\n return { ok: true, detail: \"cooldown\" };\n }\n\n const payload = {\n chat_id: input.chatId,\n user_id: input.userId,\n event: input.event,\n ts: Date.now() / 1000,\n is_start: Boolean(input.isStart),\n secret: config.botSecret\n };\n\n const payloadBytes = JSON.stringify(payload);\n const res = await fetch(config.endpoint, {\n method: \"POST\",\n headers: buildHeaders(payloadBytes),\n body: payloadBytes\n });\n\n return { ok: res.ok, status: res.status };\n}\n\nfunction inferEventFromMessage(message: any) {\n if (!message) return \"message\";\n if (message.photo?.length) return \"photo\";\n if (message.video) return \"video\";\n if (message.sticker) return \"sticker\";\n if (message.animation) return \"media\";\n return \"message\";\n}\n\nfunction adsteloTelegrafMiddleware(options?: InitOptions) {\n ensureInit(options);\n return async (ctx: any, next: () => Promise<void>) => {\n try {\n const event = ctx?.callbackQuery\n ? \"button\"\n : ctx?.inlineQuery\n ? \"inline_query\"\n : inferEventFromMessage(ctx?.message);\n const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;\n const userId = ctx?.from?.id;\n const isStart = typeof ctx?.message?.text === \"string\" && ctx.message.text.startsWith(\"/start\");\n\n if (chatId && userId) {\n await reportEvent({ chatId, userId, event, isStart });\n }\n } catch {\n // swallow\n }\n\n if (next) {\n await next();\n }\n };\n}\n\nfunction adsteloGrammyMiddleware(options?: InitOptions) {\n ensureInit(options);\n return async (ctx: any, next: () => Promise<void>) => {\n try {\n const event = ctx?.callbackQuery\n ? \"button\"\n : ctx?.inlineQuery\n ? \"inline_query\"\n : inferEventFromMessage(ctx?.message);\n const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;\n const userId = ctx?.from?.id;\n const isStart = typeof ctx?.message?.text === \"string\" && ctx.message.text.startsWith(\"/start\");\n\n if (chatId && userId) {\n await reportEvent({ chatId, userId, event, isStart });\n }\n } catch {\n // swallow\n }\n\n if (next) {\n await next();\n }\n };\n}\n\nexport const adstelo = {\n init,\n reportEvent,\n validateInitCredentials,\n telegraf: adsteloTelegrafMiddleware,\n grammy: adsteloGrammyMiddleware\n};\n\nexport const _internal = {\n buildHeaders,\n allowEvent,\n inferEventFromMessage\n};\n"],"mappings":"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","names":["crypto"]}
@@ -0,0 +1,45 @@
1
+ type InitOptions = {
2
+ botSecret: string;
3
+ apiKey: string;
4
+ cooldownSeconds?: number;
5
+ baseUrl?: string;
6
+ };
7
+ type ReportEventInput = {
8
+ chatId: number | string;
9
+ userId: number | string;
10
+ event: string;
11
+ isStart?: boolean;
12
+ };
13
+ declare function buildHeaders(payloadBytes: string): Record<string, string>;
14
+ declare function allowEvent(userId: string | number, event: string): boolean;
15
+ declare function init(options: InitOptions): void;
16
+ declare function validateInitCredentials(): Promise<{
17
+ ok: boolean;
18
+ detail: string;
19
+ }>;
20
+ declare function reportEvent(input: ReportEventInput): Promise<{
21
+ ok: boolean;
22
+ detail: string;
23
+ status?: undefined;
24
+ } | {
25
+ ok: boolean;
26
+ status: number;
27
+ detail?: undefined;
28
+ }>;
29
+ declare function inferEventFromMessage(message: any): "message" | "photo" | "video" | "sticker" | "media";
30
+ declare function adsteloTelegrafMiddleware(options?: InitOptions): (ctx: any, next: () => Promise<void>) => Promise<void>;
31
+ declare function adsteloGrammyMiddleware(options?: InitOptions): (ctx: any, next: () => Promise<void>) => Promise<void>;
32
+ declare const adstelo: {
33
+ init: typeof init;
34
+ reportEvent: typeof reportEvent;
35
+ validateInitCredentials: typeof validateInitCredentials;
36
+ telegraf: typeof adsteloTelegrafMiddleware;
37
+ grammy: typeof adsteloGrammyMiddleware;
38
+ };
39
+ declare const _internal: {
40
+ buildHeaders: typeof buildHeaders;
41
+ allowEvent: typeof allowEvent;
42
+ inferEventFromMessage: typeof inferEventFromMessage;
43
+ };
44
+
45
+ export { type InitOptions, type ReportEventInput, _internal, adstelo, init, reportEvent, validateInitCredentials };
@@ -0,0 +1,45 @@
1
+ type InitOptions = {
2
+ botSecret: string;
3
+ apiKey: string;
4
+ cooldownSeconds?: number;
5
+ baseUrl?: string;
6
+ };
7
+ type ReportEventInput = {
8
+ chatId: number | string;
9
+ userId: number | string;
10
+ event: string;
11
+ isStart?: boolean;
12
+ };
13
+ declare function buildHeaders(payloadBytes: string): Record<string, string>;
14
+ declare function allowEvent(userId: string | number, event: string): boolean;
15
+ declare function init(options: InitOptions): void;
16
+ declare function validateInitCredentials(): Promise<{
17
+ ok: boolean;
18
+ detail: string;
19
+ }>;
20
+ declare function reportEvent(input: ReportEventInput): Promise<{
21
+ ok: boolean;
22
+ detail: string;
23
+ status?: undefined;
24
+ } | {
25
+ ok: boolean;
26
+ status: number;
27
+ detail?: undefined;
28
+ }>;
29
+ declare function inferEventFromMessage(message: any): "message" | "photo" | "video" | "sticker" | "media";
30
+ declare function adsteloTelegrafMiddleware(options?: InitOptions): (ctx: any, next: () => Promise<void>) => Promise<void>;
31
+ declare function adsteloGrammyMiddleware(options?: InitOptions): (ctx: any, next: () => Promise<void>) => Promise<void>;
32
+ declare const adstelo: {
33
+ init: typeof init;
34
+ reportEvent: typeof reportEvent;
35
+ validateInitCredentials: typeof validateInitCredentials;
36
+ telegraf: typeof adsteloTelegrafMiddleware;
37
+ grammy: typeof adsteloGrammyMiddleware;
38
+ };
39
+ declare const _internal: {
40
+ buildHeaders: typeof buildHeaders;
41
+ allowEvent: typeof allowEvent;
42
+ inferEventFromMessage: typeof inferEventFromMessage;
43
+ };
44
+
45
+ export { type InitOptions, type ReportEventInput, _internal, adstelo, init, reportEvent, validateInitCredentials };
package/dist/index.js ADDED
@@ -0,0 +1,189 @@
1
+ // src/index.ts
2
+ import crypto from "crypto";
3
+ var DEFAULT_BASE_URL = "https://sdk.adstelo.com";
4
+ var config = {
5
+ apiKey: null,
6
+ botSecret: null,
7
+ endpoint: `${DEFAULT_BASE_URL}/event`,
8
+ validateEndpoint: `${DEFAULT_BASE_URL}/event/validate`,
9
+ cooldownSeconds: 2
10
+ };
11
+ var initialized = false;
12
+ var validationPromise = null;
13
+ var cooldownMap = /* @__PURE__ */ new Map();
14
+ function buildHeaders(payloadBytes) {
15
+ const headers = {
16
+ "Content-Type": "application/json",
17
+ "ngrok-skip-browser-warning": "true"
18
+ };
19
+ if (config.apiKey) {
20
+ headers["X-Api-Key"] = config.apiKey;
21
+ const signature = crypto.createHmac("sha256", config.apiKey).update(payloadBytes).digest("hex");
22
+ headers["X-Signature"] = signature;
23
+ }
24
+ return headers;
25
+ }
26
+ function nowSeconds() {
27
+ return Math.floor(Date.now() / 1e3);
28
+ }
29
+ function cooldownKey(userId, event) {
30
+ return `${userId}:${event}`;
31
+ }
32
+ function allowEvent(userId, event) {
33
+ const key = cooldownKey(userId, event);
34
+ const current = nowSeconds();
35
+ const last = cooldownMap.get(key) ?? 0;
36
+ if (current - last < config.cooldownSeconds) {
37
+ return false;
38
+ }
39
+ cooldownMap.set(key, current);
40
+ return true;
41
+ }
42
+ function init(options) {
43
+ if (!options || !options.botSecret || !options.apiKey) {
44
+ throw new Error("botSecret and apiKey are required");
45
+ }
46
+ config.botSecret = options.botSecret;
47
+ config.apiKey = options.apiKey;
48
+ config.cooldownSeconds = options.cooldownSeconds ?? 2;
49
+ const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;
50
+ config.endpoint = `${baseUrl.replace(/\/$/, "")}/event`;
51
+ config.validateEndpoint = `${baseUrl.replace(/\/$/, "")}/event/validate`;
52
+ initialized = true;
53
+ }
54
+ function ensureInit(options) {
55
+ if (initialized) return;
56
+ if (!options?.botSecret || !options?.apiKey) {
57
+ throw new Error("Missing botSecret or apiKey. Pass them to adstelo.grammy/adstelo.telegraf or call init().");
58
+ }
59
+ init(options);
60
+ if (!validationPromise) {
61
+ validationPromise = validateInitCredentials().then(({ ok, detail }) => {
62
+ if (!ok) {
63
+ console.error("[adstelo] init validation failed:", detail);
64
+ process.exit(1);
65
+ }
66
+ console.log("[adstelo] init validation ok");
67
+ }).catch((err) => {
68
+ console.error("[adstelo] init validation failed:", err?.message || err);
69
+ process.exit(1);
70
+ });
71
+ }
72
+ }
73
+ async function validateInitCredentials() {
74
+ if (!config.botSecret) {
75
+ return { ok: false, detail: "Missing botSecret" };
76
+ }
77
+ if (!config.apiKey) {
78
+ return { ok: false, detail: "Missing apiKey" };
79
+ }
80
+ const payload = { secret: config.botSecret };
81
+ const payloadBytes = JSON.stringify(payload);
82
+ const res = await fetch(config.validateEndpoint, {
83
+ method: "POST",
84
+ headers: buildHeaders(payloadBytes),
85
+ body: payloadBytes
86
+ });
87
+ if (res.ok) {
88
+ return { ok: true, detail: "ok" };
89
+ }
90
+ let detail = `HTTP ${res.status}`;
91
+ try {
92
+ const data = await res.json();
93
+ if (data && typeof data.detail === "string") {
94
+ detail = data.detail;
95
+ }
96
+ } catch {
97
+ }
98
+ return { ok: false, detail };
99
+ }
100
+ async function reportEvent(input) {
101
+ if (!config.botSecret || !config.apiKey) {
102
+ throw new Error("SDK not initialized. Call init() first.");
103
+ }
104
+ if (!input?.userId || !input?.event) {
105
+ return { ok: false, detail: "Missing userId or event" };
106
+ }
107
+ if (!allowEvent(input.userId, input.event)) {
108
+ return { ok: true, detail: "cooldown" };
109
+ }
110
+ const payload = {
111
+ chat_id: input.chatId,
112
+ user_id: input.userId,
113
+ event: input.event,
114
+ ts: Date.now() / 1e3,
115
+ is_start: Boolean(input.isStart),
116
+ secret: config.botSecret
117
+ };
118
+ const payloadBytes = JSON.stringify(payload);
119
+ const res = await fetch(config.endpoint, {
120
+ method: "POST",
121
+ headers: buildHeaders(payloadBytes),
122
+ body: payloadBytes
123
+ });
124
+ return { ok: res.ok, status: res.status };
125
+ }
126
+ function inferEventFromMessage(message) {
127
+ if (!message) return "message";
128
+ if (message.photo?.length) return "photo";
129
+ if (message.video) return "video";
130
+ if (message.sticker) return "sticker";
131
+ if (message.animation) return "media";
132
+ return "message";
133
+ }
134
+ function adsteloTelegrafMiddleware(options) {
135
+ ensureInit(options);
136
+ return async (ctx, next) => {
137
+ try {
138
+ const event = ctx?.callbackQuery ? "button" : ctx?.inlineQuery ? "inline_query" : inferEventFromMessage(ctx?.message);
139
+ const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;
140
+ const userId = ctx?.from?.id;
141
+ const isStart = typeof ctx?.message?.text === "string" && ctx.message.text.startsWith("/start");
142
+ if (chatId && userId) {
143
+ await reportEvent({ chatId, userId, event, isStart });
144
+ }
145
+ } catch {
146
+ }
147
+ if (next) {
148
+ await next();
149
+ }
150
+ };
151
+ }
152
+ function adsteloGrammyMiddleware(options) {
153
+ ensureInit(options);
154
+ return async (ctx, next) => {
155
+ try {
156
+ const event = ctx?.callbackQuery ? "button" : ctx?.inlineQuery ? "inline_query" : inferEventFromMessage(ctx?.message);
157
+ const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;
158
+ const userId = ctx?.from?.id;
159
+ const isStart = typeof ctx?.message?.text === "string" && ctx.message.text.startsWith("/start");
160
+ if (chatId && userId) {
161
+ await reportEvent({ chatId, userId, event, isStart });
162
+ }
163
+ } catch {
164
+ }
165
+ if (next) {
166
+ await next();
167
+ }
168
+ };
169
+ }
170
+ var adstelo = {
171
+ init,
172
+ reportEvent,
173
+ validateInitCredentials,
174
+ telegraf: adsteloTelegrafMiddleware,
175
+ grammy: adsteloGrammyMiddleware
176
+ };
177
+ var _internal = {
178
+ buildHeaders,
179
+ allowEvent,
180
+ inferEventFromMessage
181
+ };
182
+ export {
183
+ _internal,
184
+ adstelo,
185
+ init,
186
+ reportEvent,
187
+ validateInitCredentials
188
+ };
189
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["import crypto from \"node:crypto\";\n\nexport type InitOptions = {\n botSecret: string;\n apiKey: string;\n cooldownSeconds?: number;\n baseUrl?: string;\n};\n\nexport type ReportEventInput = {\n chatId: number | string;\n userId: number | string;\n event: string;\n isStart?: boolean;\n};\n\ntype Config = {\n apiKey: string | null;\n botSecret: string | null;\n endpoint: string;\n validateEndpoint: string;\n cooldownSeconds: number;\n};\n\nconst DEFAULT_BASE_URL = \"https://sdk.adstelo.com\";\n\nconst config: Config = {\n apiKey: null,\n botSecret: null,\n endpoint: `${DEFAULT_BASE_URL}/event`,\n validateEndpoint: `${DEFAULT_BASE_URL}/event/validate`,\n cooldownSeconds: 2\n};\n\nlet initialized = false;\nlet validationPromise: Promise<void> | null = null;\nconst cooldownMap = new Map<string, number>();\n\nfunction buildHeaders(payloadBytes: string) {\n const headers: Record<string, string> = {\n \"Content-Type\": \"application/json\",\n \"ngrok-skip-browser-warning\": \"true\"\n };\n\n if (config.apiKey) {\n headers[\"X-Api-Key\"] = config.apiKey;\n const signature = crypto\n .createHmac(\"sha256\", config.apiKey)\n .update(payloadBytes)\n .digest(\"hex\");\n headers[\"X-Signature\"] = signature;\n }\n\n return headers;\n}\n\nfunction nowSeconds() {\n return Math.floor(Date.now() / 1000);\n}\n\nfunction cooldownKey(userId: string | number, event: string) {\n return `${userId}:${event}`;\n}\n\nfunction allowEvent(userId: string | number, event: string) {\n const key = cooldownKey(userId, event);\n const current = nowSeconds();\n const last = cooldownMap.get(key) ?? 0;\n if (current - last < config.cooldownSeconds) {\n return false;\n }\n cooldownMap.set(key, current);\n return true;\n}\n\nexport function init(options: InitOptions) {\n if (!options || !options.botSecret || !options.apiKey) {\n throw new Error(\"botSecret and apiKey are required\");\n }\n\n config.botSecret = options.botSecret;\n config.apiKey = options.apiKey;\n config.cooldownSeconds = options.cooldownSeconds ?? 2;\n\n const baseUrl = options.baseUrl ?? DEFAULT_BASE_URL;\n config.endpoint = `${baseUrl.replace(/\\/$/, \"\")}/event`;\n config.validateEndpoint = `${baseUrl.replace(/\\/$/, \"\")}/event/validate`;\n initialized = true;\n}\n\nfunction ensureInit(options?: InitOptions) {\n if (initialized) return;\n if (!options?.botSecret || !options?.apiKey) {\n throw new Error(\"Missing botSecret or apiKey. Pass them to adstelo.grammy/adstelo.telegraf or call init().\");\n }\n init(options);\n if (!validationPromise) {\n validationPromise = validateInitCredentials()\n .then(({ ok, detail }) => {\n if (!ok) {\n console.error(\"[adstelo] init validation failed:\", detail);\n process.exit(1);\n }\n console.log(\"[adstelo] init validation ok\");\n })\n .catch((err) => {\n console.error(\"[adstelo] init validation failed:\", err?.message || err);\n process.exit(1);\n });\n }\n}\n\nexport async function validateInitCredentials() {\n if (!config.botSecret) {\n return { ok: false, detail: \"Missing botSecret\" };\n }\n if (!config.apiKey) {\n return { ok: false, detail: \"Missing apiKey\" };\n }\n\n const payload = { secret: config.botSecret };\n const payloadBytes = JSON.stringify(payload);\n const res = await fetch(config.validateEndpoint, {\n method: \"POST\",\n headers: buildHeaders(payloadBytes),\n body: payloadBytes\n });\n\n if (res.ok) {\n return { ok: true, detail: \"ok\" };\n }\n\n let detail = `HTTP ${res.status}`;\n try {\n const data = await res.json();\n if (data && typeof data.detail === \"string\") {\n detail = data.detail;\n }\n } catch {\n // ignore\n }\n return { ok: false, detail };\n}\n\nexport async function reportEvent(input: ReportEventInput) {\n if (!config.botSecret || !config.apiKey) {\n throw new Error(\"SDK not initialized. Call init() first.\");\n }\n if (!input?.userId || !input?.event) {\n return { ok: false, detail: \"Missing userId or event\" };\n }\n\n if (!allowEvent(input.userId, input.event)) {\n return { ok: true, detail: \"cooldown\" };\n }\n\n const payload = {\n chat_id: input.chatId,\n user_id: input.userId,\n event: input.event,\n ts: Date.now() / 1000,\n is_start: Boolean(input.isStart),\n secret: config.botSecret\n };\n\n const payloadBytes = JSON.stringify(payload);\n const res = await fetch(config.endpoint, {\n method: \"POST\",\n headers: buildHeaders(payloadBytes),\n body: payloadBytes\n });\n\n return { ok: res.ok, status: res.status };\n}\n\nfunction inferEventFromMessage(message: any) {\n if (!message) return \"message\";\n if (message.photo?.length) return \"photo\";\n if (message.video) return \"video\";\n if (message.sticker) return \"sticker\";\n if (message.animation) return \"media\";\n return \"message\";\n}\n\nfunction adsteloTelegrafMiddleware(options?: InitOptions) {\n ensureInit(options);\n return async (ctx: any, next: () => Promise<void>) => {\n try {\n const event = ctx?.callbackQuery\n ? \"button\"\n : ctx?.inlineQuery\n ? \"inline_query\"\n : inferEventFromMessage(ctx?.message);\n const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;\n const userId = ctx?.from?.id;\n const isStart = typeof ctx?.message?.text === \"string\" && ctx.message.text.startsWith(\"/start\");\n\n if (chatId && userId) {\n await reportEvent({ chatId, userId, event, isStart });\n }\n } catch {\n // swallow\n }\n\n if (next) {\n await next();\n }\n };\n}\n\nfunction adsteloGrammyMiddleware(options?: InitOptions) {\n ensureInit(options);\n return async (ctx: any, next: () => Promise<void>) => {\n try {\n const event = ctx?.callbackQuery\n ? \"button\"\n : ctx?.inlineQuery\n ? \"inline_query\"\n : inferEventFromMessage(ctx?.message);\n const chatId = ctx?.chat?.id ?? ctx?.message?.chat?.id;\n const userId = ctx?.from?.id;\n const isStart = typeof ctx?.message?.text === \"string\" && ctx.message.text.startsWith(\"/start\");\n\n if (chatId && userId) {\n await reportEvent({ chatId, userId, event, isStart });\n }\n } catch {\n // swallow\n }\n\n if (next) {\n await next();\n }\n };\n}\n\nexport const adstelo = {\n init,\n reportEvent,\n validateInitCredentials,\n telegraf: adsteloTelegrafMiddleware,\n grammy: adsteloGrammyMiddleware\n};\n\nexport const _internal = {\n buildHeaders,\n allowEvent,\n inferEventFromMessage\n};\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,36 @@
1
+ {
2
+ "name": "@adstelo/sdk",
3
+ "version": "0.1.0",
4
+ "description": "Adstelo Telegram ads SDK for bots",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "main": "./dist/index.cjs",
8
+ "module": "./dist/index.js",
9
+ "types": "./dist/index.d.ts",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.js",
14
+ "require": "./dist/index.cjs"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "README.md"
20
+ ],
21
+ "scripts": {
22
+ "build": "tsup",
23
+ "dev": "tsup --watch",
24
+ "test": "vitest run"
25
+ },
26
+ "devDependencies": {
27
+ "@types/node": "^22.10.0",
28
+ "tsup": "^8.3.5",
29
+ "typescript": "^5.6.3",
30
+ "vitest": "^2.1.5"
31
+ },
32
+ "dependencies": {
33
+ "grammy": "^1.41.1",
34
+ "telegraf": "^4.16.3"
35
+ }
36
+ }