@osano/osano-cmp-react-native 0.11.0 → 0.12.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 (68) hide show
  1. package/README.md +1 -0
  2. package/lib/commonjs/ConsentManager.js +29 -1
  3. package/lib/commonjs/ConsentManager.js.map +1 -1
  4. package/lib/commonjs/context.js +2 -1
  5. package/lib/commonjs/context.js.map +1 -1
  6. package/lib/commonjs/iab/tcf/consent.js +0 -5
  7. package/lib/commonjs/iab/tcf/consent.js.map +1 -1
  8. package/lib/commonjs/index.js +25 -6
  9. package/lib/commonjs/index.js.map +1 -1
  10. package/lib/commonjs/selectors.js +1 -1
  11. package/lib/commonjs/selectors.js.map +1 -1
  12. package/lib/commonjs/services/consent.js +54 -3
  13. package/lib/commonjs/services/consent.js.map +1 -1
  14. package/lib/commonjs/utils/EventEmitter.js +0 -2
  15. package/lib/commonjs/utils/EventEmitter.js.map +1 -1
  16. package/lib/commonjs/utils/Translator.js +2 -2
  17. package/lib/commonjs/utils/Translator.js.map +1 -1
  18. package/lib/module/ConsentManager.js +30 -2
  19. package/lib/module/ConsentManager.js.map +1 -1
  20. package/lib/module/context.js +2 -1
  21. package/lib/module/context.js.map +1 -1
  22. package/lib/module/iab/tcf/consent.js +0 -5
  23. package/lib/module/iab/tcf/consent.js.map +1 -1
  24. package/lib/module/index.js +25 -6
  25. package/lib/module/index.js.map +1 -1
  26. package/lib/module/selectors.js +1 -1
  27. package/lib/module/selectors.js.map +1 -1
  28. package/lib/module/services/consent.js +48 -1
  29. package/lib/module/services/consent.js.map +1 -1
  30. package/lib/module/utils/EventEmitter.js +0 -2
  31. package/lib/module/utils/EventEmitter.js.map +1 -1
  32. package/lib/module/utils/Translator.js +2 -2
  33. package/lib/module/utils/Translator.js.map +1 -1
  34. package/lib/typescript/lib/commonjs/ConsentManager.d.ts +2 -1
  35. package/lib/typescript/lib/commonjs/ConsentManager.d.ts.map +1 -1
  36. package/lib/typescript/lib/commonjs/iab/tcf/consent.d.ts.map +1 -1
  37. package/lib/typescript/lib/commonjs/services/consent.d.ts +4 -0
  38. package/lib/typescript/lib/commonjs/services/consent.d.ts.map +1 -1
  39. package/lib/typescript/lib/commonjs/utils/EventEmitter.d.ts.map +1 -1
  40. package/lib/typescript/lib/module/ConsentManager.d.ts +1 -0
  41. package/lib/typescript/lib/module/ConsentManager.d.ts.map +1 -1
  42. package/lib/typescript/lib/module/context.d.ts +1 -0
  43. package/lib/typescript/lib/module/context.d.ts.map +1 -1
  44. package/lib/typescript/lib/module/iab/tcf/consent.d.ts.map +1 -1
  45. package/lib/typescript/lib/module/index.d.ts.map +1 -1
  46. package/lib/typescript/lib/module/services/consent.d.ts +4 -0
  47. package/lib/typescript/lib/module/services/consent.d.ts.map +1 -1
  48. package/lib/typescript/lib/module/utils/EventEmitter.d.ts.map +1 -1
  49. package/lib/typescript/src/ConsentManager.d.ts +1 -0
  50. package/lib/typescript/src/ConsentManager.d.ts.map +1 -1
  51. package/lib/typescript/src/context.d.ts +1 -0
  52. package/lib/typescript/src/context.d.ts.map +1 -1
  53. package/lib/typescript/src/iab/tcf/consent.d.ts.map +1 -1
  54. package/lib/typescript/src/index.d.ts.map +1 -1
  55. package/lib/typescript/src/selectors.d.ts.map +1 -1
  56. package/lib/typescript/src/services/consent.d.ts +12 -1
  57. package/lib/typescript/src/services/consent.d.ts.map +1 -1
  58. package/lib/typescript/src/utils/EventEmitter.d.ts.map +1 -1
  59. package/package.json +1 -1
  60. package/src/ConsentManager.ts +42 -1
  61. package/src/context.ts +8 -6
  62. package/src/iab/tcf/consent.ts +11 -16
  63. package/src/index.tsx +42 -14
  64. package/src/selectors.ts +1 -0
  65. package/src/services/consent.ts +66 -1
  66. package/src/types/consent-config.d.ts +0 -3
  67. package/src/utils/EventEmitter.ts +1 -3
  68. package/src/utils/Translator.ts +15 -15
