@osano/osano-cmp-react-native 0.18.6 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/lib/commonjs/ConsentManager.js +32 -1
  2. package/lib/commonjs/ConsentManager.js.map +1 -1
  3. package/lib/commonjs/components/PoweredByOsano.js +72 -0
  4. package/lib/commonjs/components/PoweredByOsano.js.map +1 -0
  5. package/lib/commonjs/iab/tcf/iab-storage-utils.js +53 -49
  6. package/lib/commonjs/iab/tcf/iab-storage-utils.js.map +1 -1
  7. package/lib/commonjs/iab/tcf/middleware.js +20 -23
  8. package/lib/commonjs/iab/tcf/middleware.js.map +1 -1
  9. package/lib/commonjs/iab/tcf/reducer.js +0 -22
  10. package/lib/commonjs/iab/tcf/reducer.js.map +1 -1
  11. package/lib/commonjs/index.js +16 -2
  12. package/lib/commonjs/index.js.map +1 -1
  13. package/lib/commonjs/reducer.js +5 -1
  14. package/lib/commonjs/reducer.js.map +1 -1
  15. package/lib/commonjs/services/consent.js +178 -77
  16. package/lib/commonjs/services/consent.js.map +1 -1
  17. package/lib/commonjs/views/Dialog/index.js +15 -2
  18. package/lib/commonjs/views/Dialog/index.js.map +1 -1
  19. package/lib/commonjs/views/Drawer/Drawer.ConsentCategories.js +160 -12
  20. package/lib/commonjs/views/Drawer/Drawer.ConsentCategories.js.map +1 -1
  21. package/lib/module/ConsentManager.js +32 -1
  22. package/lib/module/ConsentManager.js.map +1 -1
  23. package/lib/module/components/PoweredByOsano.js +68 -0
  24. package/lib/module/components/PoweredByOsano.js.map +1 -0
  25. package/lib/module/iab/tcf/iab-storage-utils.js +53 -49
  26. package/lib/module/iab/tcf/iab-storage-utils.js.map +1 -1
  27. package/lib/module/iab/tcf/middleware.js +22 -25
  28. package/lib/module/iab/tcf/middleware.js.map +1 -1
  29. package/lib/module/iab/tcf/reducer.js +1 -23
  30. package/lib/module/iab/tcf/reducer.js.map +1 -1
  31. package/lib/module/index.js +17 -3
  32. package/lib/module/index.js.map +1 -1
  33. package/lib/module/reducer.js +5 -1
  34. package/lib/module/reducer.js.map +1 -1
  35. package/lib/module/services/consent.js +174 -75
  36. package/lib/module/services/consent.js.map +1 -1
  37. package/lib/module/views/Dialog/index.js +16 -3
  38. package/lib/module/views/Dialog/index.js.map +1 -1
  39. package/lib/module/views/Drawer/Drawer.ConsentCategories.js +162 -14
  40. package/lib/module/views/Drawer/Drawer.ConsentCategories.js.map +1 -1
  41. package/lib/typescript/src/ConsentManager.d.ts +13 -1
  42. package/lib/typescript/src/ConsentManager.d.ts.map +1 -1
  43. package/lib/typescript/src/components/PoweredByOsano.d.ts +5 -0
  44. package/lib/typescript/src/components/PoweredByOsano.d.ts.map +1 -0
  45. package/lib/typescript/src/iab/tcf/iab-storage-utils.d.ts +7 -7
  46. package/lib/typescript/src/iab/tcf/iab-storage-utils.d.ts.map +1 -1
  47. package/lib/typescript/src/iab/tcf/middleware.d.ts.map +1 -1
  48. package/lib/typescript/src/iab/tcf/reducer.d.ts +1 -0
  49. package/lib/typescript/src/iab/tcf/reducer.d.ts.map +1 -1
  50. package/lib/typescript/src/index.d.ts.map +1 -1
  51. package/lib/typescript/src/reducer.d.ts.map +1 -1
  52. package/lib/typescript/src/services/consent.d.ts +28 -0
  53. package/lib/typescript/src/services/consent.d.ts.map +1 -1
  54. package/lib/typescript/src/views/Dialog/index.d.ts.map +1 -1
  55. package/lib/typescript/src/views/Drawer/Drawer.ConsentCategories.d.ts.map +1 -1
  56. package/package.json +5 -4
  57. package/src/ConsentManager.ts +33 -2
  58. package/src/components/PoweredByOsano.tsx +79 -0
  59. package/src/iab/tcf/iab-storage-utils.ts +101 -56
  60. package/src/iab/tcf/middleware.ts +36 -32
  61. package/src/iab/tcf/reducer.ts +2 -29
  62. package/src/index.tsx +15 -1
  63. package/src/reducer.ts +4 -0
  64. package/src/services/consent.ts +220 -86
  65. package/src/types/consent-config.d.ts +11 -1
  66. package/src/types/store.d.ts +5 -0
  67. package/src/views/Dialog/index.tsx +19 -1
  68. package/src/views/Drawer/Drawer.ConsentCategories.tsx +168 -11
@@ -53,7 +53,7 @@ export const DEFAULT_CONFIG: Config = {
53
53
  ],
54
54
  ccpaApplies: false,
55
55
  ccpaRelaxed: false,
56
- enableDoNotSell: false,
56
+ enableDoNotSell: true,
57
57
  enableDoNotSellDefault: false,
58
58
  doNotSellCategories: [],
59
59
  configId: '',
@@ -108,6 +108,8 @@ export const DEFAULT_CONFIG: Config = {
108
108
  policyLinkText: '',
109
109
  region: '',
110
110
  remoteConsent: false,
111
+ showConsentUuid: false,
112
+ showBannerLogo: false,
111
113
  storagePolicyHref: '',
112
114
  additionalLinks: [],
113
115
  timeoutSeconds: 0,
@@ -227,6 +229,7 @@ export class ConsentConfig extends EventEmitter {
227
229
  DEFAULT_CONFIG.palette,
228
230
  config.palette,
229
231
  ) as Palette;
232
+ delete this._config.forceReconsent;
230
233
  this._config = merge(this._config, config) as Config;
231
234
  this.emit('loadSuccess', this._config);
232
235
  })
