@brozarti/spincome 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/dist/ad.js ADDED
@@ -0,0 +1,43 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.fetchAd = fetchAd;
4
+ exports.recordImpression = recordImpression;
5
+ const config_js_1 = require("./config.js");
6
+ async function fetchAd(context) {
7
+ const config = (0, config_js_1.readConfig)();
8
+ if (!config?.enabled || !config?.developerKey)
9
+ return null;
10
+ try {
11
+ const res = await fetch(`${config_js_1.API_BASE}/ads/serve`, {
12
+ method: "POST",
13
+ headers: {
14
+ "Content-Type": "application/json",
15
+ "X-Developer-Key": config.developerKey,
16
+ },
17
+ body: JSON.stringify(context),
18
+ signal: AbortSignal.timeout(3000),
19
+ });
20
+ if (!res.ok)
21
+ return null;
22
+ return (await res.json());
23
+ }
24
+ catch {
25
+ return null;
26
+ }
27
+ }
28
+ async function recordImpression(adId, developerKey, actualCpmCents, context) {
29
+ try {
30
+ await fetch(`${config_js_1.API_BASE}/ads/impression`, {
31
+ method: "POST",
32
+ headers: {
33
+ "Content-Type": "application/json",
34
+ "X-Developer-Key": developerKey,
35
+ },
36
+ body: JSON.stringify({ adId, actualCpmCents, ...context }),
37
+ signal: AbortSignal.timeout(3000),
38
+ });
39
+ }
40
+ catch {
41
+ // fire-and-forget
42
+ }
43
+ }
package/dist/cli.js ADDED
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // `npx spincome` - interactive setup CLI
4
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
5
+ if (k2 === undefined) k2 = k;
6
+ var desc = Object.getOwnPropertyDescriptor(m, k);
7
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
8
+ desc = { enumerable: true, get: function() { return m[k]; } };
9
+ }
10
+ Object.defineProperty(o, k2, desc);
11
+ }) : (function(o, m, k, k2) {
12
+ if (k2 === undefined) k2 = k;
13
+ o[k2] = m[k];
14
+ }));
15
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
16
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
17
+ }) : function(o, v) {
18
+ o["default"] = v;
19
+ });
20
+ var __importStar = (this && this.__importStar) || (function () {
21
+ var ownKeys = function(o) {
22
+ ownKeys = Object.getOwnPropertyNames || function (o) {
23
+ var ar = [];
24
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
25
+ return ar;
26
+ };
27
+ return ownKeys(o);
28
+ };
29
+ return function (mod) {
30
+ if (mod && mod.__esModule) return mod;
31
+ var result = {};
32
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
33
+ __setModuleDefault(result, mod);
34
+ return result;
35
+ };
36
+ })();
37
+ var __importDefault = (this && this.__importDefault) || function (mod) {
38
+ return (mod && mod.__esModule) ? mod : { "default": mod };
39
+ };
40
+ Object.defineProperty(exports, "__esModule", { value: true });
41
+ const readline_1 = __importDefault(require("readline"));
42
+ const fs_1 = __importDefault(require("fs"));
43
+ const path_1 = __importDefault(require("path"));
44
+ const os_1 = __importDefault(require("os"));
45
+ const config_js_1 = require("./config.js");
46
+ const CLAUDE_SETTINGS_PATHS = [
47
+ path_1.default.join(os_1.default.homedir(), ".claude", "settings.json"),
48
+ path_1.default.join(process.cwd(), ".claude", "settings.json"),
49
+ ];
50
+ function prompt(rl, question) {
51
+ return new Promise((resolve) => rl.question(question, resolve));
52
+ }
53
+ async function registerDeveloper(email, referralCode) {
54
+ const res = await fetch(`${config_js_1.API_BASE}/developers/register`, {
55
+ method: "POST",
56
+ headers: { "Content-Type": "application/json" },
57
+ body: JSON.stringify({ email, referralCode }),
58
+ });
59
+ if (!res.ok) {
60
+ const err = await res.text();
61
+ throw new Error(`Registration failed: ${err}`);
62
+ }
63
+ return (await res.json());
64
+ }
65
+ function injectHook(settingsPath) {
66
+ let settings = {};
67
+ if (fs_1.default.existsSync(settingsPath)) {
68
+ try {
69
+ settings = JSON.parse(fs_1.default.readFileSync(settingsPath, "utf8"));
70
+ }
71
+ catch {
72
+ // If settings.json is malformed, start fresh rather than crashing.
73
+ }
74
+ }
75
+ const hookCmd = "npx @brozarti/spincome hook";
76
+ const hooks = settings.hooks ?? {};
77
+ const postToolUse = hooks.PostToolUse ?? [];
78
+ const alreadyInstalled = postToolUse.some((entry) => entry.hooks?.some((h) => h.command === hookCmd));
79
+ if (!alreadyInstalled) {
80
+ postToolUse.push({
81
+ matcher: "",
82
+ hooks: [{ type: "command", command: hookCmd }],
83
+ });
84
+ }
85
+ hooks.PostToolUse = postToolUse;
86
+ settings.hooks = hooks;
87
+ const dir = path_1.default.dirname(settingsPath);
88
+ if (!fs_1.default.existsSync(dir))
89
+ fs_1.default.mkdirSync(dir, { recursive: true });
90
+ fs_1.default.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
91
+ }
92
+ async function main() {
93
+ const arg = process.argv[2];
94
+ // Called by Claude Code hook -- delegate to hook entry
95
+ if (arg === "hook") {
96
+ await Promise.resolve().then(() => __importStar(require("./hook.js")));
97
+ return;
98
+ }
99
+ console.log("\n spincome.io -- earn from your Claude Code sessions\n");
100
+ const rl = readline_1.default.createInterface({ input: process.stdin, output: process.stdout });
101
+ const email = await prompt(rl, " Enter your email to register: ");
102
+ if (!email.includes("@")) {
103
+ console.error(" Invalid email.");
104
+ rl.close();
105
+ process.exit(1);
106
+ }
107
+ const referralCode = await prompt(rl, " Referral code (press Enter to skip): ");
108
+ console.log(" Registering...");
109
+ let developerKey;
110
+ let myReferralCode;
111
+ try {
112
+ const result = await registerDeveloper(email, referralCode.trim() || undefined);
113
+ developerKey = result.developerKey;
114
+ myReferralCode = result.referralCode;
115
+ }
116
+ catch (err) {
117
+ console.error(` ${err}`);
118
+ rl.close();
119
+ process.exit(1);
120
+ }
121
+ (0, config_js_1.writeConfig)({ developerKey, enabled: true });
122
+ // Inject into user-level Claude settings
123
+ const settingsPath = CLAUDE_SETTINGS_PATHS[0];
124
+ injectHook(settingsPath);
125
+ console.log("\n All set! Ads will appear after Claude Code tool calls.");
126
+ console.log(`\n Your referral link: https://spincome.io/r/${myReferralCode}`);
127
+ console.log(" Share it -- you earn 10% of every referred developer's earnings, forever.");
128
+ console.log("\n Dashboard: https://spincome.io/dev\n");
129
+ rl.close();
130
+ }
131
+ main().catch((err) => {
132
+ console.error(err);
133
+ process.exit(1);
134
+ });
package/dist/config.js ADDED
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.API_BASE = void 0;
7
+ exports.readConfig = readConfig;
8
+ exports.writeConfig = writeConfig;
9
+ const os_1 = __importDefault(require("os"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const fs_1 = __importDefault(require("fs"));
12
+ exports.API_BASE = process.env.SPINCOME_API_URL ?? "https://spincome.io/api";
13
+ const CONFIG_PATH = path_1.default.join(os_1.default.homedir(), ".spincome", "config.json");
14
+ function readConfig() {
15
+ try {
16
+ const raw = fs_1.default.readFileSync(CONFIG_PATH, "utf8");
17
+ return JSON.parse(raw);
18
+ }
19
+ catch {
20
+ return null;
21
+ }
22
+ }
23
+ function writeConfig(config) {
24
+ const dir = path_1.default.dirname(CONFIG_PATH);
25
+ if (!fs_1.default.existsSync(dir))
26
+ fs_1.default.mkdirSync(dir, { recursive: true });
27
+ fs_1.default.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
28
+ }
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderAd = renderAd;
4
+ const RESET = "\x1b[0m";
5
+ const BOLD = "\x1b[1m";
6
+ const DIM = "\x1b[2m";
7
+ const CYAN = "\x1b[36m";
8
+ const YELLOW = "\x1b[33m";
9
+ const BG_DARK = "\x1b[48;5;235m";
10
+ function line(content = "", width = 60) {
11
+ const padded = ` ${content}`.padEnd(width);
12
+ return `${BG_DARK}${padded}${RESET}`;
13
+ }
14
+ function renderAd(ad) {
15
+ const W = 60;
16
+ const divider = `${DIM}${"─".repeat(W)}${RESET}`;
17
+ return [
18
+ "",
19
+ divider,
20
+ line(`${DIM}Sponsored by ${ad.advertiser}${RESET}`, W),
21
+ line(`${BOLD}${CYAN}${ad.headline}${RESET}`, W),
22
+ line(`${ad.body}`, W),
23
+ line(`${YELLOW}${ad.cta} → ${ad.clickUrl}${RESET}`, W),
24
+ line(`${DIM}Earning with spincome.io | /disable to opt out${RESET}`, W),
25
+ divider,
26
+ "",
27
+ ].join("\n");
28
+ }
package/dist/hook.js ADDED
@@ -0,0 +1,43 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ // Entry point for the Claude Code PostToolUse hook.
4
+ // Claude Code pipes the hook payload as JSON on stdin.
5
+ var __importDefault = (this && this.__importDefault) || function (mod) {
6
+ return (mod && mod.__esModule) ? mod : { "default": mod };
7
+ };
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ const ad_js_1 = require("./ad.js");
10
+ const display_js_1 = require("./display.js");
11
+ const config_js_1 = require("./config.js");
12
+ const path_1 = __importDefault(require("path"));
13
+ function extractContext(payload) {
14
+ const toolName = payload.tool_name ?? undefined;
15
+ // Extract file extension from any path-like field in the tool input
16
+ const filePath = payload.tool_input?.file_path ??
17
+ payload.tool_input?.path ??
18
+ undefined;
19
+ const fileExt = filePath ? path_1.default.extname(filePath).replace(".", "").toLowerCase() || undefined : undefined;
20
+ return { toolName, fileExt };
21
+ }
22
+ async function main() {
23
+ const chunks = [];
24
+ for await (const chunk of process.stdin)
25
+ chunks.push(chunk);
26
+ const config = (0, config_js_1.readConfig)();
27
+ if (!config?.enabled || !config?.developerKey)
28
+ process.exit(0);
29
+ let payload = {};
30
+ try {
31
+ payload = JSON.parse(Buffer.concat(chunks).toString("utf8"));
32
+ }
33
+ catch {
34
+ // Malformed or empty stdin -- proceed with empty context
35
+ }
36
+ const context = extractContext(payload);
37
+ const ad = await (0, ad_js_1.fetchAd)(context);
38
+ if (!ad)
39
+ process.exit(0);
40
+ process.stdout.write((0, display_js_1.renderAd)(ad));
41
+ (0, ad_js_1.recordImpression)(ad.id, config.developerKey, ad.actualCpmCents, context);
42
+ }
43
+ main().catch(() => process.exit(0));
package/package.json ADDED
@@ -0,0 +1,23 @@
1
+ {
2
+ "name": "@brozarti/spincome",
3
+ "version": "0.1.0",
4
+ "description": "Earn passive income from your Claude Code sessions",
5
+ "bin": {
6
+ "spincome": "./dist/cli.js"
7
+ },
8
+ "main": "./dist/index.js",
9
+ "scripts": {
10
+ "build": "tsc",
11
+ "dev": "tsc --watch"
12
+ },
13
+ "dependencies": {
14
+ "node-fetch": "^3.3.2",
15
+ "open": "^10.1.0",
16
+ "chalk": "^5.3.0",
17
+ "ora": "^8.0.1"
18
+ },
19
+ "devDependencies": {
20
+ "typescript": "^5.4.0",
21
+ "@types/node": "^20.0.0"
22
+ }
23
+ }
package/src/ad.ts ADDED
@@ -0,0 +1,58 @@
1
+ import { API_BASE, readConfig } from "./config.js";
2
+
3
+ export interface AdContext {
4
+ toolName?: string;
5
+ fileExt?: string;
6
+ }
7
+
8
+ export interface Ad {
9
+ id: string;
10
+ headline: string;
11
+ body: string;
12
+ cta: string;
13
+ clickUrl: string;
14
+ advertiser: string;
15
+ actualCpmCents: number;
16
+ }
17
+
18
+ export async function fetchAd(context: AdContext): Promise<Ad | null> {
19
+ const config = readConfig();
20
+ if (!config?.enabled || !config?.developerKey) return null;
21
+
22
+ try {
23
+ const res = await fetch(`${API_BASE}/ads/serve`, {
24
+ method: "POST",
25
+ headers: {
26
+ "Content-Type": "application/json",
27
+ "X-Developer-Key": config.developerKey,
28
+ },
29
+ body: JSON.stringify(context),
30
+ signal: AbortSignal.timeout(3000),
31
+ });
32
+ if (!res.ok) return null;
33
+ return (await res.json()) as Ad;
34
+ } catch {
35
+ return null;
36
+ }
37
+ }
38
+
39
+ export async function recordImpression(
40
+ adId: string,
41
+ developerKey: string,
42
+ actualCpmCents: number,
43
+ context: AdContext
44
+ ): Promise<void> {
45
+ try {
46
+ await fetch(`${API_BASE}/ads/impression`, {
47
+ method: "POST",
48
+ headers: {
49
+ "Content-Type": "application/json",
50
+ "X-Developer-Key": developerKey,
51
+ },
52
+ body: JSON.stringify({ adId, actualCpmCents, ...context }),
53
+ signal: AbortSignal.timeout(3000),
54
+ });
55
+ } catch {
56
+ // fire-and-forget
57
+ }
58
+ }
package/src/cli.ts ADDED
@@ -0,0 +1,125 @@
1
+ #!/usr/bin/env node
2
+ // `npx spincome` - interactive setup CLI
3
+
4
+ import readline from "readline";
5
+ import fs from "fs";
6
+ import path from "path";
7
+ import os from "os";
8
+ import { writeConfig, API_BASE } from "./config.js";
9
+
10
+ const CLAUDE_SETTINGS_PATHS = [
11
+ path.join(os.homedir(), ".claude", "settings.json"),
12
+ path.join(process.cwd(), ".claude", "settings.json"),
13
+ ];
14
+
15
+ function prompt(rl: readline.Interface, question: string): Promise<string> {
16
+ return new Promise((resolve) => rl.question(question, resolve));
17
+ }
18
+
19
+ async function registerDeveloper(
20
+ email: string,
21
+ referralCode?: string
22
+ ): Promise<{ developerKey: string; referralCode: string }> {
23
+ const res = await fetch(`${API_BASE}/developers/register`, {
24
+ method: "POST",
25
+ headers: { "Content-Type": "application/json" },
26
+ body: JSON.stringify({ email, referralCode }),
27
+ });
28
+ if (!res.ok) {
29
+ const err = await res.text();
30
+ throw new Error(`Registration failed: ${err}`);
31
+ }
32
+ return (await res.json()) as { developerKey: string; referralCode: string };
33
+ }
34
+
35
+ interface HookEntry {
36
+ matcher: string;
37
+ hooks: { type: string; command: string }[];
38
+ }
39
+
40
+ function injectHook(settingsPath: string): void {
41
+ let settings: Record<string, unknown> = {};
42
+ if (fs.existsSync(settingsPath)) {
43
+ try {
44
+ settings = JSON.parse(fs.readFileSync(settingsPath, "utf8"));
45
+ } catch {
46
+ // If settings.json is malformed, start fresh rather than crashing.
47
+ }
48
+ }
49
+
50
+ const hookCmd = "npx @brozarti/spincome hook";
51
+ const hooks = (settings.hooks as Record<string, unknown> | undefined) ?? {};
52
+ const postToolUse = (hooks.PostToolUse as HookEntry[] | undefined) ?? [];
53
+
54
+ const alreadyInstalled = postToolUse.some((entry) =>
55
+ entry.hooks?.some((h) => h.command === hookCmd)
56
+ );
57
+
58
+ if (!alreadyInstalled) {
59
+ postToolUse.push({
60
+ matcher: "",
61
+ hooks: [{ type: "command", command: hookCmd }],
62
+ });
63
+ }
64
+
65
+ hooks.PostToolUse = postToolUse;
66
+ settings.hooks = hooks;
67
+
68
+ const dir = path.dirname(settingsPath);
69
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
70
+ fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
71
+ }
72
+
73
+ async function main() {
74
+ const arg = process.argv[2];
75
+
76
+ // Called by Claude Code hook -- delegate to hook entry
77
+ if (arg === "hook") {
78
+ await import("./hook.js");
79
+ return;
80
+ }
81
+
82
+ console.log("\n spincome.io -- earn from your Claude Code sessions\n");
83
+
84
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
85
+
86
+ const email = await prompt(rl, " Enter your email to register: ");
87
+ if (!email.includes("@")) {
88
+ console.error(" Invalid email.");
89
+ rl.close();
90
+ process.exit(1);
91
+ }
92
+
93
+ const referralCode = await prompt(rl, " Referral code (press Enter to skip): ");
94
+
95
+ console.log(" Registering...");
96
+ let developerKey: string;
97
+ let myReferralCode: string;
98
+ try {
99
+ const result = await registerDeveloper(email, referralCode.trim() || undefined);
100
+ developerKey = result.developerKey;
101
+ myReferralCode = result.referralCode;
102
+ } catch (err) {
103
+ console.error(` ${err}`);
104
+ rl.close();
105
+ process.exit(1);
106
+ }
107
+
108
+ writeConfig({ developerKey, enabled: true });
109
+
110
+ // Inject into user-level Claude settings
111
+ const settingsPath = CLAUDE_SETTINGS_PATHS[0];
112
+ injectHook(settingsPath);
113
+
114
+ console.log("\n All set! Ads will appear after Claude Code tool calls.");
115
+ console.log(`\n Your referral link: https://spincome.io/r/${myReferralCode}`);
116
+ console.log(" Share it -- you earn 10% of every referred developer's earnings, forever.");
117
+ console.log("\n Dashboard: https://spincome.io/dev\n");
118
+
119
+ rl.close();
120
+ }
121
+
122
+ main().catch((err) => {
123
+ console.error(err);
124
+ process.exit(1);
125
+ });
package/src/config.ts ADDED
@@ -0,0 +1,27 @@
1
+ import os from "os";
2
+ import path from "path";
3
+ import fs from "fs";
4
+
5
+ export const API_BASE = process.env.SPINCOME_API_URL ?? "https://spincome.io/api";
6
+
7
+ export interface Config {
8
+ developerKey: string;
9
+ enabled: boolean;
10
+ }
11
+
12
+ const CONFIG_PATH = path.join(os.homedir(), ".spincome", "config.json");
13
+
14
+ export function readConfig(): Config | null {
15
+ try {
16
+ const raw = fs.readFileSync(CONFIG_PATH, "utf8");
17
+ return JSON.parse(raw) as Config;
18
+ } catch {
19
+ return null;
20
+ }
21
+ }
22
+
23
+ export function writeConfig(config: Config): void {
24
+ const dir = path.dirname(CONFIG_PATH);
25
+ if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
26
+ fs.writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2));
27
+ }
package/src/display.ts ADDED
@@ -0,0 +1,30 @@
1
+ import type { Ad } from "./ad.js";
2
+
3
+ const RESET = "\x1b[0m";
4
+ const BOLD = "\x1b[1m";
5
+ const DIM = "\x1b[2m";
6
+ const CYAN = "\x1b[36m";
7
+ const YELLOW = "\x1b[33m";
8
+ const BG_DARK = "\x1b[48;5;235m";
9
+
10
+ function line(content = "", width = 60): string {
11
+ const padded = ` ${content}`.padEnd(width);
12
+ return `${BG_DARK}${padded}${RESET}`;
13
+ }
14
+
15
+ export function renderAd(ad: Ad): string {
16
+ const W = 60;
17
+ const divider = `${DIM}${"─".repeat(W)}${RESET}`;
18
+
19
+ return [
20
+ "",
21
+ divider,
22
+ line(`${DIM}Sponsored by ${ad.advertiser}${RESET}`, W),
23
+ line(`${BOLD}${CYAN}${ad.headline}${RESET}`, W),
24
+ line(`${ad.body}`, W),
25
+ line(`${YELLOW}${ad.cta} → ${ad.clickUrl}${RESET}`, W),
26
+ line(`${DIM}Earning with spincome.io | /disable to opt out${RESET}`, W),
27
+ divider,
28
+ "",
29
+ ].join("\n");
30
+ }
package/src/hook.ts ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+ // Entry point for the Claude Code PostToolUse hook.
3
+ // Claude Code pipes the hook payload as JSON on stdin.
4
+
5
+ import { fetchAd, recordImpression, type AdContext } from "./ad.js";
6
+ import { renderAd } from "./display.js";
7
+ import { readConfig } from "./config.js";
8
+ import path from "path";
9
+
10
+ interface HookPayload {
11
+ tool_name?: string;
12
+ tool_input?: {
13
+ file_path?: string;
14
+ command?: string;
15
+ path?: string;
16
+ };
17
+ }
18
+
19
+ function extractContext(payload: HookPayload): AdContext {
20
+ const toolName = payload.tool_name ?? undefined;
21
+
22
+ // Extract file extension from any path-like field in the tool input
23
+ const filePath =
24
+ payload.tool_input?.file_path ??
25
+ payload.tool_input?.path ??
26
+ undefined;
27
+
28
+ const fileExt = filePath ? path.extname(filePath).replace(".", "").toLowerCase() || undefined : undefined;
29
+
30
+ return { toolName, fileExt };
31
+ }
32
+
33
+ async function main() {
34
+ const chunks: Buffer[] = [];
35
+ for await (const chunk of process.stdin) chunks.push(chunk);
36
+
37
+ const config = readConfig();
38
+ if (!config?.enabled || !config?.developerKey) process.exit(0);
39
+
40
+ let payload: HookPayload = {};
41
+ try {
42
+ payload = JSON.parse(Buffer.concat(chunks).toString("utf8"));
43
+ } catch {
44
+ // Malformed or empty stdin -- proceed with empty context
45
+ }
46
+
47
+ const context = extractContext(payload);
48
+ const ad = await fetchAd(context);
49
+ if (!ad) process.exit(0);
50
+
51
+ process.stdout.write(renderAd(ad));
52
+ recordImpression(ad.id, config.developerKey, ad.actualCpmCents, context);
53
+ }
54
+
55
+ main().catch(() => process.exit(0));
package/tsconfig.json ADDED
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2020",
4
+ "module": "CommonJS",
5
+ "outDir": "./dist",
6
+ "rootDir": "./src",
7
+ "strict": true,
8
+ "esModuleInterop": true,
9
+ "skipLibCheck": true
10
+ },
11
+ "include": ["src"]
12
+ }