@linkforty/core 1.44.0 → 1.44.2

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 (174) hide show
  1. package/README.md +6 -6
  2. package/package.json +2 -1
  3. package/dist/index.config.test.d.ts +0 -2
  4. package/dist/index.config.test.d.ts.map +0 -1
  5. package/dist/index.config.test.js +0 -87
  6. package/dist/index.config.test.js.map +0 -1
  7. package/dist/lib/bot-detection.test.d.ts +0 -2
  8. package/dist/lib/bot-detection.test.d.ts.map +0 -1
  9. package/dist/lib/bot-detection.test.js +0 -65
  10. package/dist/lib/bot-detection.test.js.map +0 -1
  11. package/dist/lib/client-ip.test.d.ts +0 -7
  12. package/dist/lib/client-ip.test.d.ts.map +0 -1
  13. package/dist/lib/client-ip.test.js +0 -114
  14. package/dist/lib/client-ip.test.js.map +0 -1
  15. package/dist/lib/config.test.d.ts +0 -2
  16. package/dist/lib/config.test.d.ts.map +0 -1
  17. package/dist/lib/config.test.js +0 -126
  18. package/dist/lib/config.test.js.map +0 -1
  19. package/dist/lib/database.test.d.ts +0 -2
  20. package/dist/lib/database.test.d.ts.map +0 -1
  21. package/dist/lib/database.test.js +0 -180
  22. package/dist/lib/database.test.js.map +0 -1
  23. package/dist/lib/deep-link-payload.test.d.ts +0 -2
  24. package/dist/lib/deep-link-payload.test.d.ts.map +0 -1
  25. package/dist/lib/deep-link-payload.test.js +0 -202
  26. package/dist/lib/deep-link-payload.test.js.map +0 -1
  27. package/dist/lib/event-emitter.test.d.ts +0 -2
  28. package/dist/lib/event-emitter.test.d.ts.map +0 -1
  29. package/dist/lib/event-emitter.test.js +0 -162
  30. package/dist/lib/event-emitter.test.js.map +0 -1
  31. package/dist/lib/fingerprint.test.d.ts +0 -2
  32. package/dist/lib/fingerprint.test.d.ts.map +0 -1
  33. package/dist/lib/fingerprint.test.js +0 -750
  34. package/dist/lib/fingerprint.test.js.map +0 -1
  35. package/dist/lib/launchpad.test.d.ts +0 -2
  36. package/dist/lib/launchpad.test.d.ts.map +0 -1
  37. package/dist/lib/launchpad.test.js +0 -368
  38. package/dist/lib/launchpad.test.js.map +0 -1
  39. package/dist/lib/link-lookup.test.d.ts +0 -2
  40. package/dist/lib/link-lookup.test.d.ts.map +0 -1
  41. package/dist/lib/link-lookup.test.js +0 -61
  42. package/dist/lib/link-lookup.test.js.map +0 -1
  43. package/dist/lib/link-resolution-cache.test.d.ts +0 -2
  44. package/dist/lib/link-resolution-cache.test.d.ts.map +0 -1
  45. package/dist/lib/link-resolution-cache.test.js +0 -45
  46. package/dist/lib/link-resolution-cache.test.js.map +0 -1
  47. package/dist/lib/link-safety.test.d.ts +0 -2
  48. package/dist/lib/link-safety.test.d.ts.map +0 -1
  49. package/dist/lib/link-safety.test.js +0 -211
  50. package/dist/lib/link-safety.test.js.map +0 -1
  51. package/dist/lib/not-found-page.test.d.ts +0 -2
  52. package/dist/lib/not-found-page.test.d.ts.map +0 -1
  53. package/dist/lib/not-found-page.test.js +0 -151
  54. package/dist/lib/not-found-page.test.js.map +0 -1
  55. package/dist/lib/portable/cli.test.d.ts +0 -2
  56. package/dist/lib/portable/cli.test.d.ts.map +0 -1
  57. package/dist/lib/portable/cli.test.js +0 -98
  58. package/dist/lib/portable/cli.test.js.map +0 -1
  59. package/dist/lib/portable/portable.integration.test.d.ts +0 -2
  60. package/dist/lib/portable/portable.integration.test.d.ts.map +0 -1
  61. package/dist/lib/portable/portable.integration.test.js +0 -139
  62. package/dist/lib/portable/portable.integration.test.js.map +0 -1
  63. package/dist/lib/portable/registry.schema.test.d.ts +0 -2
  64. package/dist/lib/portable/registry.schema.test.d.ts.map +0 -1
  65. package/dist/lib/portable/registry.schema.test.js +0 -59
  66. package/dist/lib/portable/registry.schema.test.js.map +0 -1
  67. package/dist/lib/scanner-detection.test.d.ts +0 -2
  68. package/dist/lib/scanner-detection.test.d.ts.map +0 -1
  69. package/dist/lib/scanner-detection.test.js +0 -124
  70. package/dist/lib/scanner-detection.test.js.map +0 -1
  71. package/dist/lib/schema-guard.test.d.ts +0 -2
  72. package/dist/lib/schema-guard.test.d.ts.map +0 -1
  73. package/dist/lib/schema-guard.test.js +0 -83
  74. package/dist/lib/schema-guard.test.js.map +0 -1
  75. package/dist/lib/utils.test.d.ts +0 -2
  76. package/dist/lib/utils.test.d.ts.map +0 -1
  77. package/dist/lib/utils.test.js +0 -261
  78. package/dist/lib/utils.test.js.map +0 -1
  79. package/dist/lib/webhook.test.d.ts +0 -2
  80. package/dist/lib/webhook.test.d.ts.map +0 -1
  81. package/dist/lib/webhook.test.js +0 -340
  82. package/dist/lib/webhook.test.js.map +0 -1
  83. package/dist/routes/health.test.d.ts +0 -2
  84. package/dist/routes/health.test.d.ts.map +0 -1
  85. package/dist/routes/health.test.js +0 -82
  86. package/dist/routes/health.test.js.map +0 -1
  87. package/dist/routes/preview.test.d.ts +0 -2
  88. package/dist/routes/preview.test.d.ts.map +0 -1
  89. package/dist/routes/preview.test.js +0 -111
  90. package/dist/routes/preview.test.js.map +0 -1
  91. package/dist/routes/qr.test.d.ts +0 -2
  92. package/dist/routes/qr.test.d.ts.map +0 -1
  93. package/dist/routes/qr.test.js +0 -67
  94. package/dist/routes/qr.test.js.map +0 -1
  95. package/dist/routes/redirect.click-event.test.d.ts +0 -2
  96. package/dist/routes/redirect.click-event.test.d.ts.map +0 -1
  97. package/dist/routes/redirect.click-event.test.js +0 -85
  98. package/dist/routes/redirect.click-event.test.js.map +0 -1
  99. package/dist/routes/redirect.host-scope.integration.test.d.ts +0 -2
  100. package/dist/routes/redirect.host-scope.integration.test.d.ts.map +0 -1
  101. package/dist/routes/redirect.host-scope.integration.test.js +0 -105
  102. package/dist/routes/redirect.host-scope.integration.test.js.map +0 -1
  103. package/dist/routes/redirect.interstitial.test.d.ts +0 -2
  104. package/dist/routes/redirect.interstitial.test.d.ts.map +0 -1
  105. package/dist/routes/redirect.interstitial.test.js +0 -128
  106. package/dist/routes/redirect.interstitial.test.js.map +0 -1
  107. package/dist/routes/redirect.launchpad.test.d.ts +0 -2
  108. package/dist/routes/redirect.launchpad.test.d.ts.map +0 -1
  109. package/dist/routes/redirect.launchpad.test.js +0 -515
  110. package/dist/routes/redirect.launchpad.test.js.map +0 -1
  111. package/dist/routes/redirect.no-web-destination.test.d.ts +0 -2
  112. package/dist/routes/redirect.no-web-destination.test.d.ts.map +0 -1
  113. package/dist/routes/redirect.no-web-destination.test.js +0 -176
  114. package/dist/routes/redirect.no-web-destination.test.js.map +0 -1
  115. package/dist/routes/redirect.not-found.test.d.ts +0 -2
  116. package/dist/routes/redirect.not-found.test.d.ts.map +0 -1
  117. package/dist/routes/redirect.not-found.test.js +0 -280
  118. package/dist/routes/redirect.not-found.test.js.map +0 -1
  119. package/dist/routes/redirect.safety.test.d.ts +0 -2
  120. package/dist/routes/redirect.safety.test.d.ts.map +0 -1
  121. package/dist/routes/redirect.safety.test.js +0 -284
  122. package/dist/routes/redirect.safety.test.js.map +0 -1
  123. package/dist/routes/redirect.store-url.test.d.ts +0 -2
  124. package/dist/routes/redirect.store-url.test.d.ts.map +0 -1
  125. package/dist/routes/redirect.store-url.test.js +0 -239
  126. package/dist/routes/redirect.store-url.test.js.map +0 -1
  127. package/dist/routes/redirect.test.d.ts +0 -2
  128. package/dist/routes/redirect.test.d.ts.map +0 -1
  129. package/dist/routes/redirect.test.js +0 -158
  130. package/dist/routes/redirect.test.js.map +0 -1
  131. package/dist/routes/redirect.web-link.test.d.ts +0 -2
  132. package/dist/routes/redirect.web-link.test.d.ts.map +0 -1
  133. package/dist/routes/redirect.web-link.test.js +0 -138
  134. package/dist/routes/redirect.web-link.test.js.map +0 -1
  135. package/dist/routes/sdk-cache-bypass.test.d.ts +0 -2
  136. package/dist/routes/sdk-cache-bypass.test.d.ts.map +0 -1
  137. package/dist/routes/sdk-cache-bypass.test.js +0 -175
  138. package/dist/routes/sdk-cache-bypass.test.js.map +0 -1
  139. package/dist/routes/sdk.device-values.integration.test.d.ts +0 -2
  140. package/dist/routes/sdk.device-values.integration.test.d.ts.map +0 -1
  141. package/dist/routes/sdk.device-values.integration.test.js +0 -132
  142. package/dist/routes/sdk.device-values.integration.test.js.map +0 -1
  143. package/dist/routes/sdk.event.test.d.ts +0 -2
  144. package/dist/routes/sdk.event.test.d.ts.map +0 -1
  145. package/dist/routes/sdk.event.test.js +0 -284
  146. package/dist/routes/sdk.event.test.js.map +0 -1
  147. package/dist/routes/sdk.install-certainty.integration.test.d.ts +0 -2
  148. package/dist/routes/sdk.install-certainty.integration.test.d.ts.map +0 -1
  149. package/dist/routes/sdk.install-certainty.integration.test.js +0 -104
  150. package/dist/routes/sdk.install-certainty.integration.test.js.map +0 -1
  151. package/dist/routes/sdk.install-live-links.integration.test.d.ts +0 -2
  152. package/dist/routes/sdk.install-live-links.integration.test.d.ts.map +0 -1
  153. package/dist/routes/sdk.install-live-links.integration.test.js +0 -92
  154. package/dist/routes/sdk.install-live-links.integration.test.js.map +0 -1
  155. package/dist/routes/sdk.install-referrer.integration.test.d.ts +0 -2
  156. package/dist/routes/sdk.install-referrer.integration.test.d.ts.map +0 -1
  157. package/dist/routes/sdk.install-referrer.integration.test.js +0 -187
  158. package/dist/routes/sdk.install-referrer.integration.test.js.map +0 -1
  159. package/dist/routes/sdk.install-window-once.integration.test.d.ts +0 -2
  160. package/dist/routes/sdk.install-window-once.integration.test.d.ts.map +0 -1
  161. package/dist/routes/sdk.install-window-once.integration.test.js +0 -147
  162. package/dist/routes/sdk.install-window-once.integration.test.js.map +0 -1
  163. package/dist/routes/sdk.install.test.d.ts +0 -2
  164. package/dist/routes/sdk.install.test.d.ts.map +0 -1
  165. package/dist/routes/sdk.install.test.js +0 -99
  166. package/dist/routes/sdk.install.test.js.map +0 -1
  167. package/dist/routes/sdk.resolve-click.test.d.ts +0 -2
  168. package/dist/routes/sdk.resolve-click.test.d.ts.map +0 -1
  169. package/dist/routes/sdk.resolve-click.test.js +0 -79
  170. package/dist/routes/sdk.resolve-click.test.js.map +0 -1
  171. package/dist/routes/sdk.resolve-scope.test.d.ts +0 -2
  172. package/dist/routes/sdk.resolve-scope.test.d.ts.map +0 -1
  173. package/dist/routes/sdk.resolve-scope.test.js +0 -105
  174. package/dist/routes/sdk.resolve-scope.test.js.map +0 -1