package/src/selectors.ts CHANGED
@@ -30,6 +30,7 @@ export const isDialogOpen = (state: OsanoState) =>
30
30
 
31
31
  export const isGPCSupportEnabled = (state: OsanoState) =>
32
32
  !!state.config?.gpcSupport &&
33
+ typeof navigator !== 'undefined' &&
33
34
  // Native browser support uses Navigator.prototype
34
35
  (Object.hasOwnProperty.call(navigator, 'globalPrivacyControl') ||
35
36
  // Browser extension support uses the Navigator instance on window
@@ -305,6 +305,71 @@ export const fetchConfig = (customerId: string, configId: string) => {
305
305
  })
306
306
  .catch(() => {
307
307
  // Consent not found or network/server error
308
- return null;
308
+ throw new Error('Error fetching config');
309
309
  });
310
310
  };
311
+
312
+ export const getStoredConfig = async (
313
+ configId: string,
314
+ ): Promise<Config | null> => {
315
+ try {
316
+ const config = await getStorage(`${STORAGE_KEY}_${configId}_config`);
317
+ if (config) {
318
+ return JSON.parse(config) as Config;
319
+ }
320
+ } catch (error) {
321
+ // Failed to retrieve config
322
+ }
323
+ return null;
324
+ };
325
+
326
+ export const storeConfig = async (
327
+ configId: string,
328
+ config: Config,
329
+ ): Promise<void> => {
330
+ try {
331
+ await Promise.all([
332
+ setStorage(`${STORAGE_KEY}_${configId}_config`, JSON.stringify(config)),
333
+ setStorage(
334
+ `${STORAGE_KEY}_${configId}_config_last_stored_at`,
335
+ JSON.stringify(new Date()),
336
+ ),
337
+ ]);
338
+ } catch (error) {
339
+ throw new Error('Failed to store config');
340
+ }
341
+ };
342
+
343
+ export const getConfigLastStoredAt = async (
344
+ configId: string,
345
+ ): Promise<Date | null> => {
346
+ try {
347
+ const lastStoredAt = await getStorage(
348
+ `${STORAGE_KEY}_${configId}_config_last_stored_at`,
349
+ );
350
+ if (lastStoredAt) {
351
+ return new Date(JSON.parse(lastStoredAt));
352
+ }
353
+ } catch (error) {
354
+ // Failed to retrieve last stored at
355
+ }
356
+ return null;
357
+ };
358
+
359
+ /**
360
+ * Determine if a cached config is stale
361
+ *
362
+ * @async
363
+ * @param {string} configId
364
+ * @returns {Promise<boolean>}
365
+ */
366
+ export const hasStaleConfig = async (configId: string): Promise<boolean> => {
367
+ const lastStoredAt = await getConfigLastStoredAt(configId);
368
+ if (!lastStoredAt) {
369
+ return true;
370
+ }
371
+ const now = new Date();
372
+ const diff = now.getTime() - lastStoredAt.getTime();
373
+ const diffInMinutes = Math.floor(diff / 60000);
374
+ return diffInMinutes > 1440; // 24 hours = 1440 minutes
375
+ };
@@ -70,9 +70,6 @@ export type Config = {
70
70
  type?: Flavor;
71
71
  variant: 'one' | 'two' | 'three' | 'four' | 'five' | 'six' | '' | undefined;
72
72
  country: string;
73
- region: string;
74
- iab: Iab;
75
- palette: Palette;
76
73
  additionalLinks: string[][];
77
74
  iabEnabled: boolean;
78
75
  };
