@linkforty/core 1.0.0 → 1.2.1

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.
Files changed (61) hide show
  1. package/dist/index.d.ts +4 -1
  2. package/dist/index.d.ts.map +1 -1
  3. package/dist/index.js +26 -43
  4. package/dist/index.js.map +1 -1
  5. package/dist/lib/database.d.ts.map +1 -1
  6. package/dist/lib/database.js +160 -12
  7. package/dist/lib/database.js.map +1 -1
  8. package/dist/lib/event-emitter.d.ts +46 -0
  9. package/dist/lib/event-emitter.d.ts.map +1 -0
  10. package/dist/lib/event-emitter.js +24 -0
  11. package/dist/lib/event-emitter.js.map +1 -0
  12. package/dist/lib/fingerprint.d.ts +64 -0
  13. package/dist/lib/fingerprint.d.ts.map +1 -0
  14. package/dist/lib/fingerprint.js +343 -0
  15. package/dist/lib/fingerprint.js.map +1 -0
  16. package/dist/lib/utils.d.ts +1 -0
  17. package/dist/lib/utils.d.ts.map +1 -1
  18. package/dist/lib/utils.js +12 -21
  19. package/dist/lib/utils.js.map +1 -1
  20. package/dist/lib/webhook.d.ts +18 -0
  21. package/dist/lib/webhook.d.ts.map +1 -0
  22. package/dist/lib/webhook.js +141 -0
  23. package/dist/lib/webhook.js.map +1 -0
  24. package/dist/routes/analytics.js +14 -17
  25. package/dist/routes/analytics.js.map +1 -1
  26. package/dist/routes/debug.d.ts +7 -0
  27. package/dist/routes/debug.d.ts.map +1 -0
  28. package/dist/routes/debug.js +318 -0
  29. package/dist/routes/debug.js.map +1 -0
  30. package/dist/routes/index.d.ts +5 -0
  31. package/dist/routes/index.d.ts.map +1 -1
  32. package/dist/routes/index.js +8 -9
  33. package/dist/routes/index.js.map +1 -1
  34. package/dist/routes/links.d.ts.map +1 -1
  35. package/dist/routes/links.js +53 -38
  36. package/dist/routes/links.js.map +1 -1
  37. package/dist/routes/preview.d.ts +3 -0
  38. package/dist/routes/preview.d.ts.map +1 -0
  39. package/dist/routes/preview.js +222 -0
  40. package/dist/routes/preview.js.map +1 -0
  41. package/dist/routes/qr.d.ts +6 -0
  42. package/dist/routes/qr.d.ts.map +1 -0
  43. package/dist/routes/qr.js +130 -0
  44. package/dist/routes/qr.js.map +1 -0
  45. package/dist/routes/redirect.d.ts.map +1 -1
  46. package/dist/routes/redirect.js +142 -22
  47. package/dist/routes/redirect.js.map +1 -1
  48. package/dist/routes/sdk.d.ts +7 -0
  49. package/dist/routes/sdk.d.ts.map +1 -0
  50. package/dist/routes/sdk.js +262 -0
  51. package/dist/routes/sdk.js.map +1 -0
  52. package/dist/routes/webhooks.d.ts +3 -0
  53. package/dist/routes/webhooks.d.ts.map +1 -0
  54. package/dist/routes/webhooks.js +176 -0
  55. package/dist/routes/webhooks.js.map +1 -0
  56. package/dist/scripts/migrate.js +2 -4
  57. package/dist/scripts/migrate.js.map +1 -1
  58. package/dist/types/index.d.ts +81 -0
  59. package/dist/types/index.d.ts.map +1 -1
  60. package/dist/types/index.js +1 -2
  61. package/package.json +11 -7
