@applicaster/zapp-react-native-bridge 13.0.0-rc.1 → 13.0.0-rc.100

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.
@@ -1,12 +1,12 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`getAllFavorites returns all favorites 1`] = `
4
- Array [
5
- Object {
4
+ [
5
+ {
6
6
  "foo": "bar",
7
7
  "id": "A123",
8
8
  },
9
- Object {
9
+ {
10
10
  "foo": "baz",
11
11
  "id": "B456",
12
12
  },
@@ -1,90 +1,86 @@
1
1
  import * as R from "ramda";
2
2
 
3
- const {
3
+ import {
4
4
  favoritesListener,
5
5
  isFavorite,
6
6
  setAsFavorite,
7
7
  removeFromFavorites,
8
8
  getAllFavorites,
9
- } = require("../index");
9
+ } from "..";
10
+
11
+ import { localStorage } from "../../ZappStorage/LocalStorage";
12
+ import { bridgeLogger } from "../../logger";
10
13
 
11
- const { localStorage } = require("../../ZappStorage/LocalStorage");
12
14
  const namespace = "local_favourites";
13
15
 
14
16
  const REMOVE_ERROR = new Error(
15
17
  "entry with id I throw when retrieved is not in the favourites list"
16
18
  );
17
19
 
18
- const { bridgeLogger } = require("../../logger");
19
-
20
20
  const GET_ERROR = new Error("could not get item");
21
21
  const SET_ERROR = new Error("could not set item");
22
22
 
23
- const item = {
23
+ const item: any = {
24
24
  id: "A123",
25
25
  foo: "bar",
26
26
  };
27
27
 
28
- const item2 = {
28
+ const item2: any = {
29
29
  id: "B456",
30
30
  foo: "baz",
31
31
  };
32
32
 
33
- const itemThatThrowsGet = {
33
+ const itemThatThrowsGet: any = {
34
34
  id: "I throw when retrieved",
35
35
  };
36
36
 
37
- const itemThatThrowsSet = {
37
+ const itemThatThrowsSet: any = {
38
38
  id: "I throw when set",
39
39
  };
40
40
 
41
- jest.mock("../../ZappStorage/LocalStorage", () => {
42
- let storage = {};
43
-
44
- return {
45
- localStorage: {
46
- setItem: jest.fn((key, value, namespace) => {
47
- if (R.includes(itemThatThrowsSet, value)) {
48
- throw SET_ERROR;
49
- }
50
-
51
- if (!storage[namespace]) {
52
- storage[namespace] = {};
53
- }
54
-
55
- storage[namespace][key] = value;
56
-
57
- return Promise.resolve(true);
58
- }),
59
- getItem: jest.fn((key, namespace) => {
60
- const values = storage[namespace]?.[key] || [];
61
-
62
- if (R.includes(itemThatThrowsGet, values)) {
63
- throw GET_ERROR;
64
- }
65
-
66
- return Promise.resolve(values);
67
- }),
68
- __reset: () => {
69
- storage = {};
70
- },
71
- },
72
- };
41
+ let mockStorage = {};
42
+
43
+ const mockSetItem = jest.fn((key, value, namespace) => {
44
+ if (R.includes(itemThatThrowsSet, value)) {
45
+ throw SET_ERROR;
46
+ }
47
+
48
+ if (!mockStorage[namespace]) {
49
+ mockStorage[namespace] = {};
50
+ }
51
+
52
+ mockStorage[namespace][key] = value;
53
+
54
+ return Promise.resolve(true);
55
+ });
56
+
57
+ const mockGetItem = jest.fn((key, namespace) => {
58
+ const values = mockStorage[namespace]?.[key] || [];
59
+
60
+ if (R.includes(itemThatThrowsGet, values)) {
61
+ throw GET_ERROR;
62
+ }
63
+
64
+ return Promise.resolve(values);
73
65
  });
74
66
 
67
+ jest.spyOn(localStorage, "setItem").mockImplementation(mockSetItem);
68
+ jest.spyOn(localStorage, "getItem").mockImplementation(mockGetItem);
69
+
75
70
  jest.mock("../../logger", () => ({
76
71
  bridgeLogger: {
72
+ ...jest.requireActual("../../logger").bridgeLogger,
77
73
  error: jest.fn(),
78
74
  },
79
75
  }));
80
76
 
81
77
  beforeEach(() => {
78
+ mockStorage = {};
82
79
  bridgeLogger.error.mockClear();
83
80
  });
84
81
 
85
82
  describe("isFavorite", () => {
86
83
  beforeEach(() => {
87
- localStorage.__reset();
88
84
  localStorage.setItem("favourites", [item], namespace);
89
85
  });
90
86
 
@@ -104,10 +100,6 @@ describe("isFavorite", () => {
104
100
  });
105
101
 
106
102
  describe("setAsFavorite", () => {
107
- beforeEach(() => {
108
- localStorage.__reset();
109
- });
110
-
111
103
  it("rejects when it throws", async () => {
112
104
  await expect(setAsFavorite(itemThatThrowsSet)).rejects.toEqual(SET_ERROR);
113
105
  expect(bridgeLogger.error).toHaveBeenCalledWith(SET_ERROR);
@@ -124,7 +116,6 @@ describe("setAsFavorite", () => {
124
116
 
125
117
  describe("removeFromFavorites", () => {
126
118
  beforeEach(() => {
127
- localStorage.__reset();
128
119
  localStorage.setItem("favourites", [item], namespace);
129
120
  });
130
121
 
@@ -148,7 +139,6 @@ describe("removeFromFavorites", () => {
148
139
 
149
140
  describe("getAllFavorites", () => {
150
141
  beforeEach(() => {
151
- localStorage.__reset();
152
142
  localStorage.setItem("favourites", [item, item2], namespace);
153
143
  });
154
144
 
@@ -164,15 +154,15 @@ describe("getAllFavorites", () => {
164
154
  });
165
155
 
166
156
  describe("favouritesListener", () => {
167
- beforeEach(() => {
168
- localStorage.__reset();
169
- });
170
-
171
157
  it("allows to register a listener called when favourites are changed", async () => {
172
158
  const listener = jest.fn();
173
159
  favoritesListener.on("FAVORITES_CHANGED", listener);
174
- await setAsFavorite(item);
160
+ jest.clearAllMocks();
161
+ await setAsFavorite({ ...item, id: "A1234" });
175
162
 
176
- return expect(listener).toHaveBeenCalledWith([item], expect.any(Function));
163
+ return expect(listener).toHaveBeenCalledWith(
164
+ [{ ...item, id: "A1234" }],
165
+ expect.any(Function)
166
+ );
177
167
  });
178
168
  });
@@ -3,7 +3,7 @@
3
3
  exports[`fileManager deleteFolders deletes each provided path 1`] = `true`;
4
4
 
5
5
  exports[`fileManager storeFiles calls the store file function of the native module with the provided args 1`] = `
