@drip-apex/sdk 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (246) hide show
  1. package/README.md +5 -0
  2. package/dist/bundle-report.json +584 -226
  3. package/dist/define.cjs +123 -0
  4. package/dist/define.cjs.map +7 -0
  5. package/dist/define.mjs +102 -0
  6. package/dist/define.mjs.map +7 -0
  7. package/dist/drip.cjs +19283 -0
  8. package/dist/drip.cjs.map +7 -0
  9. package/dist/drip.debug.js +1 -1
  10. package/dist/drip.debug.js.map +1 -1
  11. package/dist/drip.heatmap.js +1 -1
  12. package/dist/drip.heatmap.js.map +1 -1
  13. package/dist/drip.js +1 -1
  14. package/dist/drip.js.map +1 -1
  15. package/dist/drip.live.js +1 -1
  16. package/dist/drip.live.js.map +1 -1
  17. package/dist/drip.mjs +19267 -0
  18. package/dist/drip.mjs.map +7 -0
  19. package/dist/drip.replay-recorder.js +2 -0
  20. package/dist/drip.replay-recorder.js.map +1 -0
  21. package/dist/editor.js +147 -142
  22. package/dist/editor.js.map +4 -4
  23. package/dist/flags.cjs +1788 -0
  24. package/dist/flags.cjs.map +7 -0
  25. package/dist/flags.mjs +1765 -0
  26. package/dist/flags.mjs.map +7 -0
  27. package/dist/index.mjs +12 -0
  28. package/dist/index.mjs.map +2 -2
  29. package/dist/metafiles/define.cjs.meta.json +28 -0
  30. package/dist/metafiles/define.mjs.meta.json +32 -0
  31. package/dist/metafiles/drip.cjs.meta.json +3193 -0
  32. package/dist/metafiles/drip.debug.meta.json +2859 -574
  33. package/dist/metafiles/drip.heatmap.meta.json +2732 -460
  34. package/dist/metafiles/drip.live.meta.json +2732 -460
  35. package/dist/metafiles/drip.meta.json +2859 -574
  36. package/dist/metafiles/drip.mjs.meta.json +3235 -0
  37. package/dist/metafiles/drip.replay-recorder.meta.json +82 -0
  38. package/dist/metafiles/editor.meta.json +67 -27
  39. package/dist/metafiles/flags.cjs.meta.json +220 -0
  40. package/dist/metafiles/flags.mjs.meta.json +225 -0
  41. package/dist/metafiles/index.meta.json +2717 -491
  42. package/dist/metafiles/index.mjs.meta.json +14 -4
  43. package/dist/react/index.js +16636 -13533
  44. package/dist/react/index.js.map +4 -4
  45. package/dist/sri.json +20 -15
  46. package/dist/types/activation-runtime.d.ts +91 -0
  47. package/dist/types/analytics-runtime.d.ts +166 -0
  48. package/dist/types/antiflicker.d.ts +9 -3
  49. package/dist/types/assignment-cookie-sync.d.ts +31 -0
  50. package/dist/types/assignment-runtime.d.ts +257 -0
  51. package/dist/types/assignment-store.d.ts +4 -8
  52. package/dist/types/bucket.d.ts +1 -2
  53. package/dist/types/compact-store.d.ts +1 -0
  54. package/dist/types/config-runtime.d.ts +313 -0
  55. package/dist/types/consent-evaluation.d.ts +28 -0
  56. package/dist/types/css.d.ts +5 -3
  57. package/dist/types/debug-loader.d.ts +2 -0
  58. package/dist/types/decide-assignments.d.ts +31 -0
  59. package/dist/types/delivery-timing.d.ts +8 -0
  60. package/dist/types/early-interaction-capture.d.ts +79 -0
  61. package/dist/types/early-reassert.d.ts +32 -0
  62. package/dist/types/edge-runtime.d.ts +11 -0
  63. package/dist/types/editor/api.d.ts +3 -0
  64. package/dist/types/editor/controller.d.ts +3 -1
  65. package/dist/types/editor/publication-result.d.ts +11 -0
  66. package/dist/types/editor/types.d.ts +2 -1
  67. package/dist/types/editor/view-kit.d.ts +1 -1
  68. package/dist/types/endpoint.d.ts +8 -0
  69. package/dist/types/exclusion-groups.d.ts +4 -7
  70. package/dist/types/flags.d.ts +2 -0
  71. package/dist/types/goal-eligibility.d.ts +4 -0
  72. package/dist/types/goals.d.ts +10 -1
  73. package/dist/types/guards.d.ts +7 -7
  74. package/dist/types/handover.d.ts +12 -1
  75. package/dist/types/hash.d.ts +8 -4
  76. package/dist/types/hydration.d.ts +2 -1
  77. package/dist/types/index.d.ts +24 -128
  78. package/dist/types/init-test-helpers.d.ts +48 -0
  79. package/dist/types/inline-bootstrap.d.ts +26 -0
  80. package/dist/types/js.d.ts +3 -1
  81. package/dist/types/money.d.ts +12 -0
  82. package/dist/types/mutate.d.ts +45 -6
  83. package/dist/types/performance.d.ts +2 -0
  84. package/dist/types/persistence-decoders.d.ts +12 -0
  85. package/dist/types/public-api.d.ts +209 -0
  86. package/dist/types/qa-assistant-state.d.ts +34 -0
  87. package/dist/types/react/index.d.ts +28 -3
  88. package/dist/types/reassert-sentinel.d.ts +6 -0
  89. package/dist/types/redirect.d.ts +48 -0
  90. package/dist/types/replay-recorder-entry.d.ts +1 -0
  91. package/dist/types/replay-signal-state.d.ts +6 -0
  92. package/dist/types/replay-signals.d.ts +13 -0
  93. package/dist/types/replay.d.ts +110 -0
  94. package/dist/types/router.d.ts +12 -2
  95. package/dist/types/runtime-state.d.ts +166 -0
  96. package/dist/types/sanitize.d.ts +1 -0
  97. package/dist/types/shadow.d.ts +3 -0
  98. package/dist/types/shopify-cart.d.ts +25 -1
  99. package/dist/types/storefront-vitals.d.ts +24 -0
  100. package/dist/types/targeting-diagnostics.d.ts +1 -0
  101. package/dist/types/targeting.d.ts +16 -2
  102. package/dist/types/track.d.ts +15 -1
  103. package/dist/types/types.d.ts +115 -9
  104. package/dist/types/wait.d.ts +14 -1
  105. package/dist/types/weekday-schedule.d.ts +3 -0
  106. package/package.json +17 -8
  107. package/src/activation-runtime.ts +2737 -0
  108. package/src/analytics-runtime.ts +2175 -0
  109. package/src/antiflicker.test.ts +216 -44
  110. package/src/antiflicker.ts +103 -28
  111. package/src/artifact-concurrency.test.ts +1091 -0
  112. package/src/assignment-cookie-sync.test.ts +202 -0
  113. package/src/assignment-cookie-sync.ts +189 -0
  114. package/src/assignment-runtime.ts +3204 -0
  115. package/src/assignment-store.test.ts +56 -0
  116. package/src/assignment-store.ts +7 -38
  117. package/src/bucket.ts +3 -18
  118. package/src/commerce-analytics-lifecycle.test.ts +75 -15
  119. package/src/commerce-config-lifecycle.test.ts +81 -1
  120. package/src/commerce-price-preserve.test.ts +133 -0
  121. package/src/commerce-price.test.ts +97 -0
  122. package/src/commerce-price.ts +74 -20
  123. package/src/commerce-shipping.test.ts +53 -0
  124. package/src/commerce-shipping.ts +5 -11
  125. package/src/compact-store.ts +15 -0
  126. package/src/config-fetch.test.ts +480 -9
  127. package/src/config-runtime.ts +2071 -0
  128. package/src/consent-evaluation-borlabs.test.ts +41 -0
  129. package/src/consent-evaluation-cookiescript.test.ts +50 -0
  130. package/src/consent-evaluation.ts +151 -0
  131. package/src/css.test.ts +30 -0
  132. package/src/css.ts +120 -6
  133. package/src/cwv.test.ts +60 -77
  134. package/src/debug-loader.test.ts +214 -0
  135. package/src/debug-loader.ts +41 -0
  136. package/src/decide-assignments.test.ts +196 -0
  137. package/src/decide-assignments.ts +204 -0
  138. package/src/delivery-timing.test.ts +104 -0
  139. package/src/delivery-timing.ts +89 -0
  140. package/src/early-interaction-capture.test.ts +451 -0
  141. package/src/early-interaction-capture.ts +230 -0
  142. package/src/early-reassert.test.ts +207 -0
  143. package/src/early-reassert.ts +152 -0
  144. package/src/edge-adoption.test.ts +435 -0
  145. package/src/edge-runtime.ts +30 -0
  146. package/src/editor/api.test.ts +109 -0
  147. package/src/editor/api.ts +34 -3
  148. package/src/editor/controller.test.ts +297 -14
  149. package/src/editor/controller.ts +69 -5
  150. package/src/editor/index.test.ts +2 -0
  151. package/src/editor/index.ts +1 -0
  152. package/src/editor/publication-result.ts +58 -0
  153. package/src/editor/types.ts +10 -1
  154. package/src/editor/view-kit.ts +2 -1
  155. package/src/editor/view.test.ts +108 -0
  156. package/src/editor/view.ts +49 -7
  157. package/src/endpoint.test.ts +15 -0
  158. package/src/endpoint.ts +10 -0
  159. package/src/exclusion-groups.ts +8 -18
  160. package/src/flags.test.ts +88 -1
  161. package/src/flags.ts +29 -29
  162. package/src/global-runtime-reconciler.test.ts +271 -0
  163. package/src/goal-eligibility.test.ts +29 -0
  164. package/src/goal-eligibility.ts +17 -0
  165. package/src/goals.test.ts +144 -1
  166. package/src/goals.ts +97 -18
  167. package/src/guards.test.ts +99 -1
  168. package/src/guards.ts +34 -15
  169. package/src/handover-cache-order.test.ts +6 -3
  170. package/src/handover.test.ts +154 -8
  171. package/src/handover.ts +122 -12
  172. package/src/hash.ts +29 -54
  173. package/src/holdout.test.ts +26 -0
  174. package/src/hydration.test.ts +73 -2
  175. package/src/hydration.ts +18 -9
  176. package/src/index.ts +130 -7287
  177. package/src/init-analytics.test.ts +1694 -0
  178. package/src/init-anti-flicker.test.ts +1211 -0
  179. package/src/init-cart-attributes.test.ts +2003 -0
  180. package/src/init-config-resolution.test.ts +999 -0
  181. package/src/init-consent.test.ts +971 -0
  182. package/src/init-empty.test.ts +11 -5406
  183. package/src/init-integrations.test.ts +846 -0
  184. package/src/init-page-activation.test.ts +5064 -0
  185. package/src/init-qa-loading.test.ts +740 -0
  186. package/src/init-redirects.test.ts +2156 -0
  187. package/src/init-test-helpers.ts +287 -0
  188. package/src/inline-bootstrap.test.ts +184 -0
  189. package/src/inline-bootstrap.ts +73 -0
  190. package/src/js.test.ts +51 -1
  191. package/src/js.ts +86 -2
  192. package/src/money.test.ts +55 -1
  193. package/src/money.ts +104 -2
  194. package/src/money.web-parity.contract.test.ts +85 -0
  195. package/src/mutate.test.ts +474 -10
  196. package/src/mutate.ts +739 -230
  197. package/src/page-trigger.test.ts +218 -8
  198. package/src/performance.ts +10 -0
  199. package/src/persistence-decoders.ts +18 -0
  200. package/src/public-api.ts +1828 -0
  201. package/src/qa-assistant-state.test.ts +249 -3
  202. package/src/qa-assistant-state.ts +146 -6
  203. package/src/qa-assistant-view.test.ts +220 -2
  204. package/src/qa-assistant-view.ts +102 -5
  205. package/src/react/index.test.tsx +37 -0
  206. package/src/react/index.tsx +19 -3
  207. package/src/reassert-sentinel.test.ts +155 -1
  208. package/src/reassert-sentinel.ts +168 -8
  209. package/src/redirect.test.ts +541 -0
  210. package/src/redirect.ts +572 -0
  211. package/src/replay-recorder-entry.ts +115 -0
  212. package/src/replay-signal-state.ts +100 -0
  213. package/src/replay-signals.test.ts +249 -0
  214. package/src/replay-signals.ts +151 -0
  215. package/src/replay.test.ts +764 -0
  216. package/src/replay.ts +514 -0
  217. package/src/router.test.ts +61 -2
  218. package/src/router.ts +50 -12
  219. package/src/runtime-state.ts +507 -0
  220. package/src/runtime.test.ts +174 -7
  221. package/src/runtime.ts +88 -14
  222. package/src/sanitize.test.ts +34 -0
  223. package/src/sanitize.ts +23 -12
  224. package/src/shadow.test.ts +187 -0
  225. package/src/shadow.ts +99 -0
  226. package/src/shopify-cart.test.ts +733 -23
  227. package/src/shopify-cart.ts +402 -49
  228. package/src/storefront-vitals.test.ts +217 -0
  229. package/src/storefront-vitals.ts +206 -0
  230. package/src/surface-signals.ts +6 -0
  231. package/src/targeting-conformance.test.ts +9 -0
  232. package/src/targeting-diagnostics.ts +38 -8
  233. package/src/targeting-parity-corpus.json +559 -0
  234. package/src/targeting-parity-corpus.test.ts +18 -0
  235. package/src/targeting.detailed.test.ts +105 -0
  236. package/src/targeting.test.ts +211 -0
  237. package/src/targeting.ts +88 -207
  238. package/src/track.test.ts +147 -0
  239. package/src/track.ts +125 -26
  240. package/src/types.ts +120 -13
  241. package/src/wait.test.ts +23 -0
  242. package/src/wait.ts +129 -13
  243. package/src/weekday-delivery.test.ts +56 -0
  244. package/src/weekday-schedule-parity-corpus.json +92 -0
  245. package/src/weekday-schedule.test.ts +69 -0
  246. package/src/weekday-schedule.ts +20 -0