@@ -1,180 +0,0 @@
1
- import pg from 'pg';
2
- import { afterAll, beforeAll, describe, expect, it, vi } from 'vitest';
3
- import { SCHEMA_INIT_LOCK_KEY, db, initializeDatabase } from './database.js';
4
- /**
5
- * Schema initialisation must serialise across processes.
6
- *
7
- * `CREATE TABLE IF NOT EXISTS` is not atomic — the existence check and the
8
- * creation are separate steps — so two connections initialising an empty
9
- * database at once can both find a table absent and both try to create it. The
10
- * loser fails with a `pg_type_typname_nsp_index` unique violation. An advisory
11
- * lock makes the second caller wait instead.
12
- *
13
- * This needs a real database: the behaviour under test is a property of
14
- * Postgres locking, and a mocked client would accept any sequence of queries.
15
- * The suite skips itself when DATABASE_URL is absent so `npm test` stays green
16
- * without one.
17
- */
18
- const ADMIN_URL = process.env.DATABASE_URL;
19
- if (!ADMIN_URL) {
20
- // eslint-disable-next-line no-console
21
- console.warn('\n database.test.ts skipped: set DATABASE_URL to run it.' +
22
- '\n It creates and drops a scratch database, so the user needs CREATEDB.\n');
23
- }
24
- describe.skipIf(!ADMIN_URL)('initializeDatabase schema lock', () => {
25
- // A scratch database per run: the race only exists against an EMPTY schema,
26
- // and initialising a shared database would also mutate whatever is in it.
27
- const scratchName = `lf_core_schema_init_${Date.now()}`;
28
- let admin;
29
- let scratchUrl;
30
- beforeAll(async () => {
31
- admin = new pg.Client({ connectionString: ADMIN_URL });
32
- await admin.connect();
33
- await admin.query(`CREATE DATABASE ${scratchName}`);
34
- const url = new URL(ADMIN_URL);
35
- url.pathname = `/${scratchName}`;
36
- scratchUrl = url.toString();
37
- }, 30000);
38
- afterAll(async () => {
39
- // The pool `initializeDatabase` created still holds connections, and
40
- // Postgres refuses to drop a database that has any.
41
- await db?.end().catch(() => undefined);
42
- await admin.query(`DROP DATABASE IF EXISTS ${scratchName} WITH (FORCE)`);
43
- await admin.end();
44
- }, 30000);
45
- it('waits for a concurrent initialisation rather than racing it', async () => {
46
- // Stand in for a second instance that got there first.
47
- const holder = new pg.Client({ connectionString: scratchUrl });
48
- await holder.connect();
49
- await holder.query('SELECT pg_advisory_lock($1)', [SCHEMA_INIT_LOCK_KEY]);
50
- let settled = false;
51
- const init = initializeDatabase({ url: scratchUrl, pool: { min: 1, max: 2 } }).then(() => {
52
- settled = true;
53
- });
54
- // Long enough that an unsynchronised initialisation would have finished
55
- // creating tables and resolved.
56
- await new Promise((resolve) => setTimeout(resolve, 500));
57
- expect(settled).toBe(false);
58
- await holder.query('SELECT pg_advisory_unlock($1)', [SCHEMA_INIT_LOCK_KEY]);
59
- await holder.end();
60
- await init;
61
- expect(settled).toBe(true);
62
- }, 60000);
63
- it('releases the lock once initialisation completes', async () => {
64
- // Runs after the case above, which left a fully initialised database. A
65
- // leaked lock would block every subsequent boot, so assert it is gone.
66
- const probe = new pg.Client({ connectionString: scratchUrl });
67
- await probe.connect();
68
- try {
69
- const { rows } = await probe.query('SELECT pg_try_advisory_lock($1) AS acquired', [
70
- SCHEMA_INIT_LOCK_KEY,
71
- ]);
72
- expect(rows[0].acquired).toBe(true);
73
- await probe.query('SELECT pg_advisory_unlock($1)', [SCHEMA_INIT_LOCK_KEY]);
74
- }
75
- finally {
76
- await probe.end();
77
- }
78
- }, 30000);
79
- });
80
- describe.skipIf(!ADMIN_URL)('initialisation against a table someone is reading', () => {
81
- // Postgres takes a table's lock before it evaluates IF NOT EXISTS, so a
82
- // second start used to park an ACCESS EXCLUSIVE request on `links` behind
83
- // any long reader — and every redirect behind that. With the catalog guard
84
- // nothing is sent for a column that exists, and with a lock timeout a
85
- // statement that does need the table gives up instead of queueing it.
86
- const scratchName = `lf_core_schema_guard_${Date.now()}`;
87
- let admin;
88
- let scratchUrl;
89
- const pools = [];
90
- beforeAll(async () => {
91
- admin = new pg.Client({ connectionString: ADMIN_URL });
92
- await admin.connect();
93
- await admin.query(`CREATE DATABASE ${scratchName}`);
94
- const url = new URL(ADMIN_URL);
95
- url.pathname = `/${scratchName}`;
96
- scratchUrl = url.toString();
97
- // First start: every table, column and index exists afterwards.
98
- await initializeDatabase({ url: scratchUrl, pool: { min: 1, max: 2 } });
99
- pools.push(db);
100
- }, 60000);
101
- afterAll(async () => {
102
- for (const p of pools)
103
- await p.end().catch(() => undefined);
104
- await db?.end().catch(() => undefined);
105
- await admin.query(`DROP DATABASE IF EXISTS ${scratchName} WITH (FORCE)`);
106
- await admin.end();
107
- }, 30000);
108
- it('a second start completes while a transaction holds ACCESS SHARE on links, and the setting does not leak', async () => {
109
- const reader = new pg.Client({ connectionString: scratchUrl });
110
- await reader.connect();
111
- try {
112
- await reader.query('BEGIN');
113
- await reader.query('SELECT 1 FROM links LIMIT 1');
114
- const started = Date.now();
115
- await initializeDatabase({ url: scratchUrl, pool: { min: 1, max: 2 }, lockTimeoutMs: 2000 });
116
- pools.push(db);
117
- // Nothing waited: well under a single lock timeout.
118
- expect(Date.now() - started).toBeLessThan(10000);
119
- // The reader was never blocked either.
120
- const t = Date.now();
121
- await reader.query('SELECT 1 FROM links LIMIT 1');
122
- expect(Date.now() - t).toBeLessThan(1000);
123
- // The timeout was session-level on the initialisation client and was
124
- // reset before that client went back to the pool.
125
- const { rows } = await db.query('SHOW lock_timeout');
126
- expect(rows[0].lock_timeout).toBe('0');
127
- }
128
- finally {
129
- await reader.query('ROLLBACK').catch(() => undefined);
130
- await reader.end();
131
- }
132
- }, 60000);
133
- it('a statement that does need the table fails with 55P03 after the timeout instead of queueing it', async () => {
134
- const reader = new pg.Client({ connectionString: scratchUrl });
135
- const other = new pg.Client({ connectionString: scratchUrl });
136
- await reader.connect();
137
- await other.connect();
138
- try {
139
- await reader.query('BEGIN');
140
- await reader.query('SELECT 1 FROM links LIMIT 1');
141
- await other.query('SET lock_timeout = 1000');
142
- const t = Date.now();
143
- await expect(other.query('ALTER TABLE links ADD COLUMN probe_column_not_guarded INTEGER')).rejects.toMatchObject({ code: '55P03' });
144
- expect(Date.now() - t).toBeLessThan(5000);
145
- }
146
- finally {
147
- await reader.query('ROLLBACK').catch(() => undefined);
148
- await reader.end();
149
- await other.end();
150
- }
151
- }, 30000);
152
- });
153
- describe.skipIf(!ADMIN_URL)('idle connection errors', () => {
154
- const scratchName = `lf_core_idle_error_${Date.now()}`;
155
- let admin;
156
- beforeAll(async () => {
157
- admin = new pg.Client({ connectionString: ADMIN_URL });
158
- await admin.connect();
159
- await admin.query(`CREATE DATABASE ${scratchName}`);
160
- }, 30000);
161
- afterAll(async () => {
162
- await db?.end().catch(() => undefined);
163
- await admin.query(`DROP DATABASE IF EXISTS ${scratchName} WITH (FORCE)`);
164
- await admin.end();
165
- }, 30000);
166
- it('keeps the process alive when the server closes an idle connection, and serves the next query', async () => {
167
- const url = new URL(ADMIN_URL);
168
- url.pathname = `/${scratchName}`;
169
- await initializeDatabase({ url: url.toString(), pool: { min: 1, max: 2 } });
170
- await db.query('SELECT 1');
171
- expect(db.idleCount).toBeGreaterThan(0);
172
- // No listener of the test's own: an unhandled pool error here would fail
173
- // the run (and exit a server).
174
- await admin.query(`SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = $1 AND pid <> pg_backend_pid()`, [scratchName]);
175
- // The pool drops each closed connection once it has reported the error.
176
- await vi.waitFor(() => expect(db.totalCount).toBe(0), { timeout: 10000 });
177
- expect((await db.query('SELECT 1 AS ok')).rows[0].ok).toBe(1);
178
- }, 60000);
179
- });
180
- //# sourceMappingURL=database.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"database.test.js","sourceRoot":"","sources":["../../src/lib/database.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=deep-link-payload.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deep-link-payload.test.d.ts","sourceRoot":"","sources":["../../src/lib/deep-link-payload.test.ts"],"names":[],"mappings":""}
@@ -1,202 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { toDeepLinkPayload, CANONICAL_DEEP_LINK_KEYS, } from './deep-link-payload.js';
3
- const link = {
4
- id: 'link-123',
5
- short_code: 'abc123',
6
- original_url: 'https://example.com/product/456',
7
- deep_link_path: '/product/456',
8
- app_scheme: 'myapp',
9
- ios_app_store_url: 'https://apps.apple.com/app/id123',
10
- android_app_store_url: 'https://play.google.com/store/apps/details?id=com.example',
11
- web_fallback_url: 'https://example.com',
12
- utm_parameters: { source: 'facebook', campaign: 'summer' },
13
- targeting_rules: { countries: ['US'] },
14
- deep_link_parameters: { productId: '456' },
15
- };
16
- const clickedAt = new Date('2026-01-15T10:30:00.000Z');
17
- /** How the install endpoint projects a matched link. */
18
- function installPayload(row = link) {
19
- return toDeepLinkPayload(row, {
20
- clickedAt,
21
- isDeferred: true,
22
- confidenceScore: 85,
23
- matchedFactors: ['userAgent', 'timezone'],
24
- attributionMethod: 'fingerprint',
25
- competingLinks: 0,
26
- legacyInstallKeys: true,
27
- });
28
- }
29
- /** How the resolve endpoint projects a directly opened link. */
30
- function resolvePayload(row = link) {
31
- return toDeepLinkPayload(row, {
32
- clickedAt: clickedAt.toISOString(),
33
- isDeferred: false,
34
- });
35
- }
36
- describe('toDeepLinkPayload', () => {
37
- it('projects a link into the shape the SDK DeepLinkData model expects', () => {
38
- expect(resolvePayload()).toEqual({
39
- shortCode: 'abc123',
40
- linkId: 'link-123',
41
- deepLinkPath: '/product/456',
42
- appScheme: 'myapp',
43
- iosUrl: 'https://apps.apple.com/app/id123',
44
- androidUrl: 'https://play.google.com/store/apps/details?id=com.example',
45
- webUrl: 'https://example.com',
46
- utmParameters: { source: 'facebook', campaign: 'summer' },
47
- customParameters: { productId: '456' },
48
- clickedAt: '2026-01-15T10:30:00.000Z',
49
- isDeferred: false,
50
- });
51
- });
52
- it('normalizes a Date clickedAt to an ISO string', () => {
53
- expect(installPayload().clickedAt).toBe('2026-01-15T10:30:00.000Z');
54
- });
55
- it('omits empty canonical fields rather than sending null', () => {
56
- const payload = resolvePayload({ short_code: 'bare' });
57
- expect(payload.shortCode).toBe('bare');
58
- expect('deepLinkPath' in payload).toBe(false);
59
- expect('appScheme' in payload).toBe(false);
60
- expect('webUrl' in payload).toBe(false);
61
- expect('linkId' in payload).toBe(false);
62
- });
63
- it('carries attribution metadata on deferred opens only', () => {
64
- const deferred = installPayload();
65
- expect(deferred.isDeferred).toBe(true);
66
- expect(deferred.confidenceScore).toBe(85);
67
- expect(deferred.matchedFactors).toEqual(['userAgent', 'timezone']);
68
- expect(deferred.attributionMethod).toBe('fingerprint');
69
- // Zero is reported, not dropped: it is the answer an app checks for.
70
- expect(deferred.competingLinks).toBe(0);
71
- const direct = resolvePayload();
72
- expect(direct.isDeferred).toBe(false);
73
- expect('confidenceScore' in direct).toBe(false);
74
- expect('matchedFactors' in direct).toBe(false);
75
- expect('attributionMethod' in direct).toBe(false);
76
- expect('competingLinks' in direct).toBe(false);
77
- });
78
- it('reports a zero confidence score rather than dropping it', () => {
79
- const payload = toDeepLinkPayload(link, {
80
- clickedAt,
81
- isDeferred: true,
82
- confidenceScore: 0,
83
- matchedFactors: [],
84
- });
85
- expect(payload.confidenceScore).toBe(0);
86
- expect(payload.matchedFactors).toEqual([]);
87
- });
88
- });
89
- /**
90
- * The contract that keeps the install and resolve payloads from drifting apart
91
- * again. Both endpoints describe the same link to the same SDK model, so every
92
- * canonical field must carry the same value on both paths.
93
- */
94
- describe('install and resolve payload contract', () => {
95
- it('agrees field for field on every canonical key', () => {
96
- const install = installPayload();
97
- const resolve = resolvePayload();
98
- for (const key of CANONICAL_DEEP_LINK_KEYS) {
99
- if (key === 'isDeferred')
100
- continue; // The one field that must differ.
101
- expect(resolve[key], `resolve.${key}`).toEqual(install[key]);
102
- }
103
- });
104
- it('gives the deferred payload every field an app needs to route', () => {
105
- const payload = installPayload();
106
- // The whole point of a deferred deep link: a newly installed user lands on
107
- // the right screen, and the first session is credited to the link.
108
- expect(payload.deepLinkPath).toBe('/product/456');
109
- expect(payload.appScheme).toBe('myapp');
110
- expect(payload.customParameters).toEqual({ productId: '456' });
111
- expect(payload.linkId).toBe('link-123');
112
- });
113
- });
114
- /**
115
- * Every SDK already in the field reads the pre-1.22 install keys. App updates
116
- * take weeks to roll out, so these must keep their exact previous values —
117
- * including nulls, which is why they are asserted with `toBe`/`in` rather than
118
- * a loose truthiness check.
119
- */
120
- describe('legacy install keys', () => {
121
- it('emits the old aliases alongside the canonical ones', () => {
122
- const payload = installPayload();
123
- expect(payload.originalUrl).toBe('https://example.com/product/456');
124
- expect(payload.webFallbackUrl).toBe('https://example.com');
125
- expect(payload.targetingRules).toEqual({ countries: ['US'] });
126
- expect(payload.deepLinkParameters).toEqual({ productId: '456' });
127
- // The canonical spellings of the same values ship in the same payload.
128
- expect(payload.webUrl).toBe(payload.webFallbackUrl);
129
- expect(payload.customParameters).toEqual(payload.deepLinkParameters);
130
- });
131
- it('keeps null legacy values present rather than omitting the key', () => {
132
- const payload = installPayload({ short_code: 'bare' });
133
- expect(payload.originalUrl).toBeNull();
134
- expect(payload.webFallbackUrl).toBeNull();
135
- expect(payload.targetingRules).toBeNull();
136
- expect(payload.deepLinkParameters).toBeNull();
137
- });
138
- it('does not leak legacy keys into the resolve payload', () => {
139
- const payload = resolvePayload();
140
- expect('originalUrl' in payload).toBe(false);
141
- expect('webFallbackUrl' in payload).toBe(false);
142
- expect('targetingRules' in payload).toBe(false);
143
- expect('deepLinkParameters' in payload).toBe(false);
144
- });
145
- });
146
- describe('toDeepLinkPayload — click params', () => {
147
- const link = { short_code: 'abc123' };
148
- const base = { clickedAt: '2026-09-09T00:00:00.000Z', isDeferred: true };
149
- it('merges click params when the link has none configured', () => {
150
- const p = toDeepLinkPayload(link, { ...base, linkParams: { slug: 'titanic' } });
151
- expect(p.customParameters).toEqual({ slug: 'titanic' });
152
- });
153
- it('lets a click param override a configured one of the same name', () => {
154
- const p = toDeepLinkPayload({ ...link, deep_link_parameters: { slug: 'default', keep: 'me' } }, { ...base, linkParams: { slug: 'titanic' } });
155
- expect(p.customParameters).toEqual({ slug: 'titanic', keep: 'me' });
156
- });
157
- it('leaves the payload untouched when there are no click params', () => {
158
- const withParams = toDeepLinkPayload({ ...link, deep_link_parameters: { a: '1' } }, base);
159
- expect(withParams.customParameters).toEqual({ a: '1' });
160
- const withNone = toDeepLinkPayload(link, base);
161
- expect(withNone.customParameters).toBeUndefined();
162
- });
163
- it('treats an empty click-param object as no params', () => {
164
- const p = toDeepLinkPayload({ ...link, deep_link_parameters: { a: '1' } }, {
165
- ...base,
166
- linkParams: {},
167
- });
168
- expect(p.customParameters).toEqual({ a: '1' });
169
- });
170
- it('gives the legacy alias the same merged value as the canonical field', () => {
171
- const p = toDeepLinkPayload({ ...link, deep_link_parameters: { slug: 'default' } }, { ...base, linkParams: { slug: 'titanic' }, legacyInstallKeys: true });
172
- // SDKs in the field read deepLinkParameters in preference to
173
- // customParameters, so the two disagreeing would make the merge invisible.
174
- expect(p.deepLinkParameters).toEqual(p.customParameters);
175
- expect(p.deepLinkParameters).toEqual({ slug: 'titanic' });
176
- });
177
- it('keeps the legacy alias null when nothing is configured or carried', () => {
178
- const p = toDeepLinkPayload(link, { ...base, legacyInstallKeys: true });
179
- expect(p.deepLinkParameters).toBeNull();
180
- });
181
- it('does not throw when deep_link_parameters is null, a scalar or an array', () => {
182
- for (const bad of [null, 'nope', 42, ['a', 'b']]) {
183
- const p = toDeepLinkPayload({ ...link, deep_link_parameters: bad }, {
184
- ...base,
185
- linkParams: { slug: 'titanic' },
186
- });
187
- expect(p.customParameters).toEqual({ slug: 'titanic' });
188
- }
189
- });
190
- it('introduces no key outside the canonical set', () => {
191
- // The merge must land inside customParameters, never as a new top-level
192
- // field — SDKs decode a fixed shape.
193
- const p = toDeepLinkPayload(link, { ...base, linkParams: { slug: 'titanic' } });
194
- const allowed = new Set([
195
- ...CANONICAL_DEEP_LINK_KEYS,
196
- 'confidenceScore',
197
- 'matchedFactors',
198
- ]);
199
- expect(Object.keys(p).filter((k) => !allowed.has(k))).toEqual([]);
200
- });
201
- });
202
- //# sourceMappingURL=deep-link-payload.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"deep-link-payload.test.js","sourceRoot":"","sources":["../../src/lib/deep-link-payload.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=event-emitter.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-emitter.test.d.ts","sourceRoot":"","sources":["../../src/lib/event-emitter.test.ts"],"names":[],"mappings":""}
@@ -1,162 +0,0 @@
1
- import { describe, it, expect, vi, beforeEach } from 'vitest';
2
- import { clickEventEmitter, emitClickEvent, subscribeToClickEvents, } from './event-emitter';
3
- const mockClickEvent = {
4
- eventId: 'evt-123',
5
- timestamp: '2026-03-10T00:00:00.000Z',
6
- linkId: 'link-abc',
7
- shortCode: 'abc123',
8
- userId: 'user-1',
9
- organizationId: 'org-1',
10
- ipAddress: '1.2.3.4',
11
- userAgent: 'Mozilla/5.0',
12
- country: 'US',
13
- city: 'New York',
14
- deviceType: 'web',
15
- platform: 'Windows',
16
- browser: 'Chrome',
17
- redirectUrl: 'https://example.com',
18
- redirectReason: 'web_fallback',
19
- targetingMatched: true,
20
- utmParameters: {
21
- source: 'newsletter',
22
- medium: 'email',
23
- campaign: 'spring',
24
- },
25
- referer: 'https://google.com',
26
- language: 'en-US',
27
- };
28
- describe('clickEventEmitter', () => {
29
- it('should be an EventEmitter instance', () => {
30
- expect(clickEventEmitter).toBeDefined();
31
- expect(typeof clickEventEmitter.on).toBe('function');
32
- expect(typeof clickEventEmitter.emit).toBe('function');
33
- expect(typeof clickEventEmitter.off).toBe('function');
34
- });
35
- });
36
- describe('emitClickEvent', () => {
37
- beforeEach(() => {
38
- clickEventEmitter.removeAllListeners('click');
39
- });
40
- it('should emit a click event with the provided data', () => {
41
- const handler = vi.fn();
42
- clickEventEmitter.on('click', handler);
43
- emitClickEvent(mockClickEvent);
44
- expect(handler).toHaveBeenCalledOnce();
45
- expect(handler).toHaveBeenCalledWith(mockClickEvent);
46
- });
47
- it('should emit to all registered listeners', () => {
48
- const handler1 = vi.fn();
49
- const handler2 = vi.fn();
50
- clickEventEmitter.on('click', handler1);
51
- clickEventEmitter.on('click', handler2);
52
- emitClickEvent(mockClickEvent);
53
- expect(handler1).toHaveBeenCalledOnce();
54
- expect(handler2).toHaveBeenCalledOnce();
55
- });
56
- it('should emit multiple times when called multiple times', () => {
57
- const handler = vi.fn();
58
- clickEventEmitter.on('click', handler);
59
- emitClickEvent(mockClickEvent);
60
- emitClickEvent({ ...mockClickEvent, eventId: 'evt-456' });
61
- expect(handler).toHaveBeenCalledTimes(2);
62
- });
63
- it('should pass the exact event data to the handler', () => {
64
- const handler = vi.fn();
65
- clickEventEmitter.on('click', handler);
66
- const eventData = {
67
- ...mockClickEvent,
68
- deviceType: 'ios',
69
- country: 'CA',
70
- targetingMatched: false,
71
- };
72
- emitClickEvent(eventData);
73
- expect(handler).toHaveBeenCalledWith(eventData);
74
- });
75
- it('should work with minimal required fields', () => {
76
- const handler = vi.fn();
77
- clickEventEmitter.on('click', handler);
78
- const minimalEvent = {
79
- eventId: 'evt-min',
80
- timestamp: '2026-03-10T00:00:00.000Z',
81
- linkId: 'link-min',
82
- shortCode: 'min',
83
- ipAddress: '0.0.0.0',
84
- userAgent: '',
85
- deviceType: 'web',
86
- redirectUrl: 'https://example.com',
87
- redirectReason: 'default',
88
- targetingMatched: true,
89
- };
90
- emitClickEvent(minimalEvent);
91
- expect(handler).toHaveBeenCalledWith(minimalEvent);
92
- });
93
- });
94
- describe('subscribeToClickEvents', () => {
95
- beforeEach(() => {
96
- clickEventEmitter.removeAllListeners('click');
97
- });
98
- it('should call the callback when a click event is emitted', () => {
99
- const callback = vi.fn();
100
- subscribeToClickEvents(callback);
101
- emitClickEvent(mockClickEvent);
102
- expect(callback).toHaveBeenCalledOnce();
103
- expect(callback).toHaveBeenCalledWith(mockClickEvent);
104
- });
105
- it('should return an unsubscribe function', () => {
106
- const callback = vi.fn();
107
- const unsubscribe = subscribeToClickEvents(callback);
108
- expect(typeof unsubscribe).toBe('function');
109
- });
110
- it('should stop receiving events after unsubscribing', () => {
111
- const callback = vi.fn();
112
- const unsubscribe = subscribeToClickEvents(callback);
113
- emitClickEvent(mockClickEvent);
114
- expect(callback).toHaveBeenCalledOnce();
115
- unsubscribe();
116
- emitClickEvent(mockClickEvent);
117
- expect(callback).toHaveBeenCalledOnce(); // still only once
118
- });
119
- it('should allow multiple subscribers independently', () => {
120
- const callback1 = vi.fn();
121
- const callback2 = vi.fn();
122
- const unsubscribe1 = subscribeToClickEvents(callback1);
123
- subscribeToClickEvents(callback2);
124
- emitClickEvent(mockClickEvent);
125
- expect(callback1).toHaveBeenCalledOnce();
126
- expect(callback2).toHaveBeenCalledOnce();
127
- unsubscribe1();
128
- emitClickEvent(mockClickEvent);
129
- expect(callback1).toHaveBeenCalledOnce(); // no new calls
130
- expect(callback2).toHaveBeenCalledTimes(2);
131
- });
132
- it('should not affect other subscribers when one unsubscribes', () => {
133
- const callback1 = vi.fn();
134
- const callback2 = vi.fn();
135
- const unsubscribe1 = subscribeToClickEvents(callback1);
136
- subscribeToClickEvents(callback2);
137
- unsubscribe1();
138
- emitClickEvent(mockClickEvent);
139
- expect(callback1).not.toHaveBeenCalled();
140
- expect(callback2).toHaveBeenCalledOnce();
141
- });
142
- it('should handle unsubscribe called multiple times without error', () => {
143
- const callback = vi.fn();
144
- const unsubscribe = subscribeToClickEvents(callback);
145
- expect(() => {
146
- unsubscribe();
147
- unsubscribe();
148
- }).not.toThrow();
149
- });
150
- it('should pass event data correctly to callback', () => {
151
- const received = [];
152
- subscribeToClickEvents((data) => received.push(data));
153
- const event1 = { ...mockClickEvent, eventId: 'e1', deviceType: 'ios' };
154
- const event2 = { ...mockClickEvent, eventId: 'e2', deviceType: 'android' };
155
- emitClickEvent(event1);
156
- emitClickEvent(event2);
157
- expect(received).toHaveLength(2);
158
- expect(received[0]).toEqual(event1);
159
- expect(received[1]).toEqual(event2);
160
- });
161
- });
162
- //# sourceMappingURL=event-emitter.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"event-emitter.test.js","sourceRoot":"","sources":["../../src/lib/event-emitter.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=fingerprint.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fingerprint.test.d.ts","sourceRoot":"","sources":["../../src/lib/fingerprint.test.ts"],"names":[],"mappings":""}