6
- Object {
6
+ {
7
7
  "http://file": true,
8
8
  "http://file2": true,
9
9
  }
@@ -1,19 +1,19 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`collectAssets collects asset information from config files 1`] = `
4
- Array [
5
- Object {
4
+ [
5
+ {
6
6
  "file": "/nativ/path/files/f5f757ab2a29a4b611a116682d5117a9.jpg",
7
- "path": Array [
7
+ "path": [
8
8
  "screen1",
9
9
  "asset",
10
10
  ],
11
11
  "source": "files",
12
12
  "url": "http://img.com/asset.jpg",
13
13
  },
14
- Object {
14
+ {
15
15
  "file": "/nativ/path/files/12b7aa4be9b486035922c2536c15154a.png",
16
- "path": Array [
16
+ "path": [
17
17
  "plugins",
18
18
  "plugin_asset",
19
19
  ],
@@ -24,11 +24,11 @@ Array [
24
24
  `;
25
25
 
26
26
  exports[`remapAssetPath remaps the asset url 1`] = `
27
- Object {
28
- "plugins": Object {
27
+ {
28
+ "plugins": {
29
29
  "plugin_asset": "file://asset.png",
30
30
  },
31
- "screen1": Object {
31
+ "screen1": {
32
32
  "asset": "file://asset.jpg",
33
33
  "title": "title",
34
34
  },
@@ -85,37 +85,40 @@ export const remapAssetPath = (
85
85
  ): Record<string, any> => {
86
86
  const startTime = performance.now();
87
87
 
88
- const result = assets.reduce((obj, { path, url }) => {
89
- const localFile = localFiles[url];
90
-
91
- if (!localFile) {
92
- bridgeLogger.warning({
93
- message: `remapAssetPath: Could not replace asset with local file for url: ${url}`,
94
- data: { path, obj },
95
- });
88
+ const result = assets.reduce(
89
+ (obj, { path, url }) => {
90
+ const localFile = localFiles[url];
91
+
92
+ if (!localFile) {
93
+ bridgeLogger.warning({
94
+ message: `remapAssetPath: Could not replace asset with local file for url: ${url}`,
95
+ data: { path, obj },
96
+ });
97
+
98
+ return obj;
99
+ }
100
+
101
+ let target = obj;
102
+
103
+ // Traverse the path to the appropriate nested object
104
+ for (let i = 0; i < path.length - 1; i++) {
105
+ target = target[path[i]] = target[path[i]];
106
+ }
107
+
108
+ if (!target) {
109
+ bridgeLogger.error({
110
+ message: `remapAssetPath: Could not find path ${path.join(".")}`,
111
+ data: obj,
112
+ });
113
+ } else {
114
+ // Set the final value
115
+ target[path[path.length - 1]] = localFile;
116
+ }
96
117
 
97
118
  return obj;
98
- }
99
-
100
- let target = obj;
101
-
102
- // Traverse the path to the appropriate nested object
103
- for (let i = 0; i < path.length - 1; i++) {
104
- target = target[path[i]] = target[path[i]];
105
- }
106
-
107
- if (!target) {
108
- bridgeLogger.error({
109
- message: `remapAssetPath: Could not find path ${path.join(".")}`,
110
- data: obj,
111
- });
112
- } else {
113
- // Set the final value
114
- target[path[path.length - 1]] = localFile;
115
- }
116
-
117
- return obj;
118
- }, JSON.parse(JSON.stringify(source)));
119
+ },
120
+ JSON.parse(JSON.stringify(source))
121
+ );
119
122
 
120
123
  bridgeLogger.log({
121
124
  message: `remapAssetPath: remapping took ${
@@ -105,9 +105,8 @@ async function isPluginEnabled(identifier) {
105
105
  return isPluginEnabledNative(identifier);
106
106
  }
107
107
 
108
- const enabledInConfigurationJSON = await isPluginSupportToggleLogic(
109
- identifier
110
- );
108
+ const enabledInConfigurationJSON =
109
+ await isPluginSupportToggleLogic(identifier);
111
110
 
112
111
  if (enabledInConfigurationJSON !== undefined) {
113
112
  const enabledOverriden = await localStorage.getItem(
@@ -40,7 +40,7 @@ export class PushTopicManager {
40
40
  return this.pushTopicSubject;
41
41
  };
42
42
 
43
- notifyTagsChange = () => {
43
+ private notifyTagsChange = () => {
44
44
  this.pushTopicSubject.next(this.registeredTags);
45
45
  };
46
46
 
@@ -1,7 +1,7 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
3
  exports[`when QuickBrickCommunication Module is undefined getAppData returns the default values 1`] = `
4
- Object {
4
+ {
5
5
  "accountId": 667,
6
6
  "accountsAccountId": "5ae06cef8fba0f00084bd3c6",
7
7
  "broadcasterId": 770,
@@ -1,6 +1,5 @@
1
- const { NativeModules } = require("react-native");
2
-
3
- NativeModules.Foo = jest.fn();
1
+ import { sendQuickBrickEvent, getAppData, getLegacyInitialProps } from "../";
2
+ import { bridgeLogger } from "../../logger";
4
3
 
5
4
  jest.mock("../../logger", () => ({
6
5
  bridgeLogger: {
@@ -8,25 +7,17 @@ jest.mock("../../logger", () => ({
8
7
  },
9
8
  }));
10
9
 
11
- const {
12
- sendQuickBrickEvent,
13
- getAppData,
14
- getLegacyInitialProps,
15
- } = require("../");
16
-
17
- const eventName = "event";
18
10
  const payload = {};
19
11
 
20
- const { bridgeLogger } = require("../../logger");
21
-
22
12
  describe("when QuickBrickCommunication Module is undefined", () => {
23
- beforeEach(() => {
24
- jest.unmock("react-native");
25
- jest.resetModules();
13
+ beforeAll(() => {
14
+ require("react-native").NativeModules.QuickBrickCommunicationModule =
15
+ undefined;
26
16
  });
27
17
 
28
18
  describe("sendQuickBrickEvent", () => {
29
19
  it("throws an error", () => {
20
+ const eventName = "event";
30
21
  expect(() => sendQuickBrickEvent(eventName, payload)).toThrow();
31
22
  });
32
23
  });
@@ -28,7 +28,6 @@ export interface QuickBrickCommunicationModuleI extends AppData {
28
28
  }
29
29
 
30
30
  const { NativeModules } = require("react-native");
31
- const { QuickBrickCommunicationModule } = NativeModules;
32
31
 
33
32
  /**
34
33
  * sends an event to the native QuickBrick manager module
@@ -42,9 +41,7 @@ export function sendQuickBrickEvent(
42
41
  eventName: QuickBrickEvent,
43
42
  payload: { [key: string]: any } = {}
44
43
  ): void {
45
- const QBNativeModule =
46
- QuickBrickCommunicationModule ||
47
- NativeModules.QuickBrickCommunicationModule;
44
+ const QBNativeModule = NativeModules.QuickBrickCommunicationModule;
48
45
 
49
46
  if (!QBNativeModule) {
50
47
  throw new Error("QuickBrickCommunicationModule not found");
@@ -81,18 +78,21 @@ export function getAppData(): AppData {
81
78
  try {
82
79
  const uuid = window.localStorage.uuid || uuidv4();
83
80
  window.localStorage.setItem("uuid", uuid);
84
- QuickBrickCommunicationModule.uuid = uuid;
81
+ NativeModules.QuickBrickCommunicationModule.uuid = uuid;
85
82
  } catch (error) {
86
83
  bridgeLogger.error({ message: "cannot set device uuid", error });
87
84
  }
88
85
  }
89
86
 
90
87
  if (
91
- QuickBrickCommunicationModule &&
88
+ NativeModules.QuickBrickCommunicationModule &&
92
89
  R.allPass(R.map(R.has, APP_PROPERTY_KEYS))
93
90
  ) {
94
91
  // $FlowFixMe - CORRECT DECLARATIONS PLZ ! KTHXBYE
95
- return R.pick(APP_PROPERTY_KEYS, QuickBrickCommunicationModule);
92
+ return R.pick(
93
+ APP_PROPERTY_KEYS,
94
+ NativeModules.QuickBrickCommunicationModule
95
+ );
96
96
  } else {
97
97
  // TODO: in the end, we probably want to throw if the constants are not defined from the native side
98
98
  // for now, stubbing values is good enough
@@ -106,8 +106,8 @@ export function getAppData(): AppData {
106
106
  }
107
107
 
108
108
  export function getLegacyInitialProps() {
109
- if (QuickBrickCommunicationModule) {
110
- return QuickBrickCommunicationModule.initialProps;
109
+ if (NativeModules.QuickBrickCommunicationModule) {
110
+ return NativeModules.QuickBrickCommunicationModule.initialProps;
111
111
  }
112
112
 
113
113
  bridgeLogger.warning("QuickBrickCommunicationModule not found");
@@ -0,0 +1,108 @@
1
+ import { createLogger } from "@applicaster/zapp-react-native-utils/logger";
2
+ import { bridgeLogger } from "../logger";
3
+ import { BehaviorSubject } from "rxjs";
4
+ import { localStorage } from "@applicaster/zapp-react-native-bridge/ZappStorage/LocalStorage";
5
+ import { getNamespaceAndKey } from "@applicaster/zapp-react-native-utils/appUtils/contextKeysManager/utils";
6
+
7
+ export const { log_verbose, log_debug, log_warning, log_info, log_error } =
8
+ createLogger({
9
+ category: "StorageSingleValueProvider",
10
+ subsystem: "zapp-react-native-bridge",
11
+ parent: bridgeLogger,
12
+ });
13
+
14
+ export interface SingleValueProvider {
15
+ getObservable(): BehaviorSubject<string | null>;
16
+
17
+ setValue(value: string): Promise<void>;
18
+ getValue(): string | null;
19
+ getValueAsync(): Promise<string | null>;
20
+ clearValue(): Promise<void>;
21
+ }
22
+
23
+ interface StorageListenerArgs {
24
+ value: string | null;
25
+ }
26
+
27
+ export class StorageSingleValueProvider implements SingleValueProvider {
28
+ // Static cache of providers by namespace
29
+ private static singleValueProviders: Record<
30
+ string,
31
+ StorageSingleValueProvider
32
+ > = {};
33
+
34
+ public static getProvider(keyNamespace: string): StorageSingleValueProvider {
35
+ if (!this.singleValueProviders[keyNamespace]) {
36
+ this.singleValueProviders[keyNamespace] = new StorageSingleValueProvider(
37
+ keyNamespace
38
+ );
39
+ }
40
+
41
+ return this.singleValueProviders[keyNamespace];
42
+ }
43
+
44
+ private valueSubject: BehaviorSubject<string | null>;
45
+
46
+ private readonly key: string;
47
+ private readonly namespace: string;
48
+
49
+ private constructor(keyNamespace: string) {
50
+ const { namespace, key } = getNamespaceAndKey(keyNamespace);
51
+
52
+ if (!key) {
53
+ throw new Error("StorageSingleValueProvider: Key is required");
54
+ }
55
+
56
+ this.key = key;
57
+ this.namespace = namespace;
58
+ localStorage.addListener?.({ key, namespace }, this.reloadValue);
59
+
60
+ this.valueSubject = new BehaviorSubject<string | null>(null);
61
+
62
+ void this.getValueAsync();
63
+ log_debug("StorageSingleValueProvider: Initializing");
64
+ }
65
+
66
+ private reloadValue = async ({ value }: StorageListenerArgs) => {
67
+ log_debug(`reloadValue: request to reload value: ${value}`);
68
+
69
+ this.valueSubject.next(value);
70
+ };
71
+
72
+ public getObservable = (): BehaviorSubject<string | null> =>
73
+ this.valueSubject;
74
+
75
+ private async updateValueAndNotifyObservers(value: string | null) {
76
+ if (value === null) {
77
+ await localStorage.removeItem(this.key, this.namespace);
78
+ } else {
79
+ await localStorage.setItem(this.key, value, this.namespace);
80
+ }
81
+
82
+ this.valueSubject.next(value);
83
+ }
84
+
85
+ public setValue = async (value: string): Promise<void> => {
86
+ log_debug(`setValue: Setting new value: ${value}`);
87
+
88
+ await this.updateValueAndNotifyObservers(value);
89
+ };
90
+
91
+ public clearValue = async (): Promise<void> => {
92
+ await localStorage.removeItem(this.key, this.namespace);
93
+ log_debug("clearValue: Removing value");
94
+
95
+ this.valueSubject.next(null);
96
+ };
97
+
98
+ public getValueAsync = async (): Promise<string | null> => {
99
+ const value = await localStorage.getItem(this.key, this.namespace);
100
+ this.valueSubject.next(value);
101
+
102
+ return value;
103
+ };
104
+
105
+ public getValue = (): string | null => {
106
+ return this.valueSubject.getValue();
107
+ };
108
+ }
@@ -1,12 +1,6 @@
1
1
  import { localStorage as NativeLocalStorage } from "../__mocks__/ios";
2
2
  import { DEFAULT_NAMESPACE } from "../__mocks__/storageMock";
3
3
 
4
- const { localStorage } = require("../LocalStorage");
5
-
6
- const RN = require("react-native");
7
-
8
- RN.NativeModules.LocalStorage = NativeLocalStorage;
9
-
10
4
  const test_key = "test_key";
11
5
  const test_value = "test_value";
12
6
  const namespaced_key = "namespaced_key";
@@ -23,7 +17,17 @@ function setUpStorage() {
23
17
  NativeLocalStorage.setItem(obj_key, JSON.stringify(obj_value));
24
18
  }
25
19
 
20
+ const RN = require("react-native");
21
+
22
+ RN.NativeModules.LocalStorage = NativeLocalStorage;
23
+
26
24
  describe("localStorage", () => {
25
+ const { localStorage } = require("../LocalStorage");
26
+
27
+ beforeAll(() => {
28
+ jest.resetModules();
29
+ });
30
+
27
31
  describe("setItem", () => {
28
32
  beforeEach(async () => {
29
33
  NativeLocalStorage.__clear();
@@ -1,7 +1,5 @@
1
1
  import { localStorage as NativeLocalStorage } from "../__mocks__/android";
2
2
 
3
- const { localStorage } = require("../LocalStorage");
4
-
5
3
  const RN = require("react-native");
6
4
 
7
5
  RN.NativeModules.LocalStorage = NativeLocalStorage;
@@ -24,6 +22,7 @@ function setUpStorage() {
24
22
  }
25
23
 
26
24
  describe("localStorage - getAllItems", () => {
25
+ const { localStorage } = require("../LocalStorage");
27
26
  beforeAll(setUpStorage);
28
27
 
29
28
  it("retrieves all values", async () => {
@@ -28,7 +28,7 @@ export function throwUndefinedKeyError(storage: string, message: string) {
28
28
  }
29
29
 
30
30
  class UndefinedValueError extends Error {
31
- constructor(message, storage: string, key) {
31
+ constructor(message, _storage: string, key) {
32
32
  super(message);
33
33
  logError(message, this, { key });
34
34
  }
package/package.json CHANGED
@@ -1,11 +1,10 @@
1
1
  {
2
2
  "name": "@applicaster/zapp-react-native-bridge",
3
- "version": "13.0.0-rc.1",
3
+ "version": "13.0.0-rc.100",
4
4
  "description": "Applicaster Zapp React Native modules",
5
5
  "main": "index.js",
6
6
  "types": "index.d.ts",
7
7
  "scripts": {
8
- "test": "jest -w=2",
9
8
  "build": "echo 'skipping ts build for core packages'"
10
9
  },
11
10
  "publishConfig": {
@@ -33,14 +32,18 @@
33
32
  "homepage": "https://github.com/applicaster/quickbrick#readme",
34
33
  "dependencies": {
35
34
  "@applicaster/zapp-pipes-dev-kit": "1.4.7",
36
- "@applicaster/zapp-react-native-utils": "13.0.0-rc.1",
35
+ "@applicaster/zapp-react-native-utils": "13.0.0-rc.100",
37
36
  "md5": "^2.3.0",
38
37
  "uuid": "^3.3.2"
39
38
  },
40
39
  "peerDependencies": {
41
- "@types/node": "*",
42
- "@types/react-native": "0.69.6",
43
- "react": "17.0.2",
44
- "react-native": "0.68.6"
40
+ "@applicaster/zapp-pipes-v2-client": "*",
41
+ "@react-native-community/netinfo": "*",
42
+ "immer": "*",
43
+ "react": "*",
44
+ "react-native": "*",
45
+ "uglify-js": "*",
46
+ "validate-color": "*",
47
+ "zustand": "*"
45
48
  }
46
49
  }