@@ -0,0 +1,559 @@
1
+ [
2
+ {
3
+ "name": "wildcard path",
4
+ "url": "https://shop.test/products/serum",
5
+ "targeting": {
6
+ "url": [
7
+ {
8
+ "type": "simple",
9
+ "pattern": "/products/*",
10
+ "include": true
11
+ }
12
+ ]
13
+ },
14
+ "expect": {
15
+ "sdk": true,
16
+ "server": true
17
+ }
18
+ },
19
+ {
20
+ "name": "scheme-less host and path",
21
+ "url": "https://shop.test/products/serum",
22
+ "targeting": {
23
+ "url": [
24
+ {
25
+ "type": "simple",
26
+ "pattern": "shop.test/products/serum",
27
+ "include": true
28
+ }
29
+ ]
30
+ },
31
+ "expect": {
32
+ "sdk": true,
33
+ "server": true
34
+ }
35
+ },
36
+ {
37
+ "name": "query subset ignores extras",
38
+ "url": "https://shop.test/search?q=serum&page=2",
39
+ "targeting": {
40
+ "url": [
41
+ {
42
+ "type": "simple",
43
+ "pattern": "/search?q=serum",
44
+ "include": true
45
+ }
46
+ ]
47
+ },
48
+ "expect": {
49
+ "sdk": true,
50
+ "server": true
51
+ }
52
+ },
53
+ {
54
+ "name": "hash is matched when specified",
55
+ "url": "https://shop.test/pages/about#team",
56
+ "targeting": {
57
+ "url": [
58
+ {
59
+ "type": "simple",
60
+ "pattern": "/pages/about#team",
61
+ "include": true
62
+ }
63
+ ]
64
+ },
65
+ "expect": {
66
+ "sdk": true,
67
+ "server": true
68
+ }
69
+ },
70
+ {
71
+ "name": "contains",
72
+ "url": "https://shop.test/collections/summer-sale",
73
+ "targeting": {
74
+ "url": [
75
+ {
76
+ "type": "simple",
77
+ "matchType": "contains",
78
+ "pattern": "summer-sale",
79
+ "include": true
80
+ }
81
+ ]
82
+ },
83
+ "expect": {
84
+ "sdk": true,
85
+ "server": true
86
+ }
87
+ },
88
+ {
89
+ "name": "legacy escaped contains",
90
+ "url": "https://shop.test/products/red.shirt",
91
+ "targeting": {
92
+ "url": [
93
+ {
94
+ "type": "simple",
95
+ "matchType": "contains",
96
+ "pattern": "red\\.shirt",
97
+ "include": true
98
+ }
99
+ ]
100
+ },
101
+ "expect": {
102
+ "sdk": true,
103
+ "server": true
104
+ }
105
+ },
106
+ {
107
+ "name": "regex recognized from type",
108
+ "url": "https://shop.test/products/123",
109
+ "targeting": {
110
+ "url": [
111
+ {
112
+ "type": "regex",
113
+ "pattern": "^/products/[0-9]+$",
114
+ "include": true
115
+ }
116
+ ]
117
+ },
118
+ "expect": {
119
+ "sdk": true,
120
+ "server": true
121
+ }
122
+ },
123
+ {
124
+ "name": "matchType regex remains simple",
125
+ "url": "https://shop.test/products/123",
126
+ "targeting": {
127
+ "url": [
128
+ {
129
+ "type": "simple",
130
+ "matchType": "regex",
131
+ "pattern": "^/products/[0-9]+$",
132
+ "include": true
133
+ }
134
+ ]
135
+ },
136
+ "expect": {
137
+ "sdk": false,
138
+ "server": false
139
+ }
140
+ },
141
+ {
142
+ "name": "simple matching is case insensitive",
143
+ "url": "https://shop.test/Products/Serum",
144
+ "targeting": {
145
+ "url": [
146
+ {
147
+ "type": "simple",
148
+ "pattern": "/products/serum",
149
+ "include": true
150
+ }
151
+ ]
152
+ },
153
+ "expect": {
154
+ "sdk": true,
155
+ "server": true
156
+ }
157
+ },
158
+ {
159
+ "name": "regex matching is case sensitive",
160
+ "url": "https://shop.test/Products/Serum",
161
+ "targeting": {
162
+ "url": [
163
+ {
164
+ "type": "regex",
165
+ "pattern": "^/products/serum$",
166
+ "include": true
167
+ }
168
+ ]
169
+ },
170
+ "expect": {
171
+ "sdk": false,
172
+ "server": false
173
+ }
174
+ },
175
+ {
176
+ "name": "regex lookahead",
177
+ "url": "https://shop.test/products/serum",
178
+ "targeting": {
179
+ "url": [
180
+ {
181
+ "type": "regex",
182
+ "pattern": "^/products/(?=serum)serum$",
183
+ "include": true
184
+ }
185
+ ]
186
+ },
187
+ "expect": {
188
+ "sdk": true,
189
+ "server": true
190
+ }
191
+ },
192
+ {
193
+ "name": "regex lookbehind",
194
+ "url": "https://shop.test/products/serum",
195
+ "targeting": {
196
+ "url": [
197
+ {
198
+ "type": "regex",
199
+ "pattern": "^/products/(?<=products/)serum$",
200
+ "include": true
201
+ }
202
+ ]
203
+ },
204
+ "expect": {
205
+ "sdk": true,
206
+ "server": true
207
+ }
208
+ },
209
+ {
210
+ "name": "regex backreference",
211
+ "url": "https://shop.test/products/serum/serum",
212
+ "targeting": {
213
+ "url": [
214
+ {
215
+ "type": "regex",
216
+ "pattern": "^/products/(serum)/\\1$",
217
+ "include": true
218
+ }
219
+ ]
220
+ },
221
+ "expect": {
222
+ "sdk": true,
223
+ "server": true
224
+ }
225
+ },
226
+ {
227
+ "name": "quantified backreference is server indeterminate",
228
+ "url": "https://shop.test/aaaa!",
229
+ "targeting": {
230
+ "url": [
231
+ {
232
+ "type": "regex",
233
+ "pattern": "^(a+)\\1+$",
234
+ "include": true
235
+ }
236
+ ]
237
+ },
238
+ "expect": {
239
+ "sdk": false,
240
+ "server": true,
241
+ "serverIndeterminate": true
242
+ }
243
+ },
244
+ {
245
+ "name": "catastrophic regex is server indeterminate",
246
+ "url": "https://shop.test/a!",
247
+ "targeting": {
248
+ "url": [
249
+ {
250
+ "type": "regex",
251
+ "pattern": "^(a+)+$",
252
+ "include": true
253
+ }
254
+ ]
255
+ },
256
+ "expect": {
257
+ "sdk": false,
258
+ "server": true,
259
+ "serverIndeterminate": true
260
+ }
261
+ },
262
+ {
263
+ "name": "invalid regex fails",
264
+ "url": "https://shop.test/products/serum",
265
+ "targeting": {
266
+ "url": [
267
+ {
268
+ "type": "regex",
269
+ "pattern": "[invalid(",
270
+ "include": true
271
+ }
272
+ ]
273
+ },
274
+ "expect": {
275
+ "sdk": false,
276
+ "server": false
277
+ }
278
+ },
279
+ {
280
+ "name": "host agnostic include matching storefront origin",
281
+ "url": "https://shop.test/products/serum",
282
+ "storefrontOrigins": ["https://shop.test"],
283
+ "targeting": {
284
+ "url": [
285
+ {
286
+ "type": "simple",
287
+ "pattern": "/products/*",
288
+ "include": true
289
+ }
290
+ ]
291
+ },
292
+ "expect": {
293
+ "sdk": true,
294
+ "server": true
295
+ }
296
+ },
297
+ {
298
+ "name": "host agnostic include rejects another origin",
299
+ "url": "https://other.test/products/serum",
300
+ "storefrontOrigins": ["https://shop.test"],
301
+ "targeting": {
302
+ "url": [
303
+ {
304
+ "type": "simple",
305
+ "pattern": "/products/*",
306
+ "include": true
307
+ }
308
+ ]
309
+ },
310
+ "expect": {
311
+ "sdk": false,
312
+ "server": false
313
+ }
314
+ },
315
+ {
316
+ "name": "scheme-prefixed rule names host",
317
+ "url": "https://other.test/products/serum",
318
+ "storefrontOrigins": [
319
+ "https://shop.test"
320
+ ],
321
+ "targeting": {
322
+ "url": [
323
+ {
324
+ "type": "simple",
325
+ "pattern": "https://other.test/products/*",
326
+ "include": true
327
+ }
328
+ ]
329
+ },
330
+ "expect": {
331
+ "sdk": true,
332
+ "server": true
333
+ }
334
+ },
335
+ {
336
+ "name": "regex-prefixed absolute rule names host",
337
+ "url": "https://other.test/products/serum",
338
+ "storefrontOrigins": [
339
+ "https://shop.test"
340
+ ],
341
+ "targeting": {
342
+ "url": [
343
+ {
344
+ "type": "regex",
345
+ "pattern": "^https?:\\/\\/other\\.test/products/.*$",
346
+ "include": true
347
+ }
348
+ ]
349
+ },
350
+ "expect": {
351
+ "sdk": true,
352
+ "server": true
353
+ }
354
+ },
355
+ {
356
+ "name": "embedded query URL remains host agnostic",
357
+ "url": "https://other.test/products?return=https://example.com",
358
+ "storefrontOrigins": [
359
+ "https://shop.test"
360
+ ],
361
+ "targeting": {
362
+ "url": [
363
+ {
364
+ "type": "simple",
365
+ "pattern": "/products?return=https://example.com",
366
+ "include": true
367
+ }
368
+ ]
369
+ },
370
+ "expect": {
371
+ "sdk": false,
372
+ "server": false
373
+ }
374
+ },
375
+ {
376
+ "name": "protocol-relative rule names host",
377
+ "url": "https://other.test/products/serum",
378
+ "storefrontOrigins": [
379
+ "https://shop.test"
380
+ ],
381
+ "targeting": {
382
+ "url": [
383
+ {
384
+ "type": "simple",
385
+ "pattern": "//other.test/products/*",
386
+ "include": true
387
+ }
388
+ ]
389
+ },
390
+ "expect": {
391
+ "sdk": true,
392
+ "server": true
393
+ }
394
+ },
395
+ {
396
+ "name": "page rule bare string child stays raw",
397
+ "url": "https://shop.test/products/serum",
398
+ "targeting": {
399
+ "pageRules": [
400
+ {
401
+ "id": "raw-string",
402
+ "include": true,
403
+ "includeRules": ["/products/serum"]
404
+ }
405
+ ]
406
+ },
407
+ "expect": {
408
+ "sdk": false,
409
+ "server": false
410
+ }
411
+ },
412
+ {
413
+ "name": "page rule legacy alias child stays raw",
414
+ "url": "https://shop.test/products/serum",
415
+ "targeting": {
416
+ "pageRules": [
417
+ {
418
+ "id": "raw-alias",
419
+ "include": true,
420
+ "includeRules": [
421
+ {
422
+ "type": "url_contains",
423
+ "value": "products/serum"
424
+ }
425
+ ]
426
+ }
427
+ ]
428
+ },
429
+ "expect": {
430
+ "sdk": false,
431
+ "server": false
432
+ }
433
+ },
434
+ {
435
+ "name": "disabled include block fails gate",
436
+ "url": "https://shop.test/products/serum",
437
+ "targeting": {
438
+ "pageRules": [
439
+ {
440
+ "id": "disabled",
441
+ "disabled": true,
442
+ "include": true,
443
+ "includeRules": ["/products/*"]
444
+ }
445
+ ]
446
+ },
447
+ "expect": {
448
+ "sdk": false,
449
+ "server": false
450
+ }
451
+ },
452
+ {
453
+ "name": "js-only page block counts as rules",
454
+ "url": "https://shop.test/products/serum",
455
+ "targeting": {
456
+ "pageRules": [
457
+ {
458
+ "id": "js-only",
459
+ "include": true,
460
+ "advancedCondition": {
461
+ "code": "return true"
462
+ }
463
+ }
464
+ ]
465
+ },
466
+ "expect": {
467
+ "sdk": true,
468
+ "server": true
469
+ }
470
+ },
471
+ {
472
+ "name": "exclude takes precedence",
473
+ "url": "https://shop.test/products/sale",
474
+ "targeting": {
475
+ "url": [
476
+ {
477
+ "type": "simple",
478
+ "pattern": "/products/*",
479
+ "include": true
480
+ },
481
+ {
482
+ "type": "simple",
483
+ "pattern": "/products/sale",
484
+ "include": false
485
+ }
486
+ ]
487
+ },
488
+ "expect": {
489
+ "sdk": false,
490
+ "server": false
491
+ }
492
+ },
493
+ {
494
+ "name": "legacy segment reference without expanded rule fails closed",
495
+ "url": "https://shop.test/products/serum",
496
+ "targeting": {
497
+ "segments": [
498
+ {
499
+ "id": "segment-a"
500
+ }
501
+ ]
502
+ },
503
+ "expect": {
504
+ "sdk": false,
505
+ "server": false
506
+ }
507
+ },
508
+ {
509
+ "name": "legacy segment reference with ID-matched expanded rule passes discriminator",
510
+ "url": "https://shop.test/products/serum",
511
+ "targeting": {
512
+ "segments": [
513
+ {
514
+ "id": "segment-a"
515
+ }
516
+ ],
517
+ "segmentRules": [
518
+ {
519
+ "id": "segment-a",
520
+ "rules": {
521
+ "operator": "and",
522
+ "conditions": []
523
+ }
524
+ }
525
+ ]
526
+ },
527
+ "expect": {
528
+ "sdk": true,
529
+ "server": true
530
+ }
531
+ },
532
+ {
533
+ "name": "partially expanded legacy segment references fail closed",
534
+ "url": "https://shop.test/products/serum",
535
+ "targeting": {
536
+ "segments": [
537
+ {
538
+ "id": "segment-a"
539
+ },
540
+ {
541
+ "id": "segment-b"
542
+ }
543
+ ],
544
+ "segmentRules": [
545
+ {
546
+ "id": "segment-a",
547
+ "rules": {
548
+ "operator": "and",
549
+ "conditions": []
550
+ }
551
+ }
552
+ ]
553
+ },
554
+ "expect": {
555
+ "sdk": false,
556
+ "server": false
557
+ }
558
+ }
559
+ ]
@@ -0,0 +1,18 @@
1
+ import { describe, expect, it } from "vitest";
2
+ import corpus from "./targeting-parity-corpus.json";
3
+ import { matchesTargeting } from "./targeting";
4
+ import type { Targeting } from "./types";
5
+
6
+ describe("server targeting parity corpus", () => {
7
+ for (const entry of corpus) {
8
+ it(entry.name, () => {
9
+ expect(
10
+ matchesTargeting(entry.targeting as Targeting, {
11
+ url: entry.url,
12
+ attributes: {},
13
+ hostAgnosticIncludeOrigin: entry.storefrontOrigins,
14
+ }),
15
+ ).toBe(entry.expect.sdk);
16
+ });
17
+ }
18
+ });
@@ -4,6 +4,20 @@ import { evaluateTargetingGates, evaluateTargetingGatesDetailed } from "./target
4
4
  import type { Targeting } from "./types";