@@ -19,7 +19,6 @@ export class EventEmitter {
19
19
  private _events: Record<string, Function[]> = {};
20
20
 
21
21
  on(event: string, listener: Function) {
22
- // console.log('EventEmitter.on', event, listener);
23
22
  if (typeof this._events[event] !== 'object') {
24
23
  this._events[event] = [];
25
24
  }
@@ -29,7 +28,6 @@ export class EventEmitter {
29
28
  }
30
29
 
31
30
  off(event: string, listener: Function) {
32
- // console.log('EventEmitter.off', event, listener);
33
31
  if (typeof this._events[event] === 'object') {
34
32
  const idx = this._events[event]!.indexOf(listener);
35
33
  if (idx > -1) {
@@ -40,7 +38,7 @@ export class EventEmitter {
40
38
 
41
39
  emit(event: string, ...args: unknown[]) {
42
40
  if (typeof this._events[event] === 'object') {
43
- this._events[event]?.forEach(listener => listener.apply(this, args));
41
+ this._events[event]?.forEach((listener) => listener.apply(this, args));
44
42
  }
45
43
  }
46
44
 
@@ -57,7 +57,7 @@ export default class Translator extends EventEmitter {
57
57
  constructor(
58
58
  consentManager: ConsentManager,
59
59
  messages: LocalizedStrings = {},
60
- defaultLocale = 'en'
60
+ defaultLocale = 'en',
61
61
  ) {
62
62
  super();
63
63
  this._consentManager = consentManager;
@@ -103,15 +103,15 @@ export default class Translator extends EventEmitter {
103
103
  load(
104
104
  desiredLocale?: string,
105
105
  onLangLoadSuccess?: () => void,
106
- onLangLoadFailure?: () => void
106
+ onLangLoadFailure?: () => void,
107
107
  ): Promise<PromiseSettledResult<string | undefined>[]> {
108
108
  const allLocales = desiredLocale
109
109
  ? Translator.fallbackLanguages(
110
- desiredLocale.toLowerCase().replace(/_/g, '-')
110
+ desiredLocale.toLowerCase().replace(/_/g, '-'),
111
111
  )
112
- : [];
112
+ : [Translator.DEFAULT_LANGUAGE];
113
113
 
114
- const locale = allLocales?.shift();
114
+ const locale = allLocales.shift();
115
115
  const customerId = this._consentManager.customerId;
116
116
  const configId = this._consentManager.configId;
117
117
  this._langLoadFailureSubscription =
@@ -130,7 +130,7 @@ export default class Translator extends EventEmitter {
130
130
  } else {
131
131
  const localesToTry = [...allLocales];
132
132
  globalPromise = this._loading[locale] = fetchGlobalLocalePhrases(
133
- locale
133
+ locale,
134
134
  )
135
135
  .then((phrases) => {
136
136
  this._currentLocale = locale;
@@ -146,7 +146,7 @@ export default class Translator extends EventEmitter {
146
146
  while (nextLocale) {
147
147
  try {
148
148
  this._loading[`${nextLocale}`] = fetchGlobalLocalePhrases(
149
- nextLocale
149
+ nextLocale,
150
150
  ).then((phrases) => {
151
151
  this._currentLocale = nextLocale!;
152
152
  this.extend(phrases as LocalizedStrings, nextLocale);
@@ -179,7 +179,7 @@ export default class Translator extends EventEmitter {
179
179
  ] = fetchLocalLocalePhrases(
180
180
  this._consentManager.customerId,
181
181
  this._consentManager.configId,
182
- locale
182
+ locale,
183
183
  )
184
184
  .then((phrases) => {
185
185
  this.override(phrases as LocalizedStrings, locale);
@@ -196,7 +196,7 @@ export default class Translator extends EventEmitter {
196
196
  fetchLocalLocalePhrases(
197
197
  this._consentManager.customerId,
198
198
  this._consentManager.configId,
199
- nextLocale
199
+ nextLocale,
200
200
  ).then((phrases) => {
201
201
  this.override(phrases as LocalizedStrings, nextLocale);
202
202
  delete this._loading[
@@ -217,7 +217,7 @@ export default class Translator extends EventEmitter {
217
217
  }
218
218
  this.emit(
219
219
  'langLoadFailure',
220
- `Locale ${locale} is not available for translation`
220
+ `Locale ${locale} is not available for translation`,
221
221
  );
222
222
  throw error;
223
223
  });
@@ -231,12 +231,12 @@ export default class Translator extends EventEmitter {
231
231
  } else {
232
232
  this.emit(
233
233
  'langLoadFailure',
234
- `Locale ${locale} is not available for translation`
234
+ `Locale ${locale} is not available for translation`,
235
235
  );
236
236
  this._langLoadFailureSubscription?.remove();
237
237
  this._langLoadSuccessSubscription?.remove();
238
238
  return Promise.reject(
239
- new Error(`Locale ${locale} is not available for translation`)
239
+ new Error(`Locale ${locale} is not available for translation`),
240
240
  );
241
241
  }
242
242
  }
@@ -262,10 +262,10 @@ export default class Translator extends EventEmitter {
262
262
  * Create a translation template for a particular key path
263
263
  */
264
264
  template(
265
- key: string
265
+ key: string,
266
266
  ): (
267
267
  props: string | il8nProps,
268
- defaultPhrase: string
268
+ defaultPhrase: string,
269
269
  ) => string | LocalizedStrings {
270
270
  return (props: string | il8nProps, defaultPhrase: string) =>
271
271
  this.translate(key, props, defaultPhrase);
@@ -277,7 +277,7 @@ export default class Translator extends EventEmitter {
277
277
  translate(
278
278
  path: string | string[],
279
279
  props: string | il8nProps = {},
280
- defaultPhrase?: string
280
+ defaultPhrase?: string,
281
281
  ): string | LocalizedStrings {
282
282
  const localePassed = typeof props === 'string';
283
283
  const locale = localePassed ? props : props.locale || this.locale;