@@ -289,7 +292,7 @@ export class ConsentConfig extends EventEmitter {
289
292
  get forceManagePreferences(): boolean {
290
293
  return this._config.forceManagePreferences;
291
294
  }
292
- get forceReconsent(): Date | undefined {
295
+ get forceReconsent(): number | undefined {
293
296
  return this._config.forceReconsent;
294
297
  }
295
298
  get googleConsent(): boolean {
@@ -313,6 +316,12 @@ export class ConsentConfig extends EventEmitter {
313
316
  get managePreferencesEnabled(): boolean {
314
317
  return this._config.managePreferencesEnabled;
315
318
  }
319
+ get showConsentUuid(): boolean {
320
+ return !!this._config.showConsentUuid;
321
+ }
322
+ get showBannerLogo(): boolean {
323
+ return !!this._config.showBannerLogo;
324
+ }
316
325
  get mode(): Mode {
317
326
  return this._config.mode;
318
327
  }
@@ -699,12 +708,32 @@ export class ConsentManager {
699
708
  private _overridePalette?: Palette;
700
709
  private _googleConsentModeCallback?: GoogleConsentModeCallback;
701
710
  private _consentExpirationTestingSeconds?: number;
711
+ private _consentInvalidated = false;
712
+ private _consentPromptRequired = false;
702
713
 
703
714
  private _deviceId = '';
704
715
  public get deviceId(): string {
705
716
  return this._deviceId;
706
717
  }
707
718
 
719
+ /**
720
+ * True when the most recent load invalidated local consent data.
721
+ */
722
+ public get consentInvalidated(): boolean {
723
+ return this._consentInvalidated;
724
+ }
725
+ public set consentInvalidated(value: boolean) {
726
+ this._consentInvalidated = value;
727
+ }
728
+
729
+ /** False when fresh remote consent supersedes only the re-prompt. */
730
+ public get consentPromptRequired(): boolean {
731
+ return this._consentPromptRequired;
732
+ }
733
+ public set consentPromptRequired(value: boolean) {
734
+ this._consentPromptRequired = value;
735
+ }
736
+
708
737
  /**
709
738
  * The debug-only consent expiration testing window, in seconds, or
710
739
  * `undefined` when testing mode is disabled. Read by the consent service to
@@ -954,6 +983,8 @@ export class ConsentManager {
954
983
  resolveLoadConfig(
955
984
  new Promise((resolve, reject) => {
956
985
  this._cancelLoading = reject;
986
+ this._consentInvalidated = false;
987
+ this._consentPromptRequired = false;
957
988
  fetchConsent(this)
958
989
  .catch(() => {
959
990
  // Consent not found
@@ -0,0 +1,79 @@
1
+ import React from 'react';
2
+ import {
3
+ ClipPath,
4
+ Defs,
5
+ G,
6
+ Mask,
7
+ Path,
8
+ Rect,
9
+ Svg,
10
+ type SvgProps,
11
+ } from 'react-native-svg';
12
+
13
+ // The "Powered by Osano" brand mark, rendered inline with react-native-svg so no
14
+ // SVG asset transformer is required to display it.
15
+ const PoweredByOsano: React.FC<SvgProps> = (props) => (
16
+ <Svg
17
+ width={164}
18
+ height={20}
19
+ viewBox="0 0 164 20"
20
+ fill="none"
21
+ {...props}
22
+ // After {...props} so callers can't override it: taps must fall through to
23
+ // the wrapping Pressable, or the SVG's native view swallows the touch and
24
+ // the link never fires.
25
+ pointerEvents="none"
26
+ >
27
+ <Path
28
+ d="M1.05 15V5.2H4.242C5.01667 5.2 5.65133 5.33067 6.146 5.592C6.65 5.844 7.01867 6.18467 7.252 6.614C7.49467 7.04333 7.616 7.53333 7.616 8.084C7.616 8.616 7.49467 9.10133 7.252 9.54C7.01867 9.96933 6.65467 10.3147 6.16 10.576C5.66533 10.8373 5.026 10.968 4.242 10.968H2.226V15H1.05ZM2.226 9.974H4.228C5.012 9.974 5.572 9.80133 5.908 9.456C6.244 9.11067 6.412 8.65333 6.412 8.084C6.412 7.47733 6.244 7.01067 5.908 6.684C5.572 6.348 5.012 6.18 4.228 6.18H2.226V9.974ZM11.8409 15.168C11.1876 15.168 10.5996 15.0187 10.0769 14.72C9.55427 14.412 9.1436 13.9827 8.84494 13.432C8.54627 12.872 8.39694 12.2233 8.39694 11.486C8.39694 10.73 8.54627 10.0767 8.84494 9.526C9.15294 8.966 9.56827 8.53667 10.0909 8.238C10.6229 7.93 11.2156 7.776 11.8689 7.776C12.5409 7.776 13.1336 7.93 13.6469 8.238C14.1696 8.53667 14.5803 8.966 14.8789 9.526C15.1869 10.0767 15.3409 10.7253 15.3409 11.472C15.3409 12.2187 15.1869 12.872 14.8789 13.432C14.5709 13.9827 14.1556 14.412 13.6329 14.72C13.1103 15.0187 12.5129 15.168 11.8409 15.168ZM11.8549 14.16C12.2563 14.16 12.6296 14.062 12.9749 13.866C13.3203 13.6607 13.6003 13.3573 13.8149 12.956C14.0296 12.5547 14.1369 12.06 14.1369 11.472C14.1369 10.8747 14.0296 10.38 13.8149 9.988C13.6096 9.58667 13.3343 9.288 12.9889 9.092C12.6529 8.88667 12.2796 8.784 11.8689 8.784C11.4769 8.784 11.1036 8.88667 10.7489 9.092C10.4036 9.288 10.1236 9.58667 9.90894 9.988C9.7036 10.38 9.60094 10.8747 9.60094 11.472C9.60094 12.06 9.7036 12.5547 9.90894 12.956C10.1236 13.3573 10.3989 13.6607 10.7349 13.866C11.0803 14.062 11.4536 14.16 11.8549 14.16ZM18.158 15L16.086 7.944H17.262L18.872 13.894H18.662L20.412 7.944H21.742L23.52 13.88L23.296 13.894L24.892 7.944H26.082L24.024 15H22.82L20.972 8.784H21.21L19.362 15H18.158ZM30.242 15.168C29.5793 15.168 28.9913 15.014 28.478 14.706C27.974 14.398 27.5773 13.9687 27.288 13.418C26.9986 12.858 26.854 12.2093 26.854 11.472C26.854 10.7253 26.994 10.0767 27.274 9.526C27.5633 8.97533 27.9646 8.546 28.478 8.238C29.0006 7.93 29.598 7.776 30.27 7.776C30.9606 7.776 31.544 7.93 32.02 8.238C32.5053 8.546 32.874 8.952 33.126 9.456C33.3873 9.95067 33.518 10.4967 33.518 11.094C33.518 11.1873 33.518 11.2853 33.518 11.388C33.518 11.4907 33.5133 11.6073 33.504 11.738H27.736V10.828H32.37C32.342 10.184 32.1273 9.68 31.726 9.316C31.334 8.952 30.8393 8.77 30.242 8.77C29.8406 8.77 29.4673 8.86333 29.122 9.05C28.786 9.22733 28.5153 9.49333 28.31 9.848C28.1046 10.1933 28.002 10.6273 28.002 11.15V11.542C28.002 12.1207 28.1046 12.606 28.31 12.998C28.5246 13.39 28.8 13.684 29.136 13.88C29.4813 14.076 29.85 14.174 30.242 14.174C30.7366 14.174 31.1426 14.0667 31.46 13.852C31.7866 13.628 32.02 13.3293 32.16 12.956H33.322C33.21 13.376 33.014 13.754 32.734 14.09C32.454 14.426 32.104 14.692 31.684 14.888C31.2733 15.0747 30.7926 15.168 30.242 15.168ZM35.105 15V7.944H36.169L36.253 9.288C36.4117 8.97067 36.6123 8.7 36.855 8.476C37.107 8.252 37.4057 8.07933 37.751 7.958C38.1057 7.83667 38.507 7.776 38.955 7.776V9.008H38.521C38.2223 9.008 37.9377 9.05 37.667 9.134C37.3963 9.20867 37.1537 9.33467 36.939 9.512C36.7337 9.68933 36.5703 9.932 36.449 10.24C36.337 10.5387 36.281 10.912 36.281 11.36V15H35.105ZM43.1209 15.168C42.4582 15.168 41.8702 15.014 41.3569 14.706C40.8529 14.398 40.4562 13.9687 40.1669 13.418C39.8775 12.858 39.7329 12.2093 39.7329 11.472C39.7329 10.7253 39.8729 10.0767 40.1529 9.526C40.4422 8.97533 40.8435 8.546 41.3569 8.238C41.8795 7.93 42.4769 7.776 43.1489 7.776C43.8395 7.776 44.4229 7.93 44.8989 8.238C45.3842 8.546 45.7529 8.952 46.0049 9.456C46.2662 9.95067 46.3969 10.4967 46.3969 11.094C46.3969 11.1873 46.3969 11.2853 46.3969 11.388C46.3969 11.4907 46.3922 11.6073 46.3829 11.738H40.6149V10.828H45.2489C45.2209 10.184 45.0062 9.68 44.6049 9.316C44.2129 8.952 43.7182 8.77 43.1209 8.77C42.7195 8.77 42.3462 8.86333 42.0009 9.05C41.6649 9.22733 41.3942 9.49333 41.1889 9.848C40.9835 10.1933 40.8809 10.6273 40.8809 11.15V11.542C40.8809 12.1207 40.9835 12.606 41.1889 12.998C41.4035 13.39 41.6789 13.684 42.0149 13.88C42.3602 14.076 42.7289 14.174 43.1209 14.174C43.6155 14.174 44.0215 14.0667 44.3389 13.852C44.6655 13.628 44.8989 13.3293 45.0389 12.956H46.2009C46.0889 13.376 45.8929 13.754 45.6129 14.09C45.3329 14.426 44.9829 14.692 44.5629 14.888C44.1522 15.0747 43.6715 15.168 43.1209 15.168ZM51.0919 15.168C50.4106 15.168 49.8132 15.0093 49.2999 14.692C48.7866 14.3653 48.3899 13.922 48.1099 13.362C47.8299 12.802 47.6899 12.1673 47.6899 11.458C47.6899 10.7487 47.8299 10.1187 48.1099 9.568C48.3899 9.008 48.7866 8.56933 49.2999 8.252C49.8226 7.93467 50.4246 7.776 51.1059 7.776C51.6846 7.776 52.1886 7.89267 52.6179 8.126C53.0566 8.35933 53.3926 8.686 53.6259 9.106V4.92H54.8019V15H53.7379L53.6399 13.838C53.4906 14.0713 53.2992 14.2907 53.0659 14.496C52.8326 14.692 52.5526 14.8553 52.2259 14.986C51.8992 15.1073 51.5212 15.168 51.0919 15.168ZM51.2319 14.146C51.6986 14.146 52.1092 14.034 52.4639 13.81C52.8186 13.586 53.0939 13.278 53.2899 12.886C53.4859 12.4847 53.5839 12.0133 53.5839 11.472C53.5839 10.94 53.4859 10.4733 53.2899 10.072C53.0939 9.67067 52.8186 9.358 52.4639 9.134C52.1092 8.91 51.6986 8.798 51.2319 8.798C50.7746 8.798 50.3686 8.91 50.0139 9.134C49.6592 9.358 49.3839 9.67067 49.1879 10.072C48.9919 10.4733 48.8939 10.94 48.8939 11.472C48.8939 12.0133 48.9919 12.4847 49.1879 12.886C49.3839 13.278 49.6592 13.586 50.0139 13.81C50.3686 14.034 50.7746 14.146 51.2319 14.146ZM64.176 15.168C63.7747 15.168 63.4107 15.112 63.084 15C62.7667 14.8787 62.4867 14.72 62.244 14.524C62.0013 14.328 61.8007 14.0993 61.642 13.838L61.544 15H60.48V4.92H61.656V9.106C61.88 8.742 62.202 8.42933 62.622 8.168C63.042 7.90667 63.56 7.776 64.176 7.776C64.8573 7.776 65.4547 7.93933 65.968 8.266C66.4813 8.58333 66.878 9.022 67.158 9.582C67.4473 10.1327 67.592 10.7627 67.592 11.472C67.592 12.1813 67.4473 12.816 67.158 13.376C66.878 13.936 66.4813 14.3747 65.968 14.692C65.4547 15.0093 64.8573 15.168 64.176 15.168ZM64.036 14.146C64.4933 14.146 64.8993 14.034 65.254 13.81C65.6087 13.586 65.884 13.278 66.08 12.886C66.2853 12.4847 66.388 12.0133 66.388 11.472C66.388 10.94 66.2853 10.4733 66.08 10.072C65.884 9.67067 65.6087 9.358 65.254 9.134C64.8993 8.91 64.4933 8.798 64.036 8.798C63.5693 8.798 63.1587 8.91 62.804 9.134C62.4493 9.358 62.174 9.67067 61.978 10.072C61.782 10.4733 61.684 10.94 61.684 11.472C61.684 12.0133 61.782 12.4847 61.978 12.886C62.174 13.278 62.4493 13.586 62.804 13.81C63.1587 14.034 63.5693 14.146 64.036 14.146ZM69.4531 18.08L71.1751 14.216H70.7691L67.9971 7.944H69.2711L71.5671 13.334L73.9751 7.944H75.1931L70.6851 18.08H69.4531Z"
29
+ fill="#726A82"
30
+ />
31
+ <G clipPath="url(#clip0_387_623)">
32
+ <Mask
33
+ id="mask0_387_623"
34
+ maskType="luminance"
35
+ maskUnits="userSpaceOnUse"
36
+ x={80}
37
+ y={2}
38
+ width={84}
39
+ height={16}
40
+ >
41
+ <Path d="M163.201 2H80.0006V18H163.201V2Z" fill="white" />
42
+ </Mask>
43
+ <G mask="url(#mask0_387_623)">
44
+ <Path
45
+ d="M95.7142 10.5143C95.6506 12.4158 94.8518 14.2181 93.4863 15.5406C92.0121 17.0271 90.1358 17.7704 87.8574 17.7704C85.579 17.7704 83.7022 17.0271 82.2269 15.5406C80.862 14.2178 80.0637 12.4156 80.0006 10.5143V9.25775C80.0637 7.35653 80.862 5.55425 82.2269 4.23149C83.6999 2.74494 85.5768 2.00111 87.8574 2C90.138 1.99889 92.0143 2.74272 93.4863 4.23149C94.8518 5.55398 95.6506 7.35626 95.7142 9.25775V10.5143ZM84.2817 10.1677C84.2859 10.5979 84.3753 11.0229 84.5446 11.4183C84.714 11.8136 84.96 12.1714 85.2684 12.4708C85.9051 13.1086 86.7675 13.428 87.8557 13.4291C88.9439 13.4302 89.8069 13.1108 90.4447 12.4708C90.7536 12.1703 91 11.8115 91.1696 11.415C91.3393 11.0185 91.4288 10.5923 91.433 10.161V9.59605C91.4286 9.16501 91.339 8.73914 91.1693 8.34298C90.9997 7.94682 90.7534 7.58826 90.4447 7.28791C89.808 6.64796 88.9456 6.32854 87.8574 6.32965C86.7692 6.33076 85.9062 6.6524 85.2684 7.29457C84.9591 7.59445 84.7124 7.95295 84.5428 8.34922C84.3731 8.74549 84.2838 9.17157 84.2801 9.60271L84.2817 10.1677Z"
46
+ fill="#9563F3"
47
+ />
48
+ <Path
49
+ d="M129.634 17.7703V9.27103C129.697 7.37087 130.494 5.56932 131.857 4.24643C133.331 2.75988 135.207 2.0166 137.486 2.0166C139.764 2.0166 141.641 2.75988 143.117 4.24643C144.481 5.56919 145.279 7.37146 145.343 9.27269V17.772H141.066V9.61935C141.063 9.18714 140.974 8.75983 140.805 8.36245C140.635 7.96501 140.388 7.60538 140.078 7.30452C139.44 6.66567 138.578 6.34625 137.491 6.34625C136.404 6.34625 135.541 6.66567 134.903 7.30452C134.594 7.60506 134.348 7.96389 134.178 8.36037C134.009 8.75679 133.919 9.18303 133.915 9.61434V17.7703H129.634Z"
50
+ fill="#9563F3"
51
+ />
52
+ <Path
53
+ d="M123.424 9.60272C123.42 9.17168 123.33 8.74581 123.16 8.34965C122.991 7.95349 122.744 7.59488 122.436 7.29458C121.798 6.65463 120.935 6.33521 119.848 6.33632C118.761 6.33743 117.899 6.65685 117.261 7.29458C116.952 7.59488 116.706 7.95349 116.536 8.34965C116.367 8.74581 116.277 9.17168 116.273 9.60272V10.1677C116.278 11.0223 116.603 11.844 117.183 12.4708C117.768 13.1085 118.552 13.428 119.534 13.4291C120.516 13.4302 121.284 13.2419 121.84 12.8641V17.2771C121.228 17.611 120.54 17.7788 119.843 17.7637C117.564 17.7637 115.687 17.0205 114.213 15.5339C112.848 14.2111 112.05 12.4089 111.987 10.5076V9.25109C112.053 7.35125 112.854 5.55153 114.219 4.23149C115.694 2.74494 117.571 2.00111 119.85 2C122.13 1.99889 124.006 2.74271 125.48 4.23149C126.845 5.55425 127.644 7.35653 127.707 9.25776V17.7704H123.424V9.60272Z"
54
+ fill="#9563F3"
55
+ />
56
+ <Path
57
+ d="M109.639 11.7389C110.111 13.2255 109.951 14.6026 109.162 15.8703C108.372 17.138 107.063 17.7713 105.235 17.7701H98.2699V13.4038H104.925C105.291 13.3405 105.477 13.1833 105.483 12.9322C105.488 12.6811 104.379 12.1417 102.155 11.314C100.12 10.5929 98.8722 9.47857 98.413 7.97094C98.0469 6.36883 98.2561 5.00727 99.0403 3.88625C99.8245 2.76523 101.335 2.16805 103.571 2.09473H108.997V6.44605H104.198C103.613 6.39272 103.273 6.51549 103.178 6.81435C103.085 7.11266 103.33 7.39932 103.915 7.67094L105.985 8.4559C107.951 9.15804 109.169 10.2524 109.639 11.7389Z"
58
+ fill="#9563F3"
59
+ />
60
+ <Path
61
+ d="M163.194 10.5143C163.133 12.4146 162.337 14.2167 160.975 15.5406C159.5 17.0271 157.624 17.7704 155.344 17.7704C153.064 17.7704 151.187 17.0271 149.713 15.5406C148.348 14.2178 147.55 12.4156 147.487 10.5143V9.25776C147.55 7.35653 148.348 5.55425 149.713 4.23149C151.187 2.74494 153.064 2.00111 155.344 2C157.624 1.99889 159.5 2.74271 160.975 4.23149C162.339 5.55425 163.138 7.35653 163.201 9.25776L163.194 10.5143ZM151.762 10.1677C151.767 10.5979 151.857 11.0228 152.026 11.4181C152.196 11.8133 152.442 12.1711 152.75 12.4708C153.387 13.1085 154.249 13.428 155.337 13.4291C156.425 13.4302 157.288 13.1108 157.924 12.4708C158.233 12.1703 158.48 11.8115 158.65 11.415C158.819 11.0185 158.908 10.5923 158.913 10.161V9.59605C158.908 9.16501 158.819 8.73915 158.649 8.34299C158.48 7.94683 158.233 7.58821 157.924 7.28791C157.287 6.64796 156.424 6.32854 155.337 6.32965C154.25 6.33076 153.388 6.65018 152.75 7.28791C152.441 7.58821 152.195 7.94683 152.025 8.34299C151.856 8.73915 151.766 9.16501 151.762 9.59605V10.1677Z"
62
+ fill="#9563F3"
63
+ />
64
+ </G>
65
+ </G>
66
+ <Defs>
67
+ <ClipPath id="clip0_387_623">
68
+ <Rect
69
+ width={83.2}
70
+ height={16}
71
+ fill="white"
72
+ transform="translate(80 2)"
73
+ />
74
+ </ClipPath>
75
+ </Defs>
76
+ </Svg>
77
+ );
78
+
79
+ export default PoweredByOsano;
@@ -29,27 +29,65 @@ export interface IABConsentData {
29
29
  enableAdvertiserConsentMode?: boolean;
30
30
  }
31
31
 
32
- export const clearAllIABKeys = (): void => {
33
- osanoLogger.info('🧹 Clearing all IAB consent keys...');
34
-
35
- Object.values(IABKeys.LEGACY).forEach((key) => {
36
- clearStorageFromDefault(key);
37
- });
38
-
39
- DEFAULT_STORAGE_KEYS.IABTCF.forEach((key) => {
40
- clearStorageFromDefault(key);
41
- });
42
-
43
- CUSTOM_STORAGE_KEYS.forEach((key) => {
44
- clearStorage(key);
45
- });
46
-
47
- osanoLogger.info(
48
- '✅ All IAB consent keys cleared from both custom and default storage',
32
+ let storageQueue = Promise.resolve();
33
+
34
+ const enqueueStorageOperation = <T>(
35
+ operation: () => Promise<T>,
36
+ ): Promise<T> => {
37
+ const result = storageQueue.then(operation, operation);
38
+ storageQueue = result.then(
39
+ () => undefined,
40
+ (error) => {
41
+ osanoLogger.error(
42
+ `IAB storage operation failed: ${String(error)}`,
43
+ error instanceof Error ? error : undefined,
44
+ );
45
+ },
49
46
  );
47
+ return result;
50
48
  };
51
49
 
52
- export const setAllIABKeys = (consentData: IABConsentData): void => {
50
+ const enqueueSetStorage = (key: string, value: string) =>
51
+ enqueueStorageOperation(() => setStorage(key, value));
52
+
53
+ const enqueueSetStorageToDefault = (key: string, value: string) =>
54
+ enqueueStorageOperation(() => setStorageToDefault(key, value));
55
+
56
+ const enqueueSetIntStorageToDefault = (key: string, value: number) =>
57
+ enqueueStorageOperation(() => setIntStorageToDefault(key, value));
58
+
59
+ export const clearAllIABKeys = (
60
+ additionalCustomKeys: string[] = [],
61
+ ): Promise<void> =>
62
+ enqueueStorageOperation(async () => {
63
+ osanoLogger.info('🧹 Clearing all IAB consent keys...');
64
+ const operations = [
65
+ ...Object.values(IABKeys.LEGACY).map((key) =>
66
+ clearStorageFromDefault(key),
67
+ ),
68
+ ...DEFAULT_STORAGE_KEYS.IABTCF.map((key) => clearStorageFromDefault(key)),
69
+ ...[...CUSTOM_STORAGE_KEYS, ...additionalCustomKeys].map((key) =>
70
+ clearStorage(key),
71
+ ),
72
+ ];
73
+ const failures = await Promise.all(
74
+ operations.map((operation) =>
75
+ operation.then(
76
+ () => ({ failed: false as const }),
77
+ (error: unknown) => ({ failed: true as const, error }),
78
+ ),
79
+ ),
80
+ );
81
+ const failure = failures.find((result) => result.failed);
82
+ if (failure?.failed) {
83
+ throw failure.error;
84
+ }
85
+ osanoLogger.info(
86
+ '✅ All IAB consent keys cleared from both custom and default storage',
87
+ );
88
+ });
89
+
90
+ export const setAllIABKeys = (consentData: IABConsentData): Promise<void> => {
53
91
  const {
54
92
  tcString,
55
93
  cmpId,
@@ -72,57 +110,66 @@ export const setAllIABKeys = (consentData: IABConsentData): void => {
72
110
  const subjectToGDPR = gdprApplies ? '1' : '0';
73
111
 
74
112
  // === Save to Custom Storage ===
75
- setStorage(IABKeys.IABTCF.CMP_SDK_ID, cmpId.toString());
76
- setStorage(IABKeys.IABTCF.CMP_SDK_VERSION, cmpVersion.toString());
77
- setStorage(IABKeys.IABTCF.POLICY_VERSION, policyVersion);
78
- setStorage(IABKeys.IABTCF.PUBLISHER_CC, publisherCC);
79
- setStorage(IABKeys.IABTCF.GDPR_APPLIES, subjectToGDPR);
80
- setStorage(
113
+ enqueueSetStorage(IABKeys.IABTCF.CMP_SDK_ID, cmpId.toString());
114
+ enqueueSetStorage(IABKeys.IABTCF.CMP_SDK_VERSION, cmpVersion.toString());
115
+ enqueueSetStorage(IABKeys.IABTCF.POLICY_VERSION, policyVersion);
116
+ enqueueSetStorage(IABKeys.IABTCF.PUBLISHER_CC, publisherCC);
117
+ enqueueSetStorage(IABKeys.IABTCF.GDPR_APPLIES, subjectToGDPR);
118
+ enqueueSetStorage(
81
119
  IABKeys.IABTCF.PURPOSE_ONE_TREATMENT,
82
120
  purposeOneTreatment ? '1' : '0',
83
121
  );
84
- setStorage(
122
+ enqueueSetStorage(
85
123
  IABKeys.IABTCF.USE_NON_STANDARD_TEXTS,
86
124
  useNonStandardStacks ? '1' : '0',
87
125
  );
88
- setStorage(IABKeys.IABTCF.VENDOR_CONSENTS, vendorConsentsString);
89
- setStorage(
126
+ enqueueSetStorage(IABKeys.IABTCF.VENDOR_CONSENTS, vendorConsentsString);
127
+ enqueueSetStorage(
90
128
  IABKeys.IABTCF.VENDOR_LEGITIMATE_INTERESTS,
91
129
  vendorLegitimateInterestsString,
92
130
  );
93
- setStorage(IABKeys.IABTCF.PURPOSE_CONSENTS, purposeConsentsString);
94
- setStorage(
131
+ enqueueSetStorage(IABKeys.IABTCF.PURPOSE_CONSENTS, purposeConsentsString);
132
+ enqueueSetStorage(
95
133
  IABKeys.IABTCF.PURPOSE_LEGITIMATE_INTERESTS,
96
134
  purposeLegitimateInterestsString,
97
135
  );
98
- setStorage(
136
+ enqueueSetStorage(
99
137
  IABKeys.IABTCF.SPECIAL_FEATURES_OPT_INS,
100
138
  specialFeatureOptinsString,
101
139
  );
102
140
 
103
141
  // === Save to Default Storage for AdMob Compatibility ===
104
142
 
105
- setStorageToDefault(IABKeys.LEGACY.CMP_PRESENT, 'true');
106
- setStorageToDefault(IABKeys.LEGACY.SUBJECT_TO_GDPR, subjectToGDPR);
107
- setStorageToDefault(IABKeys.LEGACY.CONSENT_STRING, tcString);
108
- setStorageToDefault(
143
+ enqueueSetStorageToDefault(IABKeys.LEGACY.CMP_PRESENT, 'true');
144
+ enqueueSetStorageToDefault(IABKeys.LEGACY.SUBJECT_TO_GDPR, subjectToGDPR);
145
+ enqueueSetStorageToDefault(IABKeys.LEGACY.CONSENT_STRING, tcString);
146
+ enqueueSetStorageToDefault(
109
147
  IABKeys.LEGACY.PARSED_PURPOSE_CONSENTS,
110
148
  purposeConsentsString,
111
149
  );
112
- setStorageToDefault(
150
+ enqueueSetStorageToDefault(
113
151
  IABKeys.LEGACY.PARSED_VENDOR_CONSENTS,
114
152
  vendorConsentsString,
115
153
  );
116
154
 
117
- setIntStorageToDefault(IABKeys.IABTCF.GDPR_APPLIES, gdprApplies ? 1 : 0);
118
- setStorageToDefault(IABKeys.IABTCF.TC_STRING, tcString);
119
- setStorageToDefault(IABKeys.IABTCF.PURPOSE_CONSENTS, purposeConsentsString);
120
- setStorageToDefault(IABKeys.IABTCF.VENDOR_CONSENTS, vendorConsentsString);
121
- setStorageToDefault(IABKeys.IABTCF.ADDTL_CONSENT, '');
155
+ enqueueSetIntStorageToDefault(
156
+ IABKeys.IABTCF.GDPR_APPLIES,
157
+ gdprApplies ? 1 : 0,
158
+ );
159
+ enqueueSetStorageToDefault(IABKeys.IABTCF.TC_STRING, tcString);
160
+ enqueueSetStorageToDefault(
161
+ IABKeys.IABTCF.PURPOSE_CONSENTS,
162
+ purposeConsentsString,
163
+ );
164
+ enqueueSetStorageToDefault(
165
+ IABKeys.IABTCF.VENDOR_CONSENTS,
166
+ vendorConsentsString,
167
+ );
168
+ enqueueSetStorageToDefault(IABKeys.IABTCF.ADDTL_CONSENT, '');
122
169
 
123
170
  // Handle Google Consent Mode integration
124
171
  if (enableAdvertiserConsentMode !== undefined) {
125
- setIntStorageToDefault(
172
+ enqueueSetIntStorageToDefault(
126
173
  IABKeys.IABTCF.ENABLE_ADVERTISER_CONSENT_MODE,
127
174
  enableAdvertiserConsentMode ? 1 : 0,
128
175
  );
@@ -143,24 +190,22 @@ export const setAllIABKeys = (consentData: IABConsentData): void => {
143
190
  osanoLogger.debug(
144
191
  `📊 Updated IAB keys: CMP=true, SubjectToGDPR=${subjectToGDPR}, PurposeConsents=${purposeConsentsString.length} chars, VendorConsents=${vendorConsentsString.length} chars`,
145
192
  );
193
+ return enqueueStorageOperation(() => Promise.resolve());
146
194
  };
147
195
 
148
- export const setCustomIABKey = (key: string, value: string): void => {
149
- setStorage(key, value);
150
- };
196
+ export const setCustomIABKey = (key: string, value: string): Promise<string> =>
197
+ enqueueSetStorage(key, value);
151
198
 
152
- export const setDefaultIABKey = (key: string, value: string): void => {
153
- setStorageToDefault(key, value);
154
- };
199
+ export const setDefaultIABKey = (key: string, value: string): Promise<string> =>
200
+ enqueueSetStorageToDefault(key, value);
155
201
 
156
- export const setDefaultIABKeyAsInt = (key: string, value: number): void => {
157
- setIntStorageToDefault(key, value);
158
- };
202
+ export const setDefaultIABKeyAsInt = (
203
+ key: string,
204
+ value: number,
205
+ ): Promise<number> => enqueueSetIntStorageToDefault(key, value);
159
206
 
160
- export const clearCustomIABKey = (key: string): void => {
161
- clearStorage(key);
162
- };
207
+ export const clearCustomIABKey = (key: string): Promise<void> =>
208
+ enqueueStorageOperation(() => clearStorage(key));
163
209
 
164
- export const clearDefaultIABKey = (key: string): void => {
165
- clearStorageFromDefault(key);
166
- };
210
+ export const clearDefaultIABKey = (key: string): Promise<void> =>
211
+ enqueueStorageOperation(() => clearStorageFromDefault(key));
@@ -8,8 +8,12 @@ import {
8
8
  setConsent,
9
9
  } from './actions';
10
10
  import { SET_CONSENT_DATA, setConsentData } from '../actions';
11
- import { clearAllIABKeys, setAllIABKeys } from './iab-storage-utils';
12
- import { clearStorage, getStorage, setStorage } from '../../native/OsanoCmp';
11
+ import {
12
+ clearAllIABKeys,
13
+ setAllIABKeys,
14
+ setCustomIABKey,
15
+ } from './iab-storage-utils';
16
+ import { clearStorage, getStorage } from '../../native/OsanoCmp';
13
17
  import { getConsentString, getPurposeIds } from './selectors';
14
18
  import {
15
19
  idRecordToBinaryString,
@@ -25,12 +29,18 @@ import { Platform } from 'react-native';
25
29
  import type { Store } from '../../hooks/useThunkReducer';
26
30
  import { osanoLogger } from '../../utils/OsanoLogger';
27
31
 
32
+ const TCF_GPP_SECTIONS = ['tcfeuv2', 'tcfcav1'];
33
+
28
34
  export const makeMiddleware: IabMiddlewareFactory = (
29
35
  initOptions: IabInitOptions,
30
36
  ) => {
31
37
  const { createConsentPayload, gppSection, version } = initOptions;
32
38
  const parseConsentString = makeParseConsentString(initOptions);
33
39
  const formatConsentString = makeFormatConsentString(initOptions);
40
+ const clearStoredTcfConsent = (configId: string) =>
41
+ clearAllIABKeys(
42
+ TCF_GPP_SECTIONS.map((section) => `${section}_${configId}`),
43
+ );
34
44
  return (store: Store<OsanoState & IabState, OsanoAction>) =>
35
45
  (next: (action: OsanoAction) => OsanoState & IabState) =>
36
46
  (action: OsanoAction) => {
@@ -64,6 +74,20 @@ export const makeMiddleware: IabMiddlewareFactory = (
64
74
  }
65
75
  store.dispatch(setConsent(payload));
66
76
  };
77
+ // Wipe instead of rehydrating a granted string. A localStorage-only
78
+ // path left IABTCF_* behind; OsanoCmp covers every platform.
79
+ if (newState.consentInvalidated) {
80
+ newState.iab.consentStrings = {
81
+ ...newState.iab.consentStrings,
82
+ [gppSection]: '',
83
+ };
84
+ store.dispatch(setConsentData(gppSection, ''));
85
+ clearStoredTcfConsent(configId).then(
86
+ () => resConsent(null),
87
+ () => resConsent(null),
88
+ );
89
+ break;
90
+ }
67
91
  switch (Platform.OS) {
68
92
  case 'ios':
69
93
  case 'android':
@@ -87,20 +111,12 @@ export const makeMiddleware: IabMiddlewareFactory = (
87
111
  break;
88
112
  }
89
113
  case CLEAR_CONSENT: {
90
- switch (Platform.OS) {
91
- case 'ios':
92
- case 'android':
93
- clearStorage(`${gppSection}_${configId}`);
94
-
95
- clearAllIABKeys();
96
- break;
97
- default:
98
- try {
99
- window.localStorage.removeItem(`${gppSection}_${configId}`);
100
- } catch {}
101
- break;
102
- }
114
+ newState.iab.consentStrings = {
115
+ ...newState.iab.consentStrings,
116
+ [gppSection]: '',
117
+ };
103
118
  store.dispatch(setConsentData(gppSection, ''));
119
+ clearStoredTcfConsent(configId).catch(() => {});
104
120
  break;
105
121
  }
106
122
  case SET_ALL_PURPOSE_CONSENT: {
@@ -147,22 +163,10 @@ export const makeMiddleware: IabMiddlewareFactory = (
147
163
  case SAVE_BEGIN: {
148
164
  if (config && configId) {
149
165
  const consentPayload = createConsentPayload(newState);
150
- switch (Platform.OS) {
151
- case 'ios':
152
- case 'android':
153
- try {
154
- setStorage(
155
- `${gppSection}_${configId}`,
156
- JSON.stringify(consentPayload),
157
- );
158
- } catch (err) {
159
- osanoLogger.error(
160
- `Failed to save consent to device storage: ${err}`,
161
- err instanceof Error ? err : undefined,
162
- );
163
- }
164
- break;
165
- }
166
+ setCustomIABKey(
167
+ `${gppSection}_${configId}`,
168
+ JSON.stringify(consentPayload),
169
+ );
166
170
  store.dispatch(
167
171
  setConsentData(gppSection, formatConsentString(config, newState)),
168
172
  );
@@ -183,7 +187,7 @@ export const makeMiddleware: IabMiddlewareFactory = (
183
187
  osanoLogger.info(`Setting new consent string -> ${value}`);
184
188
  const consent = parseConsentString(value);
185
189
 
186
- setStorage(storageKey, value);
190
+ setCustomIABKey(storageKey, value);
187
191
 
188
192
  const consentData = {
189
193
  tcString: value,
@@ -1,4 +1,4 @@
1
- import { CLEAR_CONSENT, RELOAD, SAVE_BEGIN, SET_CONFIG } from '../../actions';
1
+ import { CLEAR_CONSENT, RELOAD, SET_CONFIG } from '../../actions';
2
2
  import type { OsanoAction, OsanoState } from '../../types/store';
3
3
  import {
4
4
  SET_CONSENT,
@@ -21,8 +21,6 @@ import {
21
21
  import type { Config } from '../../types/consent-config';
22
22
  import type { IabInitOptions } from './types';
23
23
  import type { IabState } from '../types';
24
- import { Platform } from 'react-native';
25
- import { setStorage } from '../../native/OsanoCmp';
26
24
 
27
25
  export const initialState = {
28
26
  iab: {
@@ -91,7 +89,7 @@ const updateOptions = (
91
89
  };
92
90
 
93
91
  export default function makeReducer(initOptions: IabInitOptions) {
94
- const { createConsentPayload, gppSection, version } = initOptions;
92
+ const { createConsentPayload, version } = initOptions;
95
93
  return (state: OsanoState & IabState, action: OsanoAction) => {
96
94
  const { type, payload } = action;
97
95
  switch (type) {
@@ -135,31 +133,6 @@ export default function makeReducer(initOptions: IabInitOptions) {
135
133
  };
136
134
  }
137
135
 
138
- case SAVE_BEGIN: {
139
- const config = state.config;
140
- if (config?.configId && config.iabEnabled) {
141
- const consentPayload = createConsentPayload(state);
142
- switch (Platform.OS) {
143
- case 'ios':
144
- case 'android':
145
- setStorage(
146
- `${gppSection}_${config.configId}`,
147
- JSON.stringify(consentPayload),
148
- );
149
- break;
150
- default:
151
- try {
152
- window.localStorage.setItem(
153
- `${gppSection}_${config.configId}`,
154
- JSON.stringify(consentPayload),
155
- );
156
- } catch {}
157
- break;
158
- }
159
- }
160
- return state;
161
- }
162
-
163
136
  case CLEAR_CONSENT: {
164
137
  const consentPayload = createConsentPayload();
165
138
  return {
package/src/index.tsx CHANGED
@@ -2,6 +2,7 @@ import React, { memo, useCallback, useEffect, useMemo, useRef } from 'react';
2
2
  import { Platform, UIManager } from 'react-native';
3
3
  import {
4
4
  CLEAR_CONSENT,
5
+ SAVE_BEGIN,
5
6
  reload,
6
7
  setConfig,
7
8
  setLocale,
@@ -105,7 +106,13 @@ export const Osano: React.FunctionComponent<
105
106
  }),
106
107
  );
107
108
  }
108
- return recordConsent(consentManager.current, consentedCategories);
109
+ dispatch({ type: SAVE_BEGIN, payload: consentedCategories });
110
+ return recordConsent(consentManager.current, consentedCategories).then(
111
+ (recordedConsent) => {
112
+ consentManager.current.triggerGoogleConsentUpdate(recordedConsent);
113
+ return recordedConsent;
114
+ },
115
+ );
109
116
  },
110
117
  [],
111
118
  );
@@ -208,6 +215,7 @@ export const Osano: React.FunctionComponent<
208
215
  })
209
216
  .then((reloadProps) => {
210
217
  // We need to reset the state when the configId or customerId changes
218
+ const consentInvalidated = consentManager.current.consentInvalidated;
211
219
  dispatch(
212
220
  reload({
213
221
  // Pass config so init-time opt-out normalization runs on the
@@ -217,8 +225,14 @@ export const Osano: React.FunctionComponent<
217
225
  configId: reloadProps.configId,
218
226
  customerId: reloadProps.customerId,
219
227
  consent: reloadProps.consent,
228
+ // Signals the IAB TCF middleware to wipe (not rehydrate) the
229
+ // stored TC string on this RELOAD; see its RELOAD handler.
230
+ consentInvalidated,
220
231
  }),
221
232
  );
233
+ if (consentManager.current.consentPromptRequired) {
234
+ dispatch(showDialog());
235
+ }
222
236
  return reloadProps;
223
237
  })
224
238
  .catch(() => {
package/src/reducer.ts CHANGED
@@ -127,6 +127,10 @@ export function reducer(state: OsanoState, action: OsanoAction): OsanoState {
127
127
  ...state,
128
128
  consent,
129
129
  savedConsent: { ...consent } as Record<ConsentCategoryType, boolean>,
130
+ // The user just re-consented, so the invalidation is resolved. Clear
131
+ // the marker so a later SET_CONFIG rehydrates this freshly-saved TCF
132
+ // payload instead of wiping it (the IAB middleware wipes while set).
133
+ consentInvalidated: false,
130
134
  };
131
135
  }
132
136
  case CLEAR_CONSENT: {