5
5
 
6
6
  describe("evaluateTargetingGatesDetailed", () => {
7
+ it("includes failed device conditions in QA builds", async () => {
8
+ const qaBuild = await build({
9
+ entryPoints: ["src/targeting.ts"], bundle: true, format: "esm", platform: "node", write: false,
10
+ define: { __DRIP_QA_BUILD__: "true" },
11
+ });
12
+ const moduleUrl = `data:text/javascript;base64,${Buffer.from(qaBuild.outputFiles[0].text).toString("base64")}`;
13
+ const qaTargeting = await import(/* @vite-ignore */ moduleUrl) as typeof import("./targeting");
14
+ const result = qaTargeting.evaluateTargetingGatesDetailed({
15
+ segmentRules: [{ id: "device", rules: { version: 1, operator: "and", conditions: [{ signal: "device.type", operator: "equals", value: "mobile" }] } }],
16
+ }, { url: "https://shop.test", attributes: { "device.type": "desktop" } });
17
+ expect(result.conditions).toContainEqual(expect.objectContaining({
18
+ signal: "device.type", expected: "mobile", actual: "desktop", status: "failed",
19
+ }));
20
+ });
7
21
  it("uses aggregate targeting gates with empty conditions for live builds", async () => {
8
22
  const liveBuild = await build({
9
23
  entryPoints: ["src/targeting.ts"],
@@ -330,6 +344,81 @@ describe("evaluateTargetingGatesDetailed", () => {
330
344
  }));
331
345
  });
332
346
 
347
+ it("labels an empty JS-condition result as a segment mismatch", () => {
348
+ const diagnostics = evaluateTargetingGatesDetailed({
349
+ segmentRules: [{
350
+ id: "empty-js",
351
+ name: "Returning customers",
352
+ rules: {
353
+ version: 1,
354
+ operator: "and",
355
+ conditions: [{
356
+ signal: "url.query",
357
+ operator: "equals",
358
+ value: "campaign=spring",
359
+ js: { code: "return '';" },
360
+ }],
361
+ },
362
+ }],
363
+ }, { url: "https://shop.test/", attributes: {} });
364
+
365
+ expect(diagnostics.conditions).toContainEqual(expect.objectContaining({
366
+ id: "segment:empty-js:0",
367
+ status: "failed",
368
+ reason: "segment_mismatch",
369
+ }));
370
+ });
371
+
372
+ it("reports required and detected device values and distinguishes unresolved signals", () => {
373
+ const targeting: Targeting = {
374
+ segmentRules: [{
375
+ id: "device-audience",
376
+ rules: {
377
+ version: 1,
378
+ operator: "and",
379
+ conditions: [{ signal: "device.type", operator: "equals", value: "mobile" }],
380
+ },
381
+ }],
382
+ };
383
+
384
+ const mismatch = evaluateTargetingGatesDetailed(targeting, {
385
+ url: "https://shop.test/",
386
+ attributes: { "device.type": "desktop" },
387
+ });
388
+ expect(mismatch.conditions).toContainEqual(expect.objectContaining({
389
+ id: "segment:device-audience:0",
390
+ status: "failed",
391
+ reason: "segment_mismatch",
392
+ signal: "device.type",
393
+ expected: "mobile",
394
+ actual: "desktop",
395
+ }));
396
+
397
+ const unresolved = evaluateTargetingGatesDetailed(targeting, {
398
+ url: "https://shop.test/",
399
+ attributes: { "device.type": "" },
400
+ });
401
+ expect(unresolved.conditions).toContainEqual(expect.objectContaining({
402
+ id: "segment:device-audience:0",
403
+ status: "failed",
404
+ reason: "signal_unresolved",
405
+ signal: "device.type",
406
+ expected: "mobile",
407
+ actual: "",
408
+ }));
409
+
410
+ const missing = evaluateTargetingGatesDetailed(targeting, {
411
+ url: "https://shop.test/",
412
+ attributes: {},
413
+ });
414
+ expect(missing.conditions).toContainEqual(expect.objectContaining({
415
+ id: "segment:device-audience:0",
416
+ reason: "signal_unresolved",
417
+ expected: "mobile",
418
+ actual: "",
419
+ }));
420
+ });
421
+
333
422
  it("marks audience conditions skipped after a page failure", () => {
334
423
  const targeting: Targeting = {
335
424
  url: [{ type: "simple", pattern: "/products/*" }],
@@ -440,4 +529,20 @@ describe("evaluateTargetingGatesDetailed", () => {
440
529
  }
441
530
  `);
442
531
  });
532
+
533
+ it("names unexpanded legacy segment references in audience diagnostics", () => {
534
+ const diagnostics = evaluateTargetingGatesDetailed({
535
+ segments: [{ id: "legacy-segment" }],
536
+ }, {
537
+ url: "https://shop.test/",
538
+ attributes: {},
539
+ });
540
+
541
+ expect(diagnostics.matched).toBe(false);
542
+ expect(diagnostics.gates).toContainEqual(expect.objectContaining({
543
+ id: "audience",
544
+ status: "failed",
545
+ reason: "segments_unexpanded",
546
+ }));
547
+ });
443
548
  });