@linkforty/core 1.44.1 → 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 (173) hide show
  1. package/package.json +2 -1
  2. package/dist/index.config.test.d.ts +0 -2
  3. package/dist/index.config.test.d.ts.map +0 -1
  4. package/dist/index.config.test.js +0 -87
  5. package/dist/index.config.test.js.map +0 -1
  6. package/dist/lib/bot-detection.test.d.ts +0 -2
  7. package/dist/lib/bot-detection.test.d.ts.map +0 -1
  8. package/dist/lib/bot-detection.test.js +0 -65
  9. package/dist/lib/bot-detection.test.js.map +0 -1
  10. package/dist/lib/client-ip.test.d.ts +0 -7
  11. package/dist/lib/client-ip.test.d.ts.map +0 -1
  12. package/dist/lib/client-ip.test.js +0 -114
  13. package/dist/lib/client-ip.test.js.map +0 -1
  14. package/dist/lib/config.test.d.ts +0 -2
  15. package/dist/lib/config.test.d.ts.map +0 -1
  16. package/dist/lib/config.test.js +0 -126
  17. package/dist/lib/config.test.js.map +0 -1
  18. package/dist/lib/database.test.d.ts +0 -2
  19. package/dist/lib/database.test.d.ts.map +0 -1
  20. package/dist/lib/database.test.js +0 -180
  21. package/dist/lib/database.test.js.map +0 -1
  22. package/dist/lib/deep-link-payload.test.d.ts +0 -2
  23. package/dist/lib/deep-link-payload.test.d.ts.map +0 -1
  24. package/dist/lib/deep-link-payload.test.js +0 -202
  25. package/dist/lib/deep-link-payload.test.js.map +0 -1
  26. package/dist/lib/event-emitter.test.d.ts +0 -2
  27. package/dist/lib/event-emitter.test.d.ts.map +0 -1
  28. package/dist/lib/event-emitter.test.js +0 -162
  29. package/dist/lib/event-emitter.test.js.map +0 -1
  30. package/dist/lib/fingerprint.test.d.ts +0 -2
  31. package/dist/lib/fingerprint.test.d.ts.map +0 -1
  32. package/dist/lib/fingerprint.test.js +0 -750
  33. package/dist/lib/fingerprint.test.js.map +0 -1
  34. package/dist/lib/launchpad.test.d.ts +0 -2
  35. package/dist/lib/launchpad.test.d.ts.map +0 -1
  36. package/dist/lib/launchpad.test.js +0 -368
  37. package/dist/lib/launchpad.test.js.map +0 -1
  38. package/dist/lib/link-lookup.test.d.ts +0 -2
  39. package/dist/lib/link-lookup.test.d.ts.map +0 -1
  40. package/dist/lib/link-lookup.test.js +0 -61
  41. package/dist/lib/link-lookup.test.js.map +0 -1
  42. package/dist/lib/link-resolution-cache.test.d.ts +0 -2
  43. package/dist/lib/link-resolution-cache.test.d.ts.map +0 -1
  44. package/dist/lib/link-resolution-cache.test.js +0 -45
  45. package/dist/lib/link-resolution-cache.test.js.map +0 -1
  46. package/dist/lib/link-safety.test.d.ts +0 -2
  47. package/dist/lib/link-safety.test.d.ts.map +0 -1
  48. package/dist/lib/link-safety.test.js +0 -211
  49. package/dist/lib/link-safety.test.js.map +0 -1
  50. package/dist/lib/not-found-page.test.d.ts +0 -2
  51. package/dist/lib/not-found-page.test.d.ts.map +0 -1
  52. package/dist/lib/not-found-page.test.js +0 -151
  53. package/dist/lib/not-found-page.test.js.map +0 -1
  54. package/dist/lib/portable/cli.test.d.ts +0 -2
  55. package/dist/lib/portable/cli.test.d.ts.map +0 -1
  56. package/dist/lib/portable/cli.test.js +0 -98
  57. package/dist/lib/portable/cli.test.js.map +0 -1
  58. package/dist/lib/portable/portable.integration.test.d.ts +0 -2
  59. package/dist/lib/portable/portable.integration.test.d.ts.map +0 -1
  60. package/dist/lib/portable/portable.integration.test.js +0 -139
  61. package/dist/lib/portable/portable.integration.test.js.map +0 -1
  62. package/dist/lib/portable/registry.schema.test.d.ts +0 -2
  63. package/dist/lib/portable/registry.schema.test.d.ts.map +0 -1
  64. package/dist/lib/portable/registry.schema.test.js +0 -59
  65. package/dist/lib/portable/registry.schema.test.js.map +0 -1
  66. package/dist/lib/scanner-detection.test.d.ts +0 -2
  67. package/dist/lib/scanner-detection.test.d.ts.map +0 -1
  68. package/dist/lib/scanner-detection.test.js +0 -124
  69. package/dist/lib/scanner-detection.test.js.map +0 -1
  70. package/dist/lib/schema-guard.test.d.ts +0 -2
  71. package/dist/lib/schema-guard.test.d.ts.map +0 -1
  72. package/dist/lib/schema-guard.test.js +0 -83
  73. package/dist/lib/schema-guard.test.js.map +0 -1
  74. package/dist/lib/utils.test.d.ts +0 -2
  75. package/dist/lib/utils.test.d.ts.map +0 -1
  76. package/dist/lib/utils.test.js +0 -261
  77. package/dist/lib/utils.test.js.map +0 -1
  78. package/dist/lib/webhook.test.d.ts +0 -2
  79. package/dist/lib/webhook.test.d.ts.map +0 -1
  80. package/dist/lib/webhook.test.js +0 -340
  81. package/dist/lib/webhook.test.js.map +0 -1
  82. package/dist/routes/health.test.d.ts +0 -2
  83. package/dist/routes/health.test.d.ts.map +0 -1
  84. package/dist/routes/health.test.js +0 -82
  85. package/dist/routes/health.test.js.map +0 -1
  86. package/dist/routes/preview.test.d.ts +0 -2
  87. package/dist/routes/preview.test.d.ts.map +0 -1
  88. package/dist/routes/preview.test.js +0 -111
  89. package/dist/routes/preview.test.js.map +0 -1
  90. package/dist/routes/qr.test.d.ts +0 -2
  91. package/dist/routes/qr.test.d.ts.map +0 -1
  92. package/dist/routes/qr.test.js +0 -67
  93. package/dist/routes/qr.test.js.map +0 -1
  94. package/dist/routes/redirect.click-event.test.d.ts +0 -2
  95. package/dist/routes/redirect.click-event.test.d.ts.map +0 -1
  96. package/dist/routes/redirect.click-event.test.js +0 -85
  97. package/dist/routes/redirect.click-event.test.js.map +0 -1
  98. package/dist/routes/redirect.host-scope.integration.test.d.ts +0 -2
  99. package/dist/routes/redirect.host-scope.integration.test.d.ts.map +0 -1
  100. package/dist/routes/redirect.host-scope.integration.test.js +0 -105
  101. package/dist/routes/redirect.host-scope.integration.test.js.map +0 -1
  102. package/dist/routes/redirect.interstitial.test.d.ts +0 -2
  103. package/dist/routes/redirect.interstitial.test.d.ts.map +0 -1
  104. package/dist/routes/redirect.interstitial.test.js +0 -128
  105. package/dist/routes/redirect.interstitial.test.js.map +0 -1
  106. package/dist/routes/redirect.launchpad.test.d.ts +0 -2
  107. package/dist/routes/redirect.launchpad.test.d.ts.map +0 -1
  108. package/dist/routes/redirect.launchpad.test.js +0 -515
  109. package/dist/routes/redirect.launchpad.test.js.map +0 -1
  110. package/dist/routes/redirect.no-web-destination.test.d.ts +0 -2
  111. package/dist/routes/redirect.no-web-destination.test.d.ts.map +0 -1
  112. package/dist/routes/redirect.no-web-destination.test.js +0 -176
  113. package/dist/routes/redirect.no-web-destination.test.js.map +0 -1
  114. package/dist/routes/redirect.not-found.test.d.ts +0 -2
  115. package/dist/routes/redirect.not-found.test.d.ts.map +0 -1
  116. package/dist/routes/redirect.not-found.test.js +0 -280
  117. package/dist/routes/redirect.not-found.test.js.map +0 -1
  118. package/dist/routes/redirect.safety.test.d.ts +0 -2
  119. package/dist/routes/redirect.safety.test.d.ts.map +0 -1
  120. package/dist/routes/redirect.safety.test.js +0 -284
  121. package/dist/routes/redirect.safety.test.js.map +0 -1
  122. package/dist/routes/redirect.store-url.test.d.ts +0 -2
  123. package/dist/routes/redirect.store-url.test.d.ts.map +0 -1
  124. package/dist/routes/redirect.store-url.test.js +0 -239
  125. package/dist/routes/redirect.store-url.test.js.map +0 -1
  126. package/dist/routes/redirect.test.d.ts +0 -2
  127. package/dist/routes/redirect.test.d.ts.map +0 -1
  128. package/dist/routes/redirect.test.js +0 -158
  129. package/dist/routes/redirect.test.js.map +0 -1
  130. package/dist/routes/redirect.web-link.test.d.ts +0 -2
  131. package/dist/routes/redirect.web-link.test.d.ts.map +0 -1
  132. package/dist/routes/redirect.web-link.test.js +0 -138
  133. package/dist/routes/redirect.web-link.test.js.map +0 -1
  134. package/dist/routes/sdk-cache-bypass.test.d.ts +0 -2
  135. package/dist/routes/sdk-cache-bypass.test.d.ts.map +0 -1
  136. package/dist/routes/sdk-cache-bypass.test.js +0 -175
  137. package/dist/routes/sdk-cache-bypass.test.js.map +0 -1
  138. package/dist/routes/sdk.device-values.integration.test.d.ts +0 -2
  139. package/dist/routes/sdk.device-values.integration.test.d.ts.map +0 -1
  140. package/dist/routes/sdk.device-values.integration.test.js +0 -132
  141. package/dist/routes/sdk.device-values.integration.test.js.map +0 -1
  142. package/dist/routes/sdk.event.test.d.ts +0 -2
  143. package/dist/routes/sdk.event.test.d.ts.map +0 -1
  144. package/dist/routes/sdk.event.test.js +0 -284
  145. package/dist/routes/sdk.event.test.js.map +0 -1
  146. package/dist/routes/sdk.install-certainty.integration.test.d.ts +0 -2
  147. package/dist/routes/sdk.install-certainty.integration.test.d.ts.map +0 -1
  148. package/dist/routes/sdk.install-certainty.integration.test.js +0 -104
  149. package/dist/routes/sdk.install-certainty.integration.test.js.map +0 -1
  150. package/dist/routes/sdk.install-live-links.integration.test.d.ts +0 -2
  151. package/dist/routes/sdk.install-live-links.integration.test.d.ts.map +0 -1
  152. package/dist/routes/sdk.install-live-links.integration.test.js +0 -92
  153. package/dist/routes/sdk.install-live-links.integration.test.js.map +0 -1
  154. package/dist/routes/sdk.install-referrer.integration.test.d.ts +0 -2
  155. package/dist/routes/sdk.install-referrer.integration.test.d.ts.map +0 -1
  156. package/dist/routes/sdk.install-referrer.integration.test.js +0 -187
  157. package/dist/routes/sdk.install-referrer.integration.test.js.map +0 -1
  158. package/dist/routes/sdk.install-window-once.integration.test.d.ts +0 -2
  159. package/dist/routes/sdk.install-window-once.integration.test.d.ts.map +0 -1
  160. package/dist/routes/sdk.install-window-once.integration.test.js +0 -147
  161. package/dist/routes/sdk.install-window-once.integration.test.js.map +0 -1
  162. package/dist/routes/sdk.install.test.d.ts +0 -2
  163. package/dist/routes/sdk.install.test.d.ts.map +0 -1
  164. package/dist/routes/sdk.install.test.js +0 -99
  165. package/dist/routes/sdk.install.test.js.map +0 -1
  166. package/dist/routes/sdk.resolve-click.test.d.ts +0 -2
  167. package/dist/routes/sdk.resolve-click.test.d.ts.map +0 -1
  168. package/dist/routes/sdk.resolve-click.test.js +0 -79
  169. package/dist/routes/sdk.resolve-click.test.js.map +0 -1
  170. package/dist/routes/sdk.resolve-scope.test.d.ts +0 -2
  171. package/dist/routes/sdk.resolve-scope.test.d.ts.map +0 -1
  172. package/dist/routes/sdk.resolve-scope.test.js +0 -105
  173. package/dist/routes/sdk.resolve-scope.test.js.map +0 -1