package/dist/index.d.ts CHANGED
@@ -13,6 +13,9 @@ export interface ServerOptions {
13
13
  export declare function createServer(options?: ServerOptions): Promise<FastifyInstance<import("http").Server<typeof import("http").IncomingMessage, typeof import("http").ServerResponse>, import("http").IncomingMessage, import("http").ServerResponse<import("http").IncomingMessage>, import("fastify").FastifyBaseLogger, import("fastify").FastifyTypeProviderDefault>>;
14
14
  export * from './lib/utils.js';
15
15
  export * from './lib/database.js';
16
+ export * from './lib/fingerprint.js';
17
+ export * from './lib/webhook.js';
18
+ export * from './lib/event-emitter.js';
16
19
  export * from './types/index.js';
17
- export { redirectRoutes, linkRoutes, analyticsRoutes } from './routes/index.js';
20
+ export { redirectRoutes, linkRoutes, analyticsRoutes, sdkRoutes, webhookRoutes, qrRoutes, previewRoutes, debugRoutes } from './routes/index.js';
18
21
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAAsB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAKxE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,kTA0B7D;AAGD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAgB,EAAE,eAAe,EAAE,MAAM,SAAS,CAAC;AAGnD,OAAO,EAAsB,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAOxE,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,KAAK,CAAC,EAAE;QACN,GAAG,EAAE,MAAM,CAAC;KACb,CAAC;IACF,IAAI,CAAC,EAAE;QACL,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC;KAC3B,CAAC;IACF,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,kTA4B7D;AAGD,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
package/dist/index.js CHANGED
@@ -1,59 +1,42 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
- for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
- };
16
- var __importDefault = (this && this.__importDefault) || function (mod) {
17
- return (mod && mod.__esModule) ? mod : { "default": mod };
18
- };
19
- Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.analyticsRoutes = exports.linkRoutes = exports.redirectRoutes = void 0;
21
- exports.createServer = createServer;
22
- const fastify_1 = __importDefault(require("fastify"));
23
- const cors_1 = __importDefault(require("@fastify/cors"));
24
- const redis_1 = __importDefault(require("@fastify/redis"));
25
- const database_js_1 = require("./lib/database.js");
26
- const redirect_js_1 = require("./routes/redirect.js");
27
- const links_js_1 = require("./routes/links.js");
28
- const analytics_js_1 = require("./routes/analytics.js");
29
- async function createServer(options = {}) {
30
- const fastify = (0, fastify_1.default)({
1
+ import Fastify from 'fastify';
2
+ import cors from '@fastify/cors';
3
+ import redis from '@fastify/redis';
4
+ import { initializeDatabase } from './lib/database.js';
5
+ import { redirectRoutes } from './routes/redirect.js';
6
+ import { linkRoutes } from './routes/links.js';
7
+ import { analyticsRoutes } from './routes/analytics.js';
8
+ import { sdkRoutes } from './routes/sdk.js';
9
+ import { webhookRoutes } from './routes/webhooks.js';
10
+ export async function createServer(options = {}) {
11
+ const fastify = Fastify({
31
12
  logger: options.logger !== undefined ? options.logger : true,
32
13
  });
33
14
  // CORS
34
- await fastify.register(cors_1.default, {
15
+ await fastify.register(cors, {
35
16
  origin: options.cors?.origin || '*',
36
17
  });
37
18
  // Redis (optional)
38
19
  if (options.redis?.url) {
39
- await fastify.register(redis_1.default, {
20
+ await fastify.register(redis, {
40
21
  url: options.redis.url,
41
22
  });
42
23
  }
43
24
  // Database
44
- await (0, database_js_1.initializeDatabase)(options.database);
25
+ await initializeDatabase(options.database);
45
26
  // Routes
46
- await fastify.register(redirect_js_1.redirectRoutes);
47
- await fastify.register(links_js_1.linkRoutes);
48
- await fastify.register(analytics_js_1.analyticsRoutes);
27
+ await fastify.register(redirectRoutes);
28
+ await fastify.register(linkRoutes);
29
+ await fastify.register(analyticsRoutes);
30
+ await fastify.register(sdkRoutes);
31
+ await fastify.register(webhookRoutes);
49
32
  return fastify;
50
33
  }
51
34
  // Re-export utilities and types
52
- __exportStar(require("./lib/utils.js"), exports);
53
- __exportStar(require("./lib/database.js"), exports);
54
- __exportStar(require("./types/index.js"), exports);
55
- var index_js_1 = require("./routes/index.js");
56
- Object.defineProperty(exports, "redirectRoutes", { enumerable: true, get: function () { return index_js_1.redirectRoutes; } });
57
- Object.defineProperty(exports, "linkRoutes", { enumerable: true, get: function () { return index_js_1.linkRoutes; } });
58
- Object.defineProperty(exports, "analyticsRoutes", { enumerable: true, get: function () { return index_js_1.analyticsRoutes; } });
35
+ export * from './lib/utils.js';
36
+ export * from './lib/database.js';
37
+ export * from './lib/fingerprint.js';
38
+ export * from './lib/webhook.js';
39
+ export * from './lib/event-emitter.js';
40
+ export * from './types/index.js';
41
+ export { redirectRoutes, linkRoutes, analyticsRoutes, sdkRoutes, webhookRoutes, qrRoutes, previewRoutes, debugRoutes } from './routes/index.js';
59
42
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;AAmBA,oCA0BC;AA7CD,sDAAmD;AACnD,yDAAiC;AACjC,2DAAmC;AACnC,mDAAwE;AACxE,sDAAsD;AACtD,gDAA+C;AAC/C,wDAAwD;AAajD,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,OAAO,GAAG,IAAA,iBAAO,EAAC;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KAC7D,CAAC,CAAC;IAEH,OAAO;IACP,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAI,EAAE;QAC3B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG;KACpC,CAAC,CAAC;IAEH,mBAAmB;IACnB,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAK,EAAE;YAC5B,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG;SACvB,CAAC,CAAC;IACL,CAAC;IAED,WAAW;IACX,MAAM,IAAA,gCAAkB,EAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,4BAAc,CAAC,CAAC;IACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,qBAAU,CAAC,CAAC;IACnC,MAAM,OAAO,CAAC,QAAQ,CAAC,8BAAe,CAAC,CAAC;IAExC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gCAAgC;AAChC,iDAA+B;AAC/B,oDAAkC;AAClC,mDAAiC;AACjC,8CAAgF;AAAvE,0GAAA,cAAc,OAAA;AAAE,sGAAA,UAAU,OAAA;AAAE,2GAAA,eAAe,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,OAA4B,MAAM,SAAS,CAAC;AACnD,OAAO,IAAI,MAAM,eAAe,CAAC;AACjC,OAAO,KAAK,MAAM,gBAAgB,CAAC;AACnC,OAAO,EAAE,kBAAkB,EAAmB,MAAM,mBAAmB,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,sBAAsB,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5C,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAarD,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,OAAO,GAAG,OAAO,CAAC;QACtB,MAAM,EAAE,OAAO,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI;KAC7D,CAAC,CAAC;IAEH,OAAO;IACP,MAAM,OAAO,CAAC,QAAQ,CAAC,IAAI,EAAE;QAC3B,MAAM,EAAE,OAAO,CAAC,IAAI,EAAE,MAAM,IAAI,GAAG;KACpC,CAAC,CAAC;IAEH,mBAAmB;IACnB,IAAI,OAAO,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;QACvB,MAAM,OAAO,CAAC,QAAQ,CAAC,KAAK,EAAE;YAC5B,GAAG,EAAE,OAAO,CAAC,KAAK,CAAC,GAAG;SACvB,CAAC,CAAC;IACL,CAAC;IAED,WAAW;IACX,MAAM,kBAAkB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAE3C,SAAS;IACT,MAAM,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAAC;IACvC,MAAM,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;IACnC,MAAM,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IACxC,MAAM,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAClC,MAAM,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;IAEtC,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,gCAAgC;AAChC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,mBAAmB,CAAC;AAClC,cAAc,sBAAsB,CAAC;AACrC,cAAc,kBAAkB,CAAC;AACjC,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC;AACjC,OAAO,EAAE,cAAc,EAAE,UAAU,EAAE,eAAe,EAAE,SAAS,EAAE,aAAa,EAAE,QAAQ,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,eAAO,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;AA6BvB,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,iBAoFrE"}
1
+ {"version":3,"file":"database.d.ts","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AAIpB,MAAM,WAAW,eAAe;IAC9B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE;QACL,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,GAAG,CAAC,EAAE,MAAM,CAAC;KACd,CAAC;CACH;AAED,eAAO,IAAI,EAAE,EAAE,EAAE,CAAC,IAAI,CAAC;AA6BvB,wBAAsB,kBAAkB,CAAC,OAAO,GAAE,eAAoB,iBA2PrE"}
@@ -1,12 +1,6 @@
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.db = void 0;
7
- exports.initializeDatabase = initializeDatabase;
8
- const pg_1 = __importDefault(require("pg"));
9
- const { Pool } = pg_1.default;
1
+ import pg from 'pg';
2
+ const { Pool } = pg;
3
+ export let db;
10
4
  // Helper function to wait for a specified time
11
5
  function sleep(ms) {
12
6
  return new Promise(resolve => setTimeout(resolve, ms));
@@ -15,7 +9,7 @@ function sleep(ms) {
15
9
  async function connectWithRetry(maxRetries = 10, baseDelay = 1000) {
16
10
  for (let attempt = 1; attempt <= maxRetries; attempt++) {
17
11
  try {
18
- const client = await exports.db.connect();
12
+ const client = await db.connect();
19
13
  console.log('Database connection established successfully');
20
14
  return client;
21
15
  }
@@ -34,9 +28,9 @@ async function connectWithRetry(maxRetries = 10, baseDelay = 1000) {
34
28
  throw new Error('Max retries exceeded');
35
29
  }
36
30
  // Initialize database schema
37
- async function initializeDatabase(options = {}) {
31
+ export async function initializeDatabase(options = {}) {
38
32
  // Initialize pool
39
- exports.db = new Pool({
33
+ db = new Pool({
40
34
  connectionString: options.url || process.env.DATABASE_URL || 'postgresql://postgres:password@localhost:5432/linkforty',
41
35
  ssl: process.env.NODE_ENV === 'production' ? { rejectUnauthorized: false } : false,
42
36
  min: options.pool?.min || 2,
@@ -63,6 +57,7 @@ async function initializeDatabase(options = {}) {
63
57
  short_code VARCHAR(20) UNIQUE NOT NULL,
64
58
  original_url TEXT NOT NULL,
65
59
  title VARCHAR(255),
60
+ description TEXT,
66
61
  ios_url TEXT,
67
62
  android_url TEXT,
68
63
  web_fallback_url TEXT,
@@ -96,6 +91,145 @@ async function initializeDatabase(options = {}) {
96
91
  utm_campaign VARCHAR(255),
97
92
  referrer TEXT
98
93
  )
94
+ `);
95
+ // Device fingerprints table - stores individual fingerprint components for probabilistic matching
96
+ await client.query(`
97
+ CREATE TABLE IF NOT EXISTS device_fingerprints (
98
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
99
+ click_id UUID NOT NULL REFERENCES click_events(id) ON DELETE CASCADE,
100
+ fingerprint_hash VARCHAR(64) NOT NULL,
101
+ ip_address INET,
102
+ user_agent TEXT,
103
+ timezone VARCHAR(100),
104
+ language VARCHAR(10),
105
+ screen_width INTEGER,
106
+ screen_height INTEGER,
107
+ platform VARCHAR(50),
108
+ platform_version VARCHAR(50),
109
+ created_at TIMESTAMP DEFAULT NOW()
110
+ )
111
+ `);
112
+ // Install events table - tracks app installations and matches to clicks via fingerprinting
113
+ await client.query(`
114
+ CREATE TABLE IF NOT EXISTS install_events (
115
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
116
+ link_id UUID REFERENCES links(id) ON DELETE SET NULL,
117
+ click_id UUID REFERENCES click_events(id) ON DELETE SET NULL,
118
+ fingerprint_hash VARCHAR(64) NOT NULL,
119
+ confidence_score DECIMAL(5, 2),
120
+ installed_at TIMESTAMP DEFAULT NOW(),
121
+ first_open_at TIMESTAMP,
122
+ deep_link_retrieved BOOLEAN DEFAULT false,
123
+ deep_link_data JSONB DEFAULT '{}',
124
+ attribution_window_hours INTEGER DEFAULT 168,
125
+ ip_address INET,
126
+ user_agent TEXT,
127
+ timezone VARCHAR(100),
128
+ language VARCHAR(10),
129
+ screen_width INTEGER,
130
+ screen_height INTEGER,
131
+ platform VARCHAR(50),
132
+ platform_version VARCHAR(50),
133
+ device_id VARCHAR(255),
134
+ created_at TIMESTAMP DEFAULT NOW()
135
+ )
136
+ `);
137
+ // In-app events table - tracks conversion events from mobile apps
138
+ await client.query(`
139
+ CREATE TABLE IF NOT EXISTS in_app_events (
140
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
141
+ install_id UUID NOT NULL REFERENCES install_events(id) ON DELETE CASCADE,
142
+ event_name VARCHAR(255) NOT NULL,
143
+ event_data JSONB DEFAULT '{}',
144
+ event_timestamp TIMESTAMP NOT NULL,
145
+ created_at TIMESTAMP DEFAULT NOW()
146
+ )
147
+ `);
148
+ // Webhooks table - stores webhook configurations for event postbacks
149
+ await client.query(`
150
+ CREATE TABLE IF NOT EXISTS webhooks (
151
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
152
+ user_id UUID NOT NULL REFERENCES users(id) ON DELETE CASCADE,
153
+ name VARCHAR(255) NOT NULL,
154
+ url TEXT NOT NULL,
155
+ secret VARCHAR(255) NOT NULL,
156
+ events TEXT[] NOT NULL DEFAULT '{}',
157
+ is_active BOOLEAN DEFAULT true,
158
+ retry_count INTEGER DEFAULT 3,
159
+ timeout_ms INTEGER DEFAULT 10000,
160
+ headers JSONB DEFAULT '{}',
161
+ created_at TIMESTAMP DEFAULT NOW(),
162
+ updated_at TIMESTAMP DEFAULT NOW()
163
+ )
164
+ `);
165
+ // Add description column to existing links table if it doesn't exist
166
+ await client.query(`
167
+ DO $$
168
+ BEGIN
169
+ IF NOT EXISTS (
170
+ SELECT 1 FROM information_schema.columns
171
+ WHERE table_name='links' AND column_name='description'
172
+ ) THEN
173
+ ALTER TABLE links ADD COLUMN description TEXT;
174
+ END IF;
175
+ END $$;
176
+ `);
177
+ // Add Open Graph (OG) tag columns for social media previews
178
+ await client.query(`
179
+ DO $$
180
+ BEGIN
181
+ IF NOT EXISTS (
182
+ SELECT 1 FROM information_schema.columns
183
+ WHERE table_name='links' AND column_name='og_title'
184
+ ) THEN
185
+ ALTER TABLE links ADD COLUMN og_title VARCHAR(255);
186
+ END IF;
187
+ END $$;
188
+ `);
189
+ await client.query(`
190
+ DO $$
191
+ BEGIN
192
+ IF NOT EXISTS (
193
+ SELECT 1 FROM information_schema.columns
194
+ WHERE table_name='links' AND column_name='og_description'
195
+ ) THEN
196
+ ALTER TABLE links ADD COLUMN og_description TEXT;
197
+ END IF;
198
+ END $$;
199
+ `);
200
+ await client.query(`
201
+ DO $$
202
+ BEGIN
203
+ IF NOT EXISTS (
204
+ SELECT 1 FROM information_schema.columns
205
+ WHERE table_name='links' AND column_name='og_image_url'
206
+ ) THEN
207
+ ALTER TABLE links ADD COLUMN og_image_url TEXT;
208
+ END IF;
209
+ END $$;
210
+ `);
211
+ await client.query(`
212
+ DO $$
213
+ BEGIN
214
+ IF NOT EXISTS (
215
+ SELECT 1 FROM information_schema.columns
216
+ WHERE table_name='links' AND column_name='og_type'
217
+ ) THEN
218
+ ALTER TABLE links ADD COLUMN og_type VARCHAR(50) DEFAULT 'website';
219
+ END IF;
220
+ END $$;
221
+ `);
222
+ // Add attribution window column for configurable install attribution windows
223
+ await client.query(`
224
+ DO $$
225
+ BEGIN
226
+ IF NOT EXISTS (
227
+ SELECT 1 FROM information_schema.columns
228
+ WHERE table_name='links' AND column_name='attribution_window_hours'
229
+ ) THEN
230
+ ALTER TABLE links ADD COLUMN attribution_window_hours INTEGER DEFAULT 168;
231
+ END IF;
232
+ END $$;
99
233
  `);
100
234
  // Create indexes for performance
101
235
  await client.query('CREATE UNIQUE INDEX IF NOT EXISTS idx_links_short_code ON links(short_code)');
@@ -105,6 +239,20 @@ async function initializeDatabase(options = {}) {
105
239
  await client.query('CREATE INDEX IF NOT EXISTS idx_clicks_timestamp ON click_events(clicked_at DESC)');
106
240
  await client.query('CREATE INDEX IF NOT EXISTS idx_clicks_link_date ON click_events(link_id, clicked_at DESC)');
107
241
  await client.query('CREATE INDEX IF NOT EXISTS idx_users_email ON users(email)');
242
+ // Indexes for deferred deep linking
243
+ await client.query('CREATE INDEX IF NOT EXISTS idx_fingerprints_hash ON device_fingerprints(fingerprint_hash)');
244
+ await client.query('CREATE INDEX IF NOT EXISTS idx_fingerprints_click_id ON device_fingerprints(click_id)');
245
+ await client.query('CREATE INDEX IF NOT EXISTS idx_installs_fingerprint ON install_events(fingerprint_hash)');
246
+ await client.query('CREATE INDEX IF NOT EXISTS idx_installs_link_id ON install_events(link_id)');
247
+ await client.query('CREATE INDEX IF NOT EXISTS idx_installs_timestamp ON install_events(installed_at DESC)');
248
+ await client.query('CREATE INDEX IF NOT EXISTS idx_installs_link_date ON install_events(link_id, installed_at DESC)');
249
+ // Indexes for webhooks
250
+ await client.query('CREATE INDEX IF NOT EXISTS idx_webhooks_user_id ON webhooks(user_id)');
251
+ await client.query('CREATE INDEX IF NOT EXISTS idx_webhooks_active ON webhooks(is_active) WHERE is_active = true');
252
+ // Indexes for in-app events
253
+ await client.query('CREATE INDEX IF NOT EXISTS idx_in_app_events_install_id ON in_app_events(install_id)');
254
+ await client.query('CREATE INDEX IF NOT EXISTS idx_in_app_events_name ON in_app_events(event_name)');
255
+ await client.query('CREATE INDEX IF NOT EXISTS idx_in_app_events_timestamp ON in_app_events(event_timestamp DESC)');
108
256
  console.log('Database schema initialized successfully');
109
257
  }
110
258
  catch (error) {
@@ -1 +1 @@
1
- {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"database.js","sourceRoot":"","sources":["../../src/lib/database.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,46 @@
1
+ import { EventEmitter } from 'events';
2
+ /**
3
+ * Global event emitter for real-time events
4
+ * Used for broadcasting click events to WebSocket clients
5
+ */
6
+ export declare const clickEventEmitter: EventEmitter<[never]>;
7
+ /**
8
+ * Click event data structure for real-time streaming
9
+ */
10
+ export interface ClickEventData {
11
+ eventId: string;
12
+ timestamp: string;
13
+ linkId: string;
14
+ shortCode: string;
15
+ userId: string;
16
+ organizationId?: string;
17
+ ipAddress: string;
18
+ userAgent: string;
19
+ country?: string;
20
+ city?: string;
21
+ deviceType: 'ios' | 'android' | 'web';
22
+ platform?: string;
23
+ browser?: string;
24
+ redirectUrl: string;
25
+ redirectReason: string;
26
+ targetingMatched: boolean;
27
+ utmParameters?: {
28
+ source?: string;
29
+ medium?: string;
30
+ campaign?: string;
31
+ term?: string;
32
+ content?: string;
33
+ };
34
+ referer?: string;
35
+ language?: string;
36
+ }
37
+ /**
38
+ * Emit a click event for real-time streaming
39
+ */
40
+ export declare function emitClickEvent(eventData: ClickEventData): void;
41
+ /**
42
+ * Subscribe to click events
43
+ * Returns unsubscribe function
44
+ */
45
+ export declare function subscribeToClickEvents(callback: (eventData: ClickEventData) => void): () => void;
46
+ //# sourceMappingURL=event-emitter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.d.ts","sourceRoot":"","sources":["../../src/lib/event-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC;;;GAGG;AACH,eAAO,MAAM,iBAAiB,uBAAqB,CAAC;AAEpD;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,CAAC;IAGxB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IAGd,UAAU,EAAE,KAAK,GAAG,SAAS,GAAG,KAAK,CAAC;IACtC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IAGjB,WAAW,EAAE,MAAM,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAG1B,aAAa,CAAC,EAAE;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,OAAO,CAAC,EAAE,MAAM,CAAC;KAClB,CAAC;IAGF,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,SAAS,EAAE,cAAc,QAEvD;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,CAAC,SAAS,EAAE,cAAc,KAAK,IAAI,GAC5C,MAAM,IAAI,CAOZ"}
@@ -0,0 +1,24 @@
1
+ import { EventEmitter } from 'events';
2
+ /**
3
+ * Global event emitter for real-time events
4
+ * Used for broadcasting click events to WebSocket clients
5
+ */
6
+ export const clickEventEmitter = new EventEmitter();
7
+ /**
8
+ * Emit a click event for real-time streaming
9
+ */
10
+ export function emitClickEvent(eventData) {
11
+ clickEventEmitter.emit('click', eventData);
12
+ }
13
+ /**
14
+ * Subscribe to click events
15
+ * Returns unsubscribe function
16
+ */
17
+ export function subscribeToClickEvents(callback) {
18
+ clickEventEmitter.on('click', callback);
19
+ // Return unsubscribe function
20
+ return () => {
21
+ clickEventEmitter.off('click', callback);
22
+ };
23
+ }
24
+ //# sourceMappingURL=event-emitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-emitter.js","sourceRoot":"","sources":["../../src/lib/event-emitter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAEtC;;;GAGG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,YAAY,EAAE,CAAC;AA2CpD;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,SAAyB;IACtD,iBAAiB,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;AAC7C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,sBAAsB,CACpC,QAA6C;IAE7C,iBAAiB,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAExC,8BAA8B;IAC9B,OAAO,GAAG,EAAE;QACV,iBAAiB,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;IAC3C,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,64 @@
1
+ /**
2
+ * Device fingerprint data structure
3
+ */
4
+ export interface FingerprintData {
5
+ ipAddress: string;
6
+ userAgent: string;
7
+ timezone?: string;
8
+ language?: string;
9
+ screenWidth?: number;
10
+ screenHeight?: number;
11
+ platform?: string;
12
+ platformVersion?: string;
13
+ }
14
+ /**
15
+ * Fingerprint match result with confidence scoring
16
+ */
17
+ export interface FingerprintMatch {
18
+ clickId: string;
19
+ linkId: string;
20
+ confidenceScore: number;
21
+ matchedFactors: string[];
22
+ clickedAt: Date;
23
+ }
24
+ /**
25
+ * Default attribution window in hours (7 days)
26
+ */
27
+ export declare const DEFAULT_ATTRIBUTION_WINDOW_HOURS = 168;
28
+ /**
29
+ * Minimum confidence threshold for attribution (70%)
30
+ */
31
+ export declare const CONFIDENCE_THRESHOLD = 70;
32
+ /**
33
+ * Generate a fingerprint hash from device data
34
+ * Uses SHA-256 hash of concatenated device attributes
35
+ */
36
+ export declare function generateFingerprintHash(data: FingerprintData): string;
37
+ /**
38
+ * Calculate confidence score by comparing two fingerprints
39
+ * Returns a score from 0-100 based on matched components
40
+ */
41
+ export declare function calculateConfidenceScore(fingerprint1: FingerprintData, fingerprint2: FingerprintData): {
42
+ score: number;
43
+ matchedFactors: string[];
44
+ };
45
+ /**
46
+ * Match an install event to potential click events via probabilistic fingerprinting
47
+ * Returns the best match above confidence threshold within attribution window
48
+ *
49
+ * Note: Uses link-specific attribution windows - each link can have its own window
50
+ */
51
+ export declare function matchInstallToClick(installFingerprint: FingerprintData, attributionWindowHours?: number): Promise<FingerprintMatch | null>;
52
+ /**
53
+ * Store device fingerprint for a click event
54
+ */
55
+ export declare function storeFingerprintForClick(clickId: string, fingerprintData: FingerprintData): Promise<void>;
56
+ /**
57
+ * Record an install event and attempt to match it to a click
58
+ */
59
+ export declare function recordInstallEvent(fingerprintData: FingerprintData, deviceId?: string, attributionWindowHours?: number): Promise<{
60
+ installId: string;
61
+ match: FingerprintMatch | null;
62
+ deepLinkData: any;
63
+ }>;
64
+ //# sourceMappingURL=fingerprint.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fingerprint.d.ts","sourceRoot":"","sources":["../../src/lib/fingerprint.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,WAAW,eAAe;IAC9B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,EAAE,CAAC;IACzB,SAAS,EAAE,IAAI,CAAC;CACjB;AAcD;;GAEG;AACH,eAAO,MAAM,gCAAgC,MAAM,CAAC;AAEpD;;GAEG;AACH,eAAO,MAAM,oBAAoB,KAAK,CAAC;AAEvC;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,eAAe,GAAG,MAAM,CAcrE;AA0CD;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,YAAY,EAAE,eAAe,EAC7B,YAAY,EAAE,eAAe,GAC5B;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,MAAM,EAAE,CAAA;CAAE,CA+D7C;AAED;;;;;GAKG;AACH,wBAAsB,mBAAmB,CACvC,kBAAkB,EAAE,eAAe,EACnC,sBAAsB,GAAE,MAAyC,GAChE,OAAO,CAAC,gBAAgB,GAAG,IAAI,CAAC,CAgFlC;AAED;;GAEG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,EAAE,MAAM,EACf,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,eAAe,EAAE,eAAe,EAChC,QAAQ,CAAC,EAAE,MAAM,EACjB,sBAAsB,GAAE,MAAyC,GAChE,OAAO,CAAC;IACT,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC/B,YAAY,EAAE,GAAG,CAAC;CACnB,CAAC,CA8ID"}