@osano/osano-cmp-react-native 0.9.0 → 0.10.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 (107) hide show
  1. package/lib/typescript/src/iab/gpp/api.d.ts +28 -0
  2. package/lib/typescript/src/iab/gpp/api.d.ts.map +1 -0
  3. package/lib/typescript/src/iab/gpp/consent.d.ts +24 -0
  4. package/lib/typescript/src/iab/gpp/consent.d.ts.map +1 -0
  5. package/lib/typescript/src/iab/gpp/constants.d.ts +37 -0
  6. package/lib/typescript/src/iab/gpp/constants.d.ts.map +1 -0
  7. package/lib/typescript/src/iab/gpp/encoders/AbstractBase64UrlEncoder.d.ts +28 -0
  8. package/lib/typescript/src/iab/gpp/encoders/AbstractBase64UrlEncoder.d.ts.map +1 -0
  9. package/lib/typescript/src/iab/gpp/encoders/BooleanEncoder.d.ts +34 -0
  10. package/lib/typescript/src/iab/gpp/encoders/BooleanEncoder.d.ts.map +1 -0
  11. package/lib/typescript/src/iab/gpp/encoders/CompressedBase64UrlEncoder.d.ts +28 -0
  12. package/lib/typescript/src/iab/gpp/encoders/CompressedBase64UrlEncoder.d.ts.map +1 -0
  13. package/lib/typescript/src/iab/gpp/encoders/DatetimeEncoder.d.ts +28 -0
  14. package/lib/typescript/src/iab/gpp/encoders/DatetimeEncoder.d.ts.map +1 -0
  15. package/lib/typescript/src/iab/gpp/encoders/EncodableOptimizedFixedRange.d.ts +16 -0
  16. package/lib/typescript/src/iab/gpp/encoders/EncodableOptimizedFixedRange.d.ts.map +1 -0
  17. package/lib/typescript/src/iab/gpp/encoders/FibonacciIntegerEncoder.d.ts +28 -0
  18. package/lib/typescript/src/iab/gpp/encoders/FibonacciIntegerEncoder.d.ts.map +1 -0
  19. package/lib/typescript/src/iab/gpp/encoders/FibonacciIntegerRangeEncoder.d.ts +28 -0
  20. package/lib/typescript/src/iab/gpp/encoders/FibonacciIntegerRangeEncoder.d.ts.map +1 -0
  21. package/lib/typescript/src/iab/gpp/encoders/FixedBitfieldEncoder.d.ts +28 -0
  22. package/lib/typescript/src/iab/gpp/encoders/FixedBitfieldEncoder.d.ts.map +1 -0
  23. package/lib/typescript/src/iab/gpp/encoders/FixedIdBitMapEncoder.d.ts +6 -0
  24. package/lib/typescript/src/iab/gpp/encoders/FixedIdBitMapEncoder.d.ts.map +1 -0
  25. package/lib/typescript/src/iab/gpp/encoders/FixedIntegerEncoder.d.ts +28 -0
  26. package/lib/typescript/src/iab/gpp/encoders/FixedIntegerEncoder.d.ts.map +1 -0
  27. package/lib/typescript/src/iab/gpp/encoders/FixedIntegerListEncoder.d.ts +28 -0
  28. package/lib/typescript/src/iab/gpp/encoders/FixedIntegerListEncoder.d.ts.map +1 -0
  29. package/lib/typescript/src/iab/gpp/encoders/FixedIntegerRangeEncoder.d.ts +28 -0
  30. package/lib/typescript/src/iab/gpp/encoders/FixedIntegerRangeEncoder.d.ts.map +1 -0
  31. package/lib/typescript/src/iab/gpp/encoders/FixedStringEncoder.d.ts +26 -0
  32. package/lib/typescript/src/iab/gpp/encoders/FixedStringEncoder.d.ts.map +1 -0
  33. package/lib/typescript/src/iab/gpp/encoders/TraditionalBase64UrlEncoder.d.ts +28 -0
  34. package/lib/typescript/src/iab/gpp/encoders/TraditionalBase64UrlEncoder.d.ts.map +1 -0
  35. package/lib/typescript/src/iab/gpp/encoders/errors.d.ts +19 -0
  36. package/lib/typescript/src/iab/gpp/encoders/errors.d.ts.map +1 -0
  37. package/lib/typescript/src/iab/gpp/encoders/index.d.ts +16 -0
  38. package/lib/typescript/src/iab/gpp/encoders/index.d.ts.map +1 -0
  39. package/lib/typescript/src/iab/gpp/encoders/types.d.ts +5 -0
  40. package/lib/typescript/src/iab/gpp/encoders/types.d.ts.map +1 -0
  41. package/lib/typescript/src/iab/gpp/index.d.ts +10 -0
  42. package/lib/typescript/src/iab/gpp/index.d.ts.map +1 -0
  43. package/lib/typescript/src/iab/gpp/reducer.d.ts +6 -0
  44. package/lib/typescript/src/iab/gpp/reducer.d.ts.map +1 -0
  45. package/lib/typescript/src/iab/gpp/selectors.d.ts +6 -0
  46. package/lib/typescript/src/iab/gpp/selectors.d.ts.map +1 -0
  47. package/lib/typescript/src/iab/gpp/types.d.ts +3 -0
  48. package/lib/typescript/src/iab/gpp/types.d.ts.map +1 -0
  49. package/lib/typescript/src/iab/gpp/v1/constants.d.ts +9 -0
  50. package/lib/typescript/src/iab/gpp/v1/constants.d.ts.map +1 -0
  51. package/lib/typescript/src/iab/gpp/v1/index.d.ts +19 -0
  52. package/lib/typescript/src/iab/gpp/v1/index.d.ts.map +1 -0
  53. package/lib/typescript/src/iab/usp/api.d.ts +4 -0
  54. package/lib/typescript/src/iab/usp/api.d.ts.map +1 -0
  55. package/lib/typescript/src/iab/usp/consent.d.ts +13 -0
  56. package/lib/typescript/src/iab/usp/consent.d.ts.map +1 -0
  57. package/lib/typescript/src/iab/usp/constants.d.ts +77 -0
  58. package/lib/typescript/src/iab/usp/constants.d.ts.map +1 -0
  59. package/lib/typescript/src/iab/usp/index.d.ts +10 -0
  60. package/lib/typescript/src/iab/usp/index.d.ts.map +1 -0
  61. package/lib/typescript/src/iab/usp/reducer.d.ts +13 -0
  62. package/lib/typescript/src/iab/usp/reducer.d.ts.map +1 -0
  63. package/lib/typescript/src/iab/usp/selectors.d.ts +9 -0
  64. package/lib/typescript/src/iab/usp/selectors.d.ts.map +1 -0
  65. package/lib/typescript/src/iab/usp/types.d.ts +5 -0
  66. package/lib/typescript/src/iab/usp/types.d.ts.map +1 -0
  67. package/lib/typescript/src/iab/usp/v1/constants.d.ts +9 -0
  68. package/lib/typescript/src/iab/usp/v1/constants.d.ts.map +1 -0
  69. package/lib/typescript/src/iab/usp/v1/index.d.ts +16 -0
  70. package/lib/typescript/src/iab/usp/v1/index.d.ts.map +1 -0
  71. package/package.json +2 -6
  72. package/src/iab/gpp/api.js +253 -0
  73. package/src/iab/gpp/consent.js +114 -0
  74. package/src/iab/gpp/constants.js +49 -0
  75. package/src/iab/gpp/encoders/AbstractBase64UrlEncoder.ts +89 -0
  76. package/src/iab/gpp/encoders/BooleanEncoder.ts +39 -0
  77. package/src/iab/gpp/encoders/CompressedBase64UrlEncoder.ts +41 -0
  78. package/src/iab/gpp/encoders/DatetimeEncoder.ts +46 -0
  79. package/src/iab/gpp/encoders/EncodableOptimizedFixedRange.ts +213 -0
  80. package/src/iab/gpp/encoders/FibonacciIntegerEncoder.ts +81 -0
  81. package/src/iab/gpp/encoders/FibonacciIntegerRangeEncoder.ts +122 -0
  82. package/src/iab/gpp/encoders/FixedBitfieldEncoder.ts +59 -0
  83. package/src/iab/gpp/encoders/FixedIdBitMapEncoder.ts +30 -0
  84. package/src/iab/gpp/encoders/FixedIntegerEncoder.ts +61 -0
  85. package/src/iab/gpp/encoders/FixedIntegerListEncoder.ts +87 -0
  86. package/src/iab/gpp/encoders/FixedIntegerRangeEncoder.ts +102 -0
  87. package/src/iab/gpp/encoders/FixedStringEncoder.ts +74 -0
  88. package/src/iab/gpp/encoders/LICENSE-IABTechLab +176 -0
  89. package/src/iab/gpp/encoders/TraditionalBase64UrlEncoder.ts +38 -0
  90. package/src/iab/gpp/encoders/errors.ts +41 -0
  91. package/src/iab/gpp/encoders/index.ts +15 -0
  92. package/src/iab/gpp/encoders/types.ts +5 -0
  93. package/src/iab/gpp/index.js +9 -0
  94. package/src/iab/gpp/reducer.js +7 -0
  95. package/src/iab/gpp/selectors.js +21 -0
  96. package/src/iab/gpp/types.ts +3 -0
  97. package/src/iab/gpp/v1/constants.js +7 -0
  98. package/src/iab/gpp/v1/index.js +73 -0
  99. package/src/iab/usp/api.js +56 -0
  100. package/src/iab/usp/consent.js +150 -0
  101. package/src/iab/usp/constants.js +40 -0
  102. package/src/iab/usp/index.js +9 -0
  103. package/src/iab/usp/reducer.js +107 -0
  104. package/src/iab/usp/selectors.js +31 -0
  105. package/src/iab/usp/types.ts +4 -0
  106. package/src/iab/usp/v1/constants.js +10 -0
  107. package/src/iab/usp/v1/index.js +54 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../../../../src/iab/gpp/selectors.js"],"names":[],"mappings":"AAIO,iDAC2D;AAC3D,uDAOL;AACK,mDACuD;AACvD,uEAEM;AACN,gEACgD"}
@@ -0,0 +1,3 @@
1
+ export type Gpp = unknown;
2
+ export type Gpp_v2 = Gpp;
3
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/iab/gpp/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG,GAAG,OAAO,CAAC;AAE1B,MAAM,MAAM,MAAM,GAAG,GAAG,CAAC"}
@@ -0,0 +1,9 @@
1
+ export const apiName: "__gpp";
2
+ export const gppSection: "gpp";
3
+ export const iframeName: "__gppLocator";
4
+ export const version: "1.0";
5
+ export namespace initOptions {
6
+ export { gppSection };
7
+ export { version };
8
+ }
9
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../../src/iab/gpp/v1/constants.js"],"names":[],"mappings":"AAAA,8BAA+B;AAE/B,+BAAgC;AAChC,wCAAyC;AACzC,4BAA6B"}
@@ -0,0 +1,19 @@
1
+ export function createMiddleware({ dispatchEvent }?: {
2
+ dispatchEvent: any;
3
+ }): (store: any) => (next: any) => (action: any) => any;
4
+ export default v1;
5
+ declare namespace v1 {
6
+ export let api: {
7
+ bind: (store: any, allApis: any) => (command: any, callback: any, parameter: any) => any;
8
+ dispatch: (data: any) => void;
9
+ };
10
+ export { apiName };
11
+ export { createMiddleware };
12
+ export { gppSection };
13
+ export { iframeName };
14
+ export let postMessageEventHandler: any;
15
+ }
16
+ import { apiName } from './constants';
17
+ import { gppSection } from './constants';
18
+ import { iframeName } from './constants';
19
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/iab/gpp/v1/index.js"],"names":[],"mappings":"AAYA;;wDAiDC;;;;;;;;;;;;;wBA7D4D,aAAa;2BAAb,aAAa;2BAAb,aAAa"}
@@ -0,0 +1,4 @@
1
+ export default function makeApi(initOptions: any): {
2
+ bind: (store: any) => (command: string, version: number, callback: requestCallback, parameter?: string | undefined) => any;
3
+ };
4
+ //# sourceMappingURL=api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/api.js"],"names":[],"mappings":"AAEA;oCAMa,MAAM,WACN,MAAM,YACN,eAAe;EA6C3B"}
@@ -0,0 +1,13 @@
1
+ export function makeParseConsentString({ version: providedVersion }?: {
2
+ version?: number | undefined;
3
+ }): (uspString: any) => {
4
+ version: any;
5
+ notified: any;
6
+ signatory: any;
7
+ optOut: any;
8
+ };
9
+ export function makeGetField(initOptions?: {}): (state: any, field: any) => string | 1 | undefined;
10
+ export function makeFormatConsentString(initOptions?: {}): string;
11
+ export function makeConsentFromOptions(initOptions: any): import("./constants").USPConsent;
12
+ export function getConsentDataObject(initOptions: any): import("./constants").USPData;
13
+ //# sourceMappingURL=consent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"consent.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/consent.js"],"names":[],"mappings":"AAKO;;;;;;;EAqBL;AAEK,mGAsBL;AAQK,2DAFM,MAAM,CA8BjB;AAQK,0DAFM,OAAO,aAAa,EAAE,UAAU,CA6B5C;AAQM,wDAFM,OAAO,aAAa,EAAE,OAAO,CAsBzC"}
@@ -0,0 +1,77 @@
1
+ export function toYesNoUnFromBool(b: any): "-" | "N" | "Y";
2
+ export function toBoolFromYesNoUn(yn: any): boolean | undefined;
3
+ /**
4
+ * USPData object supplied to the __uspapi callback method
5
+ */
6
+ export type USPData = {
7
+ /**
8
+ * - indicates the U.S. Privacy spec version
9
+ */
10
+ version: number;
11
+ /**
12
+ * - Indicates the privacy application and agreement
13
+ * - String; agreement: “1YNN”, not applicable: “1---”
14
+ * - Number; 1 applies, 0 doesn’t apply, -1 not set
15
+ */
16
+ uspString: (number | string);
17
+ };
18
+ /**
19
+ * USPConsent object used for creating the USPData `uspString`
20
+ */
21
+ export type USPConsent = {
22
+ /**
23
+ * - indicates the U.S. Privacy spec version
24
+ */
25
+ version: number;
26
+ /**
27
+ * - Indicates that the end user has been notified of consent agreement
28
+ */
29
+ notified: (boolean | undefined);
30
+ /**
31
+ * - Indicates that the end user has opted out of data resale
32
+ */
33
+ optOut: boolean;
34
+ /**
35
+ * - Indicates that the provider has opted into the LSPA from IAB
36
+ */
37
+ signatory: (boolean | undefined);
38
+ };
39
+ /**
40
+ * USPAPIPostMessageData object
41
+ */
42
+ export type USPAPIPostMessageData = {
43
+ /**
44
+ * - The command to be executed by the API
45
+ */
46
+ command: string;
47
+ /**
48
+ * - Optional parameter to be passed to the `command`
49
+ */
50
+ parameter: string;
51
+ /**
52
+ * - The version number that the response should adhere to
53
+ */
54
+ version: number;
55
+ /**
56
+ * - The callback method that should be called with the command result
57
+ */
58
+ callId: string;
59
+ };
60
+ /**
61
+ * USPAPIPostMessageEvent object supplied to the __uspapiLocator iframe postMessage handler
62
+ */
63
+ export type USPAPIPostMessageEvent = {
64
+ /**
65
+ * - The post message data as object or JSON string
66
+ */
67
+ data: (string | USPAPIPostMessageData);
68
+ /**
69
+ * - Indicates the origin of the window making the post
70
+ */
71
+ origin: string;
72
+ /**
73
+ * - The window which posted the message
74
+ */
75
+ source: Window;
76
+ };
77
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/constants.js"],"names":[],"mappings":"AAmCO,2DAAsE;AACtE,gEAGkC;;;;;;;;aApC3B,MAAM;;;;;;eACN,CAAC,MAAM,GAAC,MAAM,CAAC;;;;;;;;;aAQf,MAAM;;;;cACN,CAAC,UAAQ,SAAS,CAAC;;;;;;;;eAEnB,CAAC,UAAQ,SAAS,CAAC;;;;;;;;;aAMnB,MAAM;;;;eACN,MAAM;;;;aACN,MAAM;;;;YACN,MAAM;;;;;;;;;UAMN,CAAC,MAAM,GAAC,qBAAqB,CAAC;;;;YAC9B,MAAM;;;;YACN,MAAM"}
@@ -0,0 +1,10 @@
1
+ declare namespace _default {
2
+ export { reducer };
3
+ export namespace versions {
4
+ export { v1_0 };
5
+ }
6
+ }
7
+ export default _default;
8
+ import reducer from './reducer';
9
+ import v1_0 from './v1';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/index.js"],"names":[],"mappings":";;;;;;;oBAAoB,WAAW;iBACd,MAAM"}
@@ -0,0 +1,13 @@
1
+ export namespace initialState {
2
+ namespace iab {
3
+ namespace usp {
4
+ let ccpaApplies: boolean;
5
+ let notified: undefined;
6
+ let signatory: undefined;
7
+ let optOut: boolean;
8
+ }
9
+ }
10
+ }
11
+ declare const _default: any;
12
+ export default _default;
13
+ //# sourceMappingURL=reducer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reducer.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/reducer.js"],"names":[],"mappings":""}
@@ -0,0 +1,9 @@
1
+ export const DOMAIN: "iab.usp";
2
+ export function getStore(state: any): any;
3
+ export function doesCCPAApply(state: any): boolean;
4
+ export function getConsentString(state: any, { gppSection, version: providedVersion }?: {
5
+ gppSection: any;
6
+ version: any;
7
+ }): string;
8
+ export function getOptOut(state: any): any;
9
+ //# sourceMappingURL=selectors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selectors.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/selectors.js"],"names":[],"mappings":"AAIA,+BAAgC;AAEzB,0CAAgD;AAChD,mDACsD;AAEtD;;;WAmBN;AACM,2CAAiD"}
@@ -0,0 +1,5 @@
1
+ export type Usp = {
2
+ enabled: boolean;
3
+ ccpaApplies: boolean;
4
+ };
5
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../../src/iab/usp/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,GAAG,GAAG;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,WAAW,EAAE,OAAO,CAAC;CACrB,CAAC"}
@@ -0,0 +1,9 @@
1
+ export const apiName: "__uspapi";
2
+ export const gppSection: "uspv1";
3
+ export const iframeName: "__uspapiLocator";
4
+ export const version: 1;
5
+ export namespace initOptions {
6
+ export { gppSection };
7
+ export { version };
8
+ }
9
+ //# sourceMappingURL=constants.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../../../../../src/iab/usp/v1/constants.js"],"names":[],"mappings":"AAAA,iCAAkC;AAElC,iCAAkC;AAClC,2CAA4C;AAC5C,wBAAyB"}
@@ -0,0 +1,16 @@
1
+ export default v1;
2
+ declare namespace v1 {
3
+ export let api: {
4
+ bind: (store: any) => (command: string, version: number, callback: requestCallback, parameter?: string | undefined) => any;
5
+ };
6
+ export { apiName };
7
+ export { createMiddleware };
8
+ export { gppSection };
9
+ export { iframeName };
10
+ export let postMessageEventHandler: any;
11
+ }
12
+ import { apiName } from './constants';
13
+ declare function createMiddleware(): (store: any) => (next: any) => (action: any) => any;
14
+ import { gppSection } from './constants';
15
+ import { iframeName } from './constants';
16
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/iab/usp/v1/index.js"],"names":[],"mappings":";;;2EAOQ,eAAe;;;;;;;;wBANsC,aAAa;AAY1E,yFA6BC;2BAzC4D,aAAa;2BAAb,aAAa"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@osano/osano-cmp-react-native",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Package and example for the react-native Osano CMP SDK",
5
5
  "main": "lib/commonjs/index",