@@ -1,158 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { isIOSInAppBrowser, isAndroidInAppBrowser, pickMobileFallbackUrl, } from './redirect.js';
3
- // Real-world UA strings (truncated where helpful) for use across test cases.
4
- const UA = {
5
- // Regular browsers — should NOT be detected as in-app
6
- iosSafari: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Mobile/15E148 Safari/604.1',
7
- iosChrome: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) CriOS/123.0.6312.52 Mobile/15E148 Safari/604.1',
8
- androidChrome: 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36',
9
- androidFirefox: 'Mozilla/5.0 (Android 14; Mobile; rv:125.0) Gecko/125.0 Firefox/125.0',
10
- // iOS in-app browsers
11
- iosGmail: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 GSA/322.0.616052181 Safari/604.1',
12
- iosFacebook: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 [FBAN/FBIOS;FBAV/450.0.0.0]',
13
- iosInstagram: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Instagram 320.0.0.0',
14
- iosOutlook: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Outlook-iOS/2.0',
15
- iosTwitter: 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_4 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 Twitter for iPhone/10.0',
16
- // Android in-app browsers
17
- androidWebview: 'Mozilla/5.0 (Linux; Android 14; Pixel 8; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/124.0.0.0 Mobile Safari/537.36',
18
- androidFacebook: 'Mozilla/5.0 (Linux; Android 14; Pixel 8; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/124.0.0.0 Mobile Safari/537.36 [FB_IAB/FB4A;FBAV/450.0.0.0]',
19
- androidInstagram: 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 Instagram 320.0.0.0',
20
- androidLine: 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 Line/13.0.0',
21
- androidWhatsapp: 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Mobile Safari/537.36 WhatsApp/2.24.0',
22
- };
23
- const URLS = {
24
- iosStore: 'https://apps.apple.com/app/example/id123',
25
- androidStore: 'https://play.google.com/store/apps/details?id=com.example',
26
- webFallback: 'https://example.com/landing',
27
- };
28
- describe('isIOSInAppBrowser', () => {
29
- it('detects Gmail (GSA token)', () => {
30
- expect(isIOSInAppBrowser(UA.iosGmail)).toBe(true);
31
- });
32
- it('detects Facebook (FBAN/FBAV)', () => {
33
- expect(isIOSInAppBrowser(UA.iosFacebook)).toBe(true);
34
- });
35
- it('detects Instagram', () => {
36
- expect(isIOSInAppBrowser(UA.iosInstagram)).toBe(true);
37
- });
38
- it('detects Outlook', () => {
39
- expect(isIOSInAppBrowser(UA.iosOutlook)).toBe(true);
40
- });
41
- it('detects Twitter', () => {
42
- expect(isIOSInAppBrowser(UA.iosTwitter)).toBe(true);
43
- });
44
- it('does not flag Safari as in-app', () => {
45
- expect(isIOSInAppBrowser(UA.iosSafari)).toBe(false);
46
- });
47
- it('does not flag Chrome on iOS as in-app', () => {
48
- expect(isIOSInAppBrowser(UA.iosChrome)).toBe(false);
49
- });
50
- });
51
- describe('isAndroidInAppBrowser', () => {
52
- it('detects generic Android WebView via wv) marker', () => {
53
- expect(isAndroidInAppBrowser(UA.androidWebview)).toBe(true);
54
- });
55
- it('detects Facebook (FB_IAB/FBAN/FBAV)', () => {
56
- expect(isAndroidInAppBrowser(UA.androidFacebook)).toBe(true);
57
- });
58
- it('detects Instagram', () => {
59
- expect(isAndroidInAppBrowser(UA.androidInstagram)).toBe(true);
60
- });
61
- it('detects Line', () => {
62
- expect(isAndroidInAppBrowser(UA.androidLine)).toBe(true);
63
- });
64
- it('detects WhatsApp', () => {
65
- expect(isAndroidInAppBrowser(UA.androidWhatsapp)).toBe(true);
66
- });
67
- it('does not flag Chrome as in-app', () => {
68
- expect(isAndroidInAppBrowser(UA.androidChrome)).toBe(false);
69
- });
70
- it('does not flag Firefox as in-app', () => {
71
- expect(isAndroidInAppBrowser(UA.androidFirefox)).toBe(false);
72
- });
73
- });
74
- describe('pickMobileFallbackUrl — iOS regular browser (Safari/Chrome)', () => {
75
- it('prefers iOS store URL over web fallback', () => {
76
- const r = pickMobileFallbackUrl('ios', UA.iosSafari, URLS.iosStore, URLS.androidStore, URLS.webFallback);
77
- expect(r).toEqual({ url: URLS.iosStore, reason: 'ios_app_store_url' });
78
- });
79
- it('falls back to web fallback when iOS store URL is absent', () => {
80
- const r = pickMobileFallbackUrl('ios', UA.iosSafari, null, URLS.androidStore, URLS.webFallback);
81
- expect(r).toEqual({ url: URLS.webFallback, reason: 'web_fallback_url' });
82
- });
83
- it('uses iOS store URL when web fallback is absent', () => {
84
- const r = pickMobileFallbackUrl('ios', UA.iosSafari, URLS.iosStore, URLS.androidStore, null);
85
- expect(r).toEqual({ url: URLS.iosStore, reason: 'ios_app_store_url' });
86
- });
87
- it('returns null when both iOS store URL and web fallback are absent', () => {
88
- expect(pickMobileFallbackUrl('ios', UA.iosSafari, null, URLS.androidStore, null)).toBeNull();
89
- });
90
- });
91
- describe('pickMobileFallbackUrl — iOS in-app browser (Gmail/FB/Instagram/etc.)', () => {
92
- it('prefers web fallback over iOS store URL', () => {
93
- const r = pickMobileFallbackUrl('ios', UA.iosGmail, URLS.iosStore, URLS.androidStore, URLS.webFallback);
94
- expect(r).toEqual({ url: URLS.webFallback, reason: 'web_fallback_url' });
95
- });
96
- it('falls back to iOS store URL when web fallback is absent', () => {
97
- const r = pickMobileFallbackUrl('ios', UA.iosGmail, URLS.iosStore, URLS.androidStore, null);
98
- expect(r).toEqual({ url: URLS.iosStore, reason: 'ios_app_store_url' });
99
- });
100
- it('returns null when both iOS store URL and web fallback are absent', () => {
101
- expect(pickMobileFallbackUrl('ios', UA.iosGmail, null, URLS.androidStore, null)).toBeNull();
102
- });
103
- });
104
- describe('pickMobileFallbackUrl — Android regular browser (Chrome/Firefox)', () => {
105
- it('prefers Android store URL over web fallback', () => {
106
- const r = pickMobileFallbackUrl('android', UA.androidChrome, URLS.iosStore, URLS.androidStore, URLS.webFallback);
107
- expect(r).toEqual({ url: URLS.androidStore, reason: 'android_app_store_url' });
108
- });
109
- it('falls back to web fallback when Android store URL is absent', () => {
110
- const r = pickMobileFallbackUrl('android', UA.androidChrome, URLS.iosStore, null, URLS.webFallback);
111
- expect(r).toEqual({ url: URLS.webFallback, reason: 'web_fallback_url' });
112
- });
113
- it('uses Android store URL when web fallback is absent', () => {
114
- const r = pickMobileFallbackUrl('android', UA.androidChrome, URLS.iosStore, URLS.androidStore, null);
115
- expect(r).toEqual({ url: URLS.androidStore, reason: 'android_app_store_url' });
116
- });
117
- it('returns null when both Android store URL and web fallback are absent', () => {
118
- expect(pickMobileFallbackUrl('android', UA.androidChrome, URLS.iosStore, null, null)).toBeNull();
119
- });
120
- });
121
- describe('pickMobileFallbackUrl — Android in-app browser (FB/Instagram/Line/WebView)', () => {
122
- it('prefers web fallback over Android store URL', () => {
123
- const r = pickMobileFallbackUrl('android', UA.androidFacebook, URLS.iosStore, URLS.androidStore, URLS.webFallback);
124
- expect(r).toEqual({ url: URLS.webFallback, reason: 'web_fallback_url' });
125
- });
126
- it('detects WebView via wv) marker and prefers web fallback', () => {
127
- const r = pickMobileFallbackUrl('android', UA.androidWebview, URLS.iosStore, URLS.androidStore, URLS.webFallback);
128
- expect(r).toEqual({ url: URLS.webFallback, reason: 'web_fallback_url' });
129
- });
130
- it('falls back to Android store URL when web fallback is absent', () => {
131
- const r = pickMobileFallbackUrl('android', UA.androidFacebook, URLS.iosStore, URLS.androidStore, null);
132
- expect(r).toEqual({ url: URLS.androidStore, reason: 'android_app_store_url' });
133
- });
134
- });
135
- describe('pickMobileFallbackUrl — reporter scenario regression test', () => {
136
- // Reproduces a reported regression: a link with iOS, Android and web fallback
137
- // URLs served the web fallback to mobile visitors, who expect the App/Play Store.
138
- it('iOS Safari → iOS App Store (was: web fallback)', () => {
139
- const r = pickMobileFallbackUrl('ios', UA.iosSafari, URLS.iosStore, URLS.androidStore, URLS.webFallback);
140
- expect(r?.url).toBe(URLS.iosStore);
141
- expect(r?.reason).toBe('ios_app_store_url');
142
- });
143
- it('Android Chrome → Play Store (was: web fallback)', () => {
144
- const r = pickMobileFallbackUrl('android', UA.androidChrome, URLS.iosStore, URLS.androidStore, URLS.webFallback);
145
- expect(r?.url).toBe(URLS.androidStore);
146
- expect(r?.reason).toBe('android_app_store_url');
147
- });
148
- // And the email-marketing flow that the prior fix protected stays correct:
149
- it('iOS Gmail in-app → web fallback (preserves UL second-chance)', () => {
150
- const r = pickMobileFallbackUrl('ios', UA.iosGmail, URLS.iosStore, URLS.androidStore, URLS.webFallback);
151
- expect(r?.url).toBe(URLS.webFallback);
152
- });
153
- it('Android Facebook in-app → web fallback (preserves UL second-chance)', () => {
154
- const r = pickMobileFallbackUrl('android', UA.androidFacebook, URLS.iosStore, URLS.androidStore, URLS.webFallback);
155
- expect(r?.url).toBe(URLS.webFallback);
156
- });
157
- });
158
- //# sourceMappingURL=redirect.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redirect.test.js","sourceRoot":"","sources":["../../src/routes/redirect.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAC9C,OAAO,EACL,iBAAiB,EACjB,qBAAqB,EACrB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB,6EAA6E;AAC7E,MAAM,EAAE,GAAG;IACT,sDAAsD;IACtD,SAAS,EACP,yIAAyI;IAC3I,SAAS,EACP,gJAAgJ;IAClJ,aAAa,EACX,uHAAuH;IACzH,cAAc,EACZ,sEAAsE;IAExE,sBAAsB;IACtB,QAAQ,EACN,gJAAgJ;IAClJ,WAAW,EACT,2IAA2I;IAC7I,YAAY,EACV,mIAAmI;IACrI,UAAU,EACR,+HAA+H;IACjI,UAAU,EACR,uIAAuI;IAEzI,0BAA0B;IAC1B,cAAc,EACZ,uIAAuI;IACzI,eAAe,EACb,oKAAoK;IACtK,gBAAgB,EACd,2IAA2I;IAC7I,WAAW,EACT,mIAAmI;IACrI,eAAe,EACb,uIAAuI;CAC1I,CAAC;AAEF,MAAM,IAAI,GAAG;IACX,QAAQ,EAAE,0CAA0C;IACpD,YAAY,EAAE,2DAA2D;IACzE,WAAW,EAAE,6BAA6B;CAC3C,CAAC;AAEF,QAAQ,CAAC,mBAAmB,EAAE,GAAG,EAAE;IACjC,EAAE,CAAC,2BAA2B,EAAE,GAAG,EAAE;QACnC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,8BAA8B,EAAE,GAAG,EAAE;QACtC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACvD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;QACzB,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,uCAAuC,EAAE,GAAG,EAAE;QAC/C,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IACtD,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,uBAAuB,EAAE,GAAG,EAAE;IACrC,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,qCAAqC,EAAE,GAAG,EAAE;QAC7C,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;QAC3B,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,gBAAgB,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,cAAc,EAAE,GAAG,EAAE;QACtB,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC3D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,kBAAkB,EAAE,GAAG,EAAE;QAC1B,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gCAAgC,EAAE,GAAG,EAAE;QACxC,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9D,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iCAAiC,EAAE,GAAG,EAAE;QACzC,MAAM,CAAC,qBAAqB,CAAC,EAAE,CAAC,cAAc,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC/D,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,6DAA6D,EAAE,GAAG,EAAE;IAC3E,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACzG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAChG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC7F,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC/F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,sEAAsE,EAAE,GAAG,EAAE;IACpF,EAAE,CAAC,yCAAyC,EAAE,GAAG,EAAE;QACjD,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACxG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QAC5F,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,QAAQ,EAAE,MAAM,EAAE,mBAAmB,EAAE,CAAC,CAAC;IACzE,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,kEAAkE,EAAE,GAAG,EAAE;QAC1E,MAAM,CAAC,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IAC9F,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,kEAAkE,EAAE,GAAG,EAAE;IAChF,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACjH,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACpG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,oDAAoD,EAAE,GAAG,EAAE;QAC5D,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACrG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,sEAAsE,EAAE,GAAG,EAAE;QAC9E,MAAM,CAAC,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACnG,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,4EAA4E,EAAE,GAAG,EAAE;IAC1F,EAAE,CAAC,6CAA6C,EAAE,GAAG,EAAE;QACrD,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnH,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,yDAAyD,EAAE,GAAG,EAAE;QACjE,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QAClH,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,kBAAkB,EAAE,CAAC,CAAC;IAC3E,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,6DAA6D,EAAE,GAAG,EAAE;QACrE,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,CAAC;QACvG,MAAM,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,YAAY,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC;IACjF,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,QAAQ,CAAC,2DAA2D,EAAE,GAAG,EAAE;IACzE,8EAA8E;IAC9E,kFAAkF;IAClF,EAAE,CAAC,gDAAgD,EAAE,GAAG,EAAE;QACxD,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACzG,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,mBAAmB,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,iDAAiD,EAAE,GAAG,EAAE;QACzD,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,aAAa,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACjH,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACvC,MAAM,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IACH,2EAA2E;IAC3E,EAAE,CAAC,8DAA8D,EAAE,GAAG,EAAE;QACtE,MAAM,CAAC,GAAG,qBAAqB,CAAC,KAAK,EAAE,EAAE,CAAC,QAAQ,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACxG,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IACH,EAAE,CAAC,qEAAqE,EAAE,GAAG,EAAE;QAC7E,MAAM,CAAC,GAAG,qBAAqB,CAAC,SAAS,EAAE,EAAE,CAAC,eAAe,EAAE,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,YAAY,EAAE,IAAI,CAAC,WAAW,CAAC,CAAC;QACnH,MAAM,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=redirect.web-link.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redirect.web-link.test.d.ts","sourceRoot":"","sources":["../../src/routes/redirect.web-link.test.ts"],"names":[],"mappings":""}
@@ -1,138 +0,0 @@
1
- /**
2
- * On a host the deployment reserves for web links (`isWebLinkRequest`), every
3
- * link opens the website on every device: a plain 302 to the destination
4
- * desktop gets, never the Launchpad page, the scheme interstitial or a store.
5
- * Follows redirect.launchpad.test.ts.
6
- */
7
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
8
- import Fastify from 'fastify';
9
- import { redirectRoutes } from './redirect.js';
10
- const query = vi.fn();
11
- vi.mock('../lib/database.js', () => ({
12
- db: {
13
- query: (...args) => query(...args),
14
- },
15
- }));
16
- const DESKTOP_UA = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Safari/537.36';
17
- const IPHONE_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.0 Mobile/15E148 Safari/604.1';
18
- const ANDROID_UA = 'Mozilla/5.0 (Linux; Android 14; Pixel 8) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0 Mobile Safari/537.36';
19
- const FB_IOS_UA = 'Mozilla/5.0 (iPhone; CPU iPhone OS 17_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 [FBAN/FBIOS;FBAV/450.0.0.0.0]';
20
- const WEB_HOST = 'links.example';
21
- /** The deployment's rule: one host is for web links. */
22
- const options = {
23
- isWebLinkRequest: (request) => request.headers.host === WEB_HOST,
24
- };
25
- /** Launchpad page mode: without the flag, a mobile visitor to an app-less link gets the page. */
26
- const PAGE_MODE = { launchpad: { mobile: 'page' } };
27
- function linkRow(overrides = {}) {
28
- return {
29
- id: '00000000-0000-0000-0000-0000000000aa',
30
- short_code: 'abc123',
31
- title: null,
32
- description: null,
33
- og_title: null,
34
- og_description: null,
35
- og_image_url: null,
36
- original_url: 'https://example.com/podcast',
37
- web_fallback_url: null,
38
- ios_app_store_url: null,
39
- android_app_store_url: null,
40
- ios_universal_link: null,
41
- android_app_link: null,
42
- app_scheme: null,
43
- deep_link_path: null,
44
- launchpad_mode: 'inherit',
45
- is_active: true,
46
- warn_at: null,
47
- owner_suspended_at: null,
48
- expires_at: null,
49
- targeting_rules: null,
50
- template_settings: null,
51
- org_settings: PAGE_MODE,
52
- utm_parameters: null,
53
- deep_link_parameters: null,
54
- append_click_id: false,
55
- ...overrides,
56
- };
57
- }
58
- function mockDb(row) {
59
- query.mockReset();
60
- query.mockImplementation(async (sql) => {
61
- if (/information_schema\.columns/i.test(sql)) {
62
- return { rows: [{ '?column?': 1 }], rowCount: 1 };
63
- }
64
- if (/^\s*SELECT\s+l\.\*/i.test(sql) || /FROM links l/i.test(sql)) {
65
- return { rows: row ? [row] : [], rowCount: row ? 1 : 0 };
66
- }
67
- return { rows: [], rowCount: 0 };
68
- });
69
- }
70
- const get = (app, ua, host = WEB_HOST) => app.inject({ method: 'GET', url: '/abc123', headers: { 'user-agent': ua, host } });
71
- let app;
72
- beforeEach(async () => {
73
- app = Fastify();
74
- await app.register(redirectRoutes, options);
75
- await app.ready();
76
- });
77
- afterEach(async () => {
78
- await new Promise((r) => setImmediate(r));
79
- await app.close();
80
- });
81
- describe('web-link host', () => {
82
- it('302s every device to the web destination, even with the workspace in Launchpad page mode', async () => {
83
- mockDb(linkRow());
84
- for (const ua of [IPHONE_UA, ANDROID_UA, FB_IOS_UA, DESKTOP_UA]) {
85
- const res = await get(app, ua);
86
- expect(res.statusCode, ua).toBe(302);
87
- expect(res.headers.location, ua).toBe('https://example.com/podcast');
88
- }
89
- });
90
- it('ignores app destinations the link or workspace carries: no store, scheme or Universal Link', async () => {
91
- mockDb(linkRow({
92
- ios_app_store_url: 'https://apps.apple.com/app/id1',
93
- android_app_store_url: 'https://play.google.com/store/apps/details?id=demo',
94
- ios_universal_link: 'https://go.example/app/1',
95
- android_app_link: 'https://go.example/app/1',
96
- app_scheme: 'demo',
97
- deep_link_path: '/p/1',
98
- }));
99
- for (const ua of [IPHONE_UA, ANDROID_UA]) {
100
- const res = await get(app, ua);
101
- expect(res.statusCode, ua).toBe(302);
102
- expect(res.headers.location, ua).toBe('https://example.com/podcast');
103
- }
104
- });
105
- it('uses the same destination desktop does: web fallback first, with UTM parameters', async () => {
106
- mockDb(linkRow({
107
- web_fallback_url: 'https://example.com/landing',
108
- utm_parameters: { source: 'email', campaign: 'oct' },
109
- }));
110
- const res = await get(app, IPHONE_UA);
111
- expect(res.statusCode).toBe(302);
112
- const location = new URL(res.headers.location);
113
- expect(location.origin + location.pathname).toBe('https://example.com/landing');
114
- expect(location.searchParams.get('utm_source')).toBe('email');
115
- expect(location.searchParams.get('utm_campaign')).toBe('oct');
116
- });
117
- it('leaves every other host alone: the same link gets the Launchpad page on an app-link host', async () => {
118
- mockDb(linkRow({ ios_app_store_url: 'https://apps.apple.com/app/id1' }));
119
- const res = await get(app, IPHONE_UA, 'go.example');
120
- expect(res.statusCode).toBe(200);
121
- expect(res.headers['content-type']).toMatch(/text\/html/);
122
- });
123
- it('treats a hook that throws as an app-link host rather than failing the click', async () => {
124
- await app.close();
125
- app = Fastify();
126
- await app.register(redirectRoutes, {
127
- isWebLinkRequest: () => {
128
- throw new Error('lookup failed');
129
- },
130
- });
131
- await app.ready();
132
- mockDb(linkRow({ ios_app_store_url: 'https://apps.apple.com/app/id1' }));
133
- const res = await get(app, IPHONE_UA);
134
- expect(res.statusCode).toBe(200);
135
- expect(res.headers['content-type']).toMatch(/text\/html/);
136
- });
137
- });
138
- //# sourceMappingURL=redirect.web-link.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"redirect.web-link.test.js","sourceRoot":"","sources":["../../src/routes/redirect.web-link.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=sdk-cache-bypass.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sdk-cache-bypass.test.d.ts","sourceRoot":"","sources":["../../src/routes/sdk-cache-bypass.test.ts"],"names":[],"mappings":""}
@@ -1,175 +0,0 @@
1
- /**
2
- * Regression test for the owner-restriction bypass via the SDK resolve endpoint.
3
- *
4
- * The redirect and `/api/sdk/v1/resolve/:shortCode` write the SAME Redis key. The SDK
5
- * query used to omit the `organizations` join, so the row it cached carried no
6
- * `owner_suspended_at`. The redirect then read `undefined`, its gate treated that as
7
- * "not restricted", and a restricted owner's link redirected for the rest of the TTL.
8
- *
9
- * Both plugins share one fake Redis here, because sharing the cache is the mechanism —
10
- * testing them in isolation cannot reproduce it.
11
- */
12
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
13
- import Fastify from 'fastify';
14
- const query = vi.fn();
15
- vi.mock('../lib/database.js', () => ({ db: { query: (...a) => query(...a) } }));
16
- import { redirectRoutes } from './redirect.js';
17
- import { sdkRoutes } from './sdk.js';
18
- /** Minimal shared Redis stand-in — get/set/setex/del over one Map. */
19
- function fakeRedis() {
20
- const store = new Map();
21
- return {
22
- store,
23
- get: async (k) => store.get(k) ?? null,
24
- set: async (k, v) => void store.set(k, v),
25
- setex: async (k, _ttl, v) => void store.set(k, v),
26
- del: async (k) => void store.delete(k),
27
- };
28
- }
29
- const RESTRICTED = '2026-08-10T00:00:00Z';
30
- function row(overrides = {}) {
31
- return {
32
- id: '00000000-0000-0000-0000-0000000000aa',
33
- short_code: 'abc123',
34
- organization_id: '00000000-0000-0000-0000-0000000000bb',
35
- original_url: 'https://example.com/landing',
36
- web_fallback_url: null,
37
- deep_link_path: null,
38
- is_active: true,
39
- warn_at: null,
40
- owner_suspended_at: RESTRICTED,
41
- expires_at: null,
42
- targeting_rules: null,
43
- template_settings: null,
44
- org_settings: null,
45
- utm_parameters: null,
46
- append_click_id: false,
47
- ...overrides,
48
- };
49
- }
50
- /**
51
- * Mock the database so the row's shape follows the SELECT, exactly as Postgres would:
52
- * `owner_suspended_at` is only present when the query asked for it. That is what makes
53
- * this a real reproduction rather than a restatement of the fix.
54
- */
55
- function mockDb() {
56
- query.mockReset();
57
- query.mockImplementation(async (sql) => {
58
- if (/information_schema\.columns/i.test(sql))
59
- return { rows: [{ x: 1 }], rowCount: 1 };
60
- if (/FROM links/i.test(sql)) {
61
- // The row's shape follows the SELECT, exactly as Postgres would: a column is
62
- // present only if the query asked for it. That is what makes these real
63
- // reproductions rather than restatements of the fix.
64
- const r = row();
65
- if (!/owner_suspended_at/i.test(sql))
66
- delete r.owner_suspended_at;
67
- if (!/template_settings/i.test(sql))
68
- delete r.template_settings;
69
- if (!/org_settings/i.test(sql))
70
- delete r.org_settings;
71
- return { rows: [r], rowCount: 1 };
72
- }
73
- return { rows: [], rowCount: 0 };
74
- });
75
- }
76
- let redirectApp;
77
- let sdkApp;
78
- let redis;
79
- beforeEach(async () => {
80
- mockDb();
81
- redis = fakeRedis();
82
- redirectApp = Fastify();
83
- redirectApp.decorate('redis', redis);
84
- await redirectApp.register(redirectRoutes);
85
- await redirectApp.ready();
86
- sdkApp = Fastify();
87
- sdkApp.decorate('redis', redis);
88
- await sdkApp.register(sdkRoutes);
89
- await sdkApp.ready();
90
- });
91
- afterEach(async () => {
92
- await new Promise((r) => setImmediate(r));
93
- await redirectApp.close();
94
- await sdkApp.close();
95
- });
96
- describe('owner restriction cannot be bypassed through the SDK cache', () => {
97
- /**
98
- * Asserted as "does not resolve", not as a status code. A restricted owner's link
99
- * now answers 410 with a notice rather than 404, and this file is about the
100
- * bypass, not the wording — pinning the code here would make every future change
101
- * to the blocked response look like a security regression.
102
- */
103
- it('blocks a restricted owner when the redirect populates the cache itself', async () => {
104
- const res = await redirectApp.inject({ method: 'GET', url: '/abc123' });
105
- expect(res.statusCode).not.toBe(302);
106
- expect(res.headers.location).toBeUndefined();
107
- expect(res.body).not.toContain('example.com');
108
- });
109
- it('still blocks after an SDK resolve has primed the same cache key', async () => {
110
- // This is the bypass: prime via the public SDK endpoint, then hit the redirect.
111
- await sdkApp.inject({ method: 'GET', url: '/api/sdk/v1/resolve/abc123' });
112
- expect(redis.store.has('link:abc123')).toBe(true);
113
- const res = await redirectApp.inject({ method: 'GET', url: '/abc123' });
114
- expect(res.statusCode, 'a restricted owner must stay blocked on a cache hit').not.toBe(302);
115
- expect(res.headers.location).toBeUndefined();
116
- });
117
- it('the cached row carries owner_suspended_at whichever path wrote it', async () => {
118
- await sdkApp.inject({ method: 'GET', url: '/api/sdk/v1/resolve/abc123' });
119
- const cached = JSON.parse(redis.store.get('link:abc123'));
120
- // Absent (not merely null) is what made the redirect's gate pass.
121
- expect(Object.prototype.hasOwnProperty.call(cached, 'owner_suspended_at')).toBe(true);
122
- });
123
- it('the SDK endpoint itself refuses to resolve a restricted link', async () => {
124
- // It returns the destination directly, so it must enforce the same policy — that
125
- // is the information the redirect is refusing to disclose.
126
- const res = await sdkApp.inject({ method: 'GET', url: '/api/sdk/v1/resolve/abc123' });
127
- expect(res.statusCode).toBe(404);
128
- expect(res.body).not.toContain('example.com/landing');
129
- });
130
- });
131
- /**
132
- * The same cache-shape divergence, one field over.
133
- *
134
- * The redirect reads `template_settings` and `org_settings` from this shared key for
135
- * its URL fallback chain (link, then template, then workspace). While the SDK query
136
- * omitted them, an SDK resolve left the next redirect unable to see a template-level
137
- * fallback, so a link relying on one silently fell through to `original_url`.
138
- */
139
- describe('the URL fallback chain survives an SDK resolve', () => {
140
- /** No link-level web fallback; the destination lives on the template. */
141
- function templateFallbackRow() {
142
- return {
143
- ...row({ owner_suspended_at: null }),
144
- original_url: 'https://example.com/ORIGINAL',
145
- web_fallback_url: null,
146
- template_settings: { defaultWebFallbackUrl: 'https://cdn.example.com/template-default' },
147
- org_settings: null,
148
- };
149
- }
150
- beforeEach(() => {
151
- query.mockReset();
152
- query.mockImplementation(async (sql) => {
153
- if (/information_schema\.columns/i.test(sql))
154
- return { rows: [{ x: 1 }], rowCount: 1 };
155
- if (/FROM links/i.test(sql)) {
156
- const r = templateFallbackRow();
157
- if (!/owner_suspended_at/i.test(sql))
158
- delete r.owner_suspended_at;
159
- if (!/template_settings/i.test(sql))
160
- delete r.template_settings;
161
- if (!/org_settings/i.test(sql))
162
- delete r.org_settings;
163
- return { rows: [r], rowCount: 1 };
164
- }
165
- return { rows: [], rowCount: 0 };
166
- });
167
- });
168
- it('caches template_settings whichever path writes the key', async () => {
169
- await sdkApp.inject({ method: 'GET', url: '/api/sdk/v1/resolve/abc123' });
170
- const cached = JSON.parse(redis.store.get('link:abc123'));
171
- expect(Object.prototype.hasOwnProperty.call(cached, 'template_settings')).toBe(true);
172
- expect(Object.prototype.hasOwnProperty.call(cached, 'org_settings')).toBe(true);
173
- });
174
- });
175
- //# sourceMappingURL=sdk-cache-bypass.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sdk-cache-bypass.test.js","sourceRoot":"","sources":["../../src/routes/sdk-cache-bypass.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=sdk.device-values.integration.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"sdk.device-values.integration.test.d.ts","sourceRoot":"","sources":["../../src/routes/sdk.device-values.integration.test.ts"],"names":[],"mappings":""}