6
6
  "module": "lib/module/index",
@@ -24,14 +24,10 @@
24
24
  "!**/__fixtures__",
25
25
  "!**/__mocks__",
26
26
  "!**/.*",
27
- "!src/iab/usp",
28
- "!src/iab/gpp",
29
27
  "!lib/typescript/webdriverio-appium/**",
30
28
  "!lib/typescript/webdriverio-appium/common/**",
31
29
  "!lib/typescript/webdriverio-appium/config/**",
32
- "!lib/typescript/webdriverio-appium/test/**",
33
- "!lib/typescript/src/iab/usp",
34
- "!lib/typescript/src/iab/gpp"
30
+ "!lib/typescript/webdriverio-appium/test/**"
35
31
  ],
36
32
  "scripts": {
37
33
  "example": "yarn workspace osano-cmp-sdk-example",
@@ -0,0 +1,253 @@
1
+ import {
2
+ formatConsentString,
3
+ makeFormatPingData,
4
+ makeParseConsentString,
5
+ } from './consent';
6
+
7
+ import { EventNames } from './constants';
8
+ import { MAX_DATE } from '../../constants';
9
+ import { getSupportedApis } from './selectors';
10
+
11
+ /**
12
+ * An object that contains the client callback and metadata.
13
+ * @typedef {Object} EventSubscriber
14
+ * @property {number} version - The version of the API that the subscriber is
15
+ * listening to.
16
+ * @property {function} callback - The callback function that the subscriber
17
+ * provided. The signature should match the API version.
18
+ */
19
+
20
+ /**
21
+ * The listener ID is a number that is used to identify a subscriber. It is both
22
+ * a key in the eventSubscribers map and a property that is given back to the
23
+ * subscriber. It must not change for the lifetime of the subscriber.
24
+ * @typedef {number} ListenerId
25
+ */
26
+
27
+ /**
28
+ * A map of listener IDs to event subscribers.
29
+ * @type {Map<ListenerId, EventSubscriber>}
30
+ */
31
+ const eventSubscribers = new Map();
32
+
33
+ // Allows us to clear the event subscribers in tests
34
+ export const _clearEventSubscribers =
35
+ process.env.NODE_ENV === 'jest' ? () => eventSubscribers.clear() : undefined;
36
+
37
+ const createListenerId = () => {
38
+ let inc = 0;
39
+ let listenerId = MAX_DATE - Date.now();
40
+ do {
41
+ listenerId -= inc++;
42
+ } while (eventSubscribers.has(listenerId));
43
+
44
+ return listenerId;
45
+ };
46
+
47
+ /**
48
+ * Responsible for dispatching events to the subscribers.
49
+ * @param {number} apiVersion - The version of the API as defined by the IAB.
50
+ * @param {object} data - The data to dispatch to the subscribers.
51
+ */
52
+ const makeDispatch = apiVersion =>
53
+ function dispatch(data) {
54
+ eventSubscribers.forEach(({ version, callback }, listenerId) => {
55
+ apiVersion === version &&
56
+ callback({
57
+ ...data,
58
+ listenerId,
59
+ });
60
+ });
61
+ };
62
+
63
+ /**
64
+ * The GPP has its own API but it can also call the older APIs. This function
65
+ * adapts the newer GPP call signature to the older APIs.
66
+ */
67
+ const adaptedApis = new Map();
68
+
69
+ // Allows us to clear the event subscribers in tests
70
+ export const _clearAdaptedApis =
71
+ process.env.NODE_ENV === 'jest' ? () => adaptedApis.clear() : undefined;
72
+
73
+ const getAdaptedApi = (clientApi, api) => {
74
+ // cache the adapted API so that we aren't creating a new function on every call
75
+ const adaptedApi = adaptedApis.get(clientApi);
76
+ if (adaptedApi) {
77
+ return adaptedApi;
78
+ }
79
+
80
+ // If the API is not available, throw an error. If the requested API is the
81
+ // GPP, throw an error (the GPP should never call itself as a sub-API).
82
+ if (!api || clientApi === 'gpp') {
83
+ throw new Error(`API ${clientApi} is not available`);
84
+ }
85
+
86
+ switch (clientApi) {
87
+ // pre-GPP APIs use the signature (command, version, callback, parameter)
88
+ case 'tcfeuv2':
89
+ adaptedApis.set(clientApi, (command, callback, parameter) =>
90
+ api(command, 2, callback, parameter),
91
+ );
92
+ break;
93
+ case 'uspv1':
94
+ adaptedApis.set(clientApi, (command, callback, parameter) =>
95
+ api(command, 1, callback, parameter),
96
+ );
97
+ break;
98
+ default:
99
+ adaptedApis.set(clientApi, api);
100
+ }
101
+
102
+ return adaptedApis.get(clientApi);
103
+ };
104
+
105
+ export default function makeApi(initOptions) {
106
+ const formatPingData = makeFormatPingData(initOptions);
107
+ const parseConsentString = makeParseConsentString(initOptions);
108
+ const makeEventSubscriber = callback => ({
109
+ version: initOptions.version,
110
+ callback,
111
+ });
112
+ const eventListenerReturn = (state, eventName, listenerId, data) => ({
113
+ eventName,
114
+ listenerId,
115
+ data,
116
+ pingData: formatPingData(state),
117
+ });
118
+ const dispatch = makeDispatch(initOptions.version);
119
+
120
+ function bind(store, allApis) {
121
+ const subApiSubscribers = new Map();
122
+ // The GPP spec says that events dispatched from section APIs should be
123
+ // dispatched from the GPP API. To do that, we'll subscribe to the
124
+ // events from the other APIs and re-dispatch them from here.
125
+ const initDispatchAggregator = () => {
126
+ if (subApiSubscribers.size > 0) {
127
+ // We have already initialized the dispatch aggregator
128
+ return;
129
+ }
130
+
131
+ const supportedApis = getSupportedApis(store.getState());
132
+ allApis.forEach((api, section) => {
133
+ if (!supportedApis.includes(section)) {
134
+ return;
135
+ }
136
+
137
+ const subscriber = data => {
138
+ // remove our own listener ID from the data object
139
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
140
+ const { listenerId, ...rest } = data;
141
+
142
+ dispatch({
143
+ // Other APIs don't currently have event names but if
144
+ // they are added this field should be dot-separated,
145
+ // e.g. `${section}.${data.eventName}`
146
+ eventName: section,
147
+ data: rest,
148
+ pingData: formatPingData(store.getState()),
149
+ });
150
+ };
151
+ subApiSubscribers.set(section, subscriber);
152
+ getAdaptedApi(section, api)('addEventListener', subscriber);
153
+ });
154
+ };
155
+
156
+ return function gppApi(command, callback, parameter) {
157
+ const state = store.getState();
158
+
159
+ switch (command) {
160
+ case 'ping': {
161
+ return formatPingData(state);
162
+ }
163
+
164
+ case 'addEventListener': {
165
+ // We wait to initialize the dispatch aggregator until there
166
+ // is at least one client event listener. Saves a little
167
+ // performance and ensures that all APIs are available.
168
+ initDispatchAggregator();
169
+ const listenerId = createListenerId();
170
+
171
+ try {
172
+ if (typeof callback !== 'function') {
173
+ throw new Error('Callback must be a function');
174
+ }
175
+ eventSubscribers.set(listenerId, makeEventSubscriber(callback));
176
+ const returnObject = eventListenerReturn(
177
+ state,
178
+ EventNames.LISTENER_REGISTERED,
179
+ listenerId,
180
+ true,
181
+ );
182
+
183
+ return returnObject;
184
+ } catch {
185
+ eventSubscribers.delete(listenerId);
186
+ return eventListenerReturn(
187
+ state,
188
+ EventNames.LISTENER_REGISTERED,
189
+ 0,
190
+ false,
191
+ );
192
+ }
193
+ }
194
+
195
+ case 'removeEventListener': {
196
+ const listenerId = parseInt(parameter, 10);
197
+ const removed = eventSubscribers.delete(listenerId);
198
+ return eventListenerReturn(
199
+ state,
200
+ EventNames.LISTENER_REMOVED,
201
+ listenerId,
202
+ removed,
203
+ );
204
+ }
205
+
206
+ case 'hasSection': {
207
+ const section = parameter;
208
+ return getSupportedApis(state).includes(`${section}`);
209
+ }
210
+
211
+ /** Note that this command throws if the requested section
212
+ * doesn't exist. The spec does not define what should happen in
213
+ * this case. Returning nothing could be misleading so an error
214
+ * is clearer. */
215
+ case 'getSection': {
216
+ const clientApi = parameter;
217
+ const sectionApi = getAdaptedApi(clientApi, allApis.get(clientApi));
218
+ return sectionApi('getSection');
219
+ }
220
+
221
+ /** Note that as above, this command throws if the requested
222
+ * section does not exist and returns undefined if the field
223
+ * doesn't exist. The spec is again silent on this case. */
224
+ case 'getField': {
225
+ const [clientApi, ...fieldPath] = parameter.split('.');
226
+ const sectionApi = getAdaptedApi(clientApi, allApis.get(clientApi));
227
+ return sectionApi('getField', undefined, fieldPath.join('.'));
228
+ }
229
+
230
+ case 'getGPPData': {
231
+ const gppString = formatConsentString(state);
232
+ return gppString ? parseConsentString(gppString, state) : undefined;
233
+ }
234
+
235
+ default: {
236
+ const mark = command.indexOf('.');
237
+ if (mark < 0) {
238
+ throw new Error(`Invalid command: ${command}`);
239
+ }
240
+ const clientApi = command.substring(0, mark);
241
+ const apiCommand = command.substring(mark + 1);
242
+ const sectionApi = getAdaptedApi(clientApi, allApis.get(clientApi));
243
+ return sectionApi(apiCommand, callback, parameter);
244
+ }
245
+ }
246
+ };
247
+ }
248
+
249
+ return {
250
+ bind,
251
+ dispatch,
252
+ };
253
+ }
@@ -0,0 +1,114 @@
1
+ import { CmpDisplayStatusCodes, CmpStatusCodes, SECTIONS } from './constants';
2
+ import {
3
+ decode as base64Decode,
4
+ encode as base64Encode,
5
+ } from './encoders/CompressedBase64UrlEncoder';
6
+ import {
7
+ doesGDPRApply,
8
+ getConsentString,
9
+ getSupportedApis,
10
+ isBrowsingFrom,
11
+ isUiVisible,
12
+ } from './selectors';
13
+ import {
14
+ decode as fibRangeDecode,
15
+ encode as fibRangeEncode,
16
+ } from './encoders/FibonacciIntegerRangeEncoder';
17
+
18
+ import { CMP_ID } from '../constants';
19
+
20
+ const ERROR_MESSAGE = 'Invalid GPP string';
21
+
22
+ /* A note on the GPP version number: According to the GPP spec, the GPP string's
23
+ * header can only contain an integer version number. However, the API spec for
24
+ * the PingReturn object requires that the GPP version number is in the format
25
+ * Major.Minor (e.g. 1.0). It's not a problem for now but will be interesting if
26
+ * and when they introduce a version 1.1.
27
+ */
28
+ const HEADER_PREFIX = 'DB'; // Section 3 ('D'), GPP v1 ('B')
29
+
30
+ export const isSectionApplicable = (sectionId, state) => {
31
+ switch (sectionId) {
32
+ // case 1 is TCF v1 and is unsupported
33
+ case 2: // TCF EU v2
34
+ return doesGDPRApply(state);
35
+ // cases 3 and 4 are GPP header and integrity sections and are not applicable
36
+ case 5: // TCF CA
37
+ return isBrowsingFrom(state, 'ca');
38
+ case 6: // USPrivacy v1
39
+ // case 7: // US National
40
+ return isBrowsingFrom(state, 'us');
41
+ // We do not implement the GPP US-state spec
42
+ // case 8: // US California
43
+ // return isBrowsingFrom(state, 'us-ca');
44
+ // case 9: // US Virginia
45
+ // return isBrowsingFrom(state, 'us-va');
46
+ // case 10: // US Colorado
47
+ // return isBrowsingFrom(state, 'us-co');
48
+ // case 11: // US Utah
49
+ // return isBrowsingFrom(state, 'us-ut');
50
+ // case 12: // US Connecticut
51
+ // return isBrowsingFrom(state, 'us-ct');
52
+ default:
53
+ return false;
54
+ }
55
+ };
56
+
57
+ export const makeFormatPingData = initOptions => state => ({
58
+ gppVersion: initOptions.version, // '1.0', see note above
59
+ cmpStatus: CmpStatusCodes.LOADED,
60
+ cmpDisplayStatus: isUiVisible(state)
61
+ ? CmpDisplayStatusCodes.VISIBLE
62
+ : CmpDisplayStatusCodes.HIDDEN,
63
+ supportedAPIs: getSupportedApis(state),
64
+ cmpId: CMP_ID,
65
+ });
66
+
67
+ export const makeParseConsentString = initOptions => (gppString, state) => {
68
+ const [header, ...sections] = gppString.split('~');
69
+
70
+ // All GPPv1 strings must start with 'DB'
71
+ if (header.substring(0, 2) !== HEADER_PREFIX) {
72
+ throw new Error(`${ERROR_MESSAGE}: Invalid header`);
73
+ }
74
+
75
+ const expectedSections = fibRangeDecode(base64Decode(header.substring(2)));
76
+
77
+ if (sections.length !== expectedSections.length) {
78
+ throw new Error(
79
+ `${ERROR_MESSAGE}: Number of sections does not match header`,
80
+ );
81
+ }
82
+
83
+ return {
84
+ sectionId: 3,
85
+ gppVersion: 1, // see note above
86
+ sectionList: expectedSections,
87
+ applicableSections: expectedSections.filter(sectionId =>
88
+ isSectionApplicable(sectionId, state),
89
+ ),
90
+ gppString,
91
+ pingData: makeFormatPingData(initOptions)(state),
92
+ };
93
+ };
94
+
95
+ export const formatConsentString = state => {
96
+ const consentStrings = getSupportedApis(state)
97
+ .map(section => ({
98
+ sectionId: SECTIONS[`${section}`],
99
+ consentString: getConsentString(state, section),
100
+ }))
101
+ .filter(({ consentString }) => consentString !== undefined)
102
+ .sort((a, b) => a.sectionId - b.sectionId);
103
+
104
+ const header = `${HEADER_PREFIX}${base64Encode(
105
+ fibRangeEncode(consentStrings.map(({ sectionId }) => sectionId)),
106
+ )}`;
107
+
108
+ const sections = [
109
+ header,
110
+ ...consentStrings.map(({ consentString }) => consentString),
111
+ ];
112
+
113
+ return sections.join('~');
114
+ };