cozy-external-bridge 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -4,7 +4,7 @@ This library allows communication between a container app and an app embedded in
4
4
 
5
5
  ## For container app
6
6
 
7
- Just add the `useExternalBridge` hook and it will :
7
+ Add the `useExternalBridge` hook and it will :
8
8
 
9
9
  - allow history syncing
10
10
  - expose a `getContacts` method
@@ -18,6 +18,20 @@ const App = () => {
18
18
  }
19
19
  ```
20
20
 
21
+ You also need to manage routing if embedded app use history syncing :
22
+
23
+ ```
24
+ <HashRouter>
25
+ <Routes>
26
+ <Route element={<AppLayout />}>
27
+ <Route path="/" element={<OutletWrapper Component={App} />}>
28
+ <Route path="bridge/*" />
29
+ </Route>
30
+ </Route>
31
+ </Routes>
32
+ </HashRouter>
33
+ ```
34
+
21
35
  ## For embedded app
22
36
 
23
37
  Import `dist/embedded/bundle.js` script. It exposes method in `window._cozyBridge`.
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.BRIDGE_ROUTE_PREFIX = void 0;
7
+ var BRIDGE_ROUTE_PREFIX = '/bridge';
8
+ exports.BRIDGE_ROUTE_PREFIX = BRIDGE_ROUTE_PREFIX;
@@ -3,7 +3,19 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.handleRequestParentOrigin = exports.extractUrl = void 0;
6
+ exports.handleRequestParentOrigin = exports.getIframe = exports.extractUrl = void 0;
7
+
8
+ var getIframe = function getIframe() {
9
+ var iframe = document.getElementById('embeddedApp');
10
+
11
+ if (iframe === null) {
12
+ throw new Error('No iframe found');
13
+ }
14
+
15
+ return iframe;
16
+ };
17
+
18
+ exports.getIframe = getIframe;
7
19
 
8
20
  var extractUrl = function extractUrl(url) {
9
21
  if (url.startsWith('http')) {
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.useParentOrigin = exports.useInitialRedirection = void 0;
7
+
8
+ var _react = require("react");
9
+
10
+ var _reactRouterDom = require("react-router-dom");
11
+
12
+ var _cozyClient = require("cozy-client");
13
+
14
+ var _constants = require("./constants");
15
+
16
+ var _helpers = require("./helpers");
17
+
18
+ // Initial redirection is necessary when we load a page from a direct link
19
+ // to load the iframe to the direct link
20
+ var useInitialRedirection = function useInitialRedirection() {
21
+ var location = (0, _reactRouterDom.useLocation)();
22
+ (0, _react.useEffect)(function () {
23
+ if (location.pathname.startsWith(_constants.BRIDGE_ROUTE_PREFIX)) {
24
+ var iframe = (0, _helpers.getIframe)();
25
+ var destUrl = new URL(iframe.src);
26
+ destUrl.pathname = location.pathname.replace(_constants.BRIDGE_ROUTE_PREFIX, '');
27
+ destUrl.hash = location.hash;
28
+ destUrl.search = location.search;
29
+ iframe.src = destUrl.toString();
30
+ }
31
+ }, []);
32
+ }; // Allow the iframe to request the origin of the parent window
33
+
34
+
35
+ exports.useInitialRedirection = useInitialRedirection;
36
+
37
+ var useParentOrigin = function useParentOrigin(origin) {
38
+ var client = (0, _cozyClient.useClient)();
39
+ (0, _react.useEffect)(function () {
40
+ if (!client) return;
41
+
42
+ var requestParentOriginHandler = function requestParentOriginHandler(event) {
43
+ return (0, _helpers.handleRequestParentOrigin)(event, origin);
44
+ };
45
+
46
+ window.addEventListener('message', requestParentOriginHandler);
47
+ return function () {
48
+ window.removeEventListener('message', requestParentOriginHandler);
49
+ };
50
+ }, [client, origin]);
51
+ };
52
+
53
+ exports.useParentOrigin = useParentOrigin;
@@ -0,0 +1,64 @@
1
+ import { renderHook } from '@testing-library/react-hooks'
2
+ import { useLocation } from 'react-router-dom'
3
+
4
+ import { getIframe } from './helpers'
5
+ import { useInitialRedirection } from './hooks'
6
+
7
+ jest.mock('react-router-dom', () => ({
8
+ useLocation: jest.fn()
9
+ }))
10
+
11
+ jest.mock('./helpers', () => ({
12
+ getIframe: jest.fn()
13
+ }))
14
+
15
+ const mockedUseLocation = useLocation as jest.Mock
16
+ const mockedGetIframe = getIframe as jest.Mock
17
+
18
+ describe('useInitialRedirection', () => {
19
+ afterEach(() => {
20
+ jest.clearAllMocks()
21
+ })
22
+
23
+ it('should not modify iframe.src when pathname does not start with bridge prefix', () => {
24
+ const mockLocation = { pathname: 'assistant', hash: '', search: '' }
25
+ mockedUseLocation.mockReturnValue(mockLocation)
26
+
27
+ const mockIframe = { src: 'https://alice-chat.mycozy.cloud' }
28
+ mockedGetIframe.mockReturnValue(mockIframe)
29
+
30
+ renderHook(() => useInitialRedirection())
31
+
32
+ expect(mockIframe.src).toBe('https://alice-chat.mycozy.cloud')
33
+ })
34
+
35
+ it('should modify iframe.src when pathname start with bridge prefix', () => {
36
+ const mockLocation = { pathname: '/bridge/welcome', hash: '', search: '' }
37
+ mockedUseLocation.mockReturnValue(mockLocation)
38
+
39
+ const mockIframe = { src: 'https://alice-chat.mycozy.cloud' }
40
+ mockedGetIframe.mockReturnValue(mockIframe)
41
+
42
+ renderHook(() => useInitialRedirection())
43
+
44
+ expect(mockIframe.src).toBe('https://alice-chat.mycozy.cloud/welcome')
45
+ })
46
+
47
+ it('should modify iframe.src when pathname start with bridge prefix and allow bridge keyword in iframe url', () => {
48
+ const mockLocation = {
49
+ pathname: '/bridge/welcome/bridge',
50
+ hash: '',
51
+ search: ''
52
+ }
53
+ mockedUseLocation.mockReturnValue(mockLocation)
54
+
55
+ const mockIframe = { src: 'https://alice-chat.mycozy.cloud' }
56
+ mockedGetIframe.mockReturnValue(mockIframe)
57
+
58
+ renderHook(() => useInitialRedirection())
59
+
60
+ expect(mockIframe.src).toBe(
61
+ 'https://alice-chat.mycozy.cloud/welcome/bridge'
62
+ )
63
+ })
64
+ })
@@ -21,68 +21,25 @@ var _cozyClient = require("cozy-client");
21
21
 
22
22
  var _cozyFlags = _interopRequireDefault(require("cozy-flags"));
23
23
 
24
- var _helpers = require("./helpers");
25
-
26
- function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
27
-
28
- function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
29
-
30
- /* eslint-disable no-console */
31
- var getIframe = function getIframe() {
32
- var iframe = document.getElementById('embeddedApp');
24
+ var _cozyMinilog = _interopRequireDefault(require("cozy-minilog"));
33
25
 
34
- if (iframe === null) {
35
- throw new Error('No iframe found');
36
- }
26
+ var _constants = require("./constants");
37
27
 
38
- return iframe;
39
- }; // Initial redirection is necessary when we load a page from a direct link
40
- // to load the iframe to the direct link
28
+ var _helpers = require("./helpers");
41
29
 
30
+ var _hooks = require("./hooks");
42
31
 
43
- var useInitialRedirection = function useInitialRedirection() {
44
- var location = (0, _reactRouterDom.useLocation)();
45
- (0, _react.useEffect)(function () {
46
- // If current url is root url, do nothing
47
- if (location.pathname === '/' && location.hash === '' && location.search === '') {
48
- return;
49
- }
50
-
51
- var iframe = getIframe();
52
- var destUrl = new URL(iframe.src);
53
- destUrl.pathname = location.pathname;
54
- destUrl.hash = location.hash;
55
- destUrl.search = location.search;
56
- var currentIframeUrl = new URL(iframe.src);
57
-
58
- if (destUrl.toString() !== currentIframeUrl.toString()) {
59
- iframe.src = destUrl.toString();
60
- }
61
- }, []);
62
- }; // Allow the iframe to request the origin of the parent window
63
-
64
-
65
- var useParentOrigin = function useParentOrigin(origin) {
66
- var client = (0, _cozyClient.useClient)();
67
- (0, _react.useEffect)(function () {
68
- if (!client) return;
32
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
69
33
 
70
- var requestParentOriginHandler = function requestParentOriginHandler(event) {
71
- return (0, _helpers.handleRequestParentOrigin)(event, origin);
72
- };
34
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
73
35
 
74
- window.addEventListener('message', requestParentOriginHandler);
75
- return function () {
76
- window.removeEventListener('message', requestParentOriginHandler);
77
- };
78
- }, [client, origin]);
79
- };
36
+ var log = (0, _cozyMinilog.default)('🌉 [Container bridge]');
80
37
 
81
38
  var useExternalBridge = function useExternalBridge(origin) {
82
39
  var client = (0, _cozyClient.useClient)();
83
40
  var navigate = (0, _reactRouterDom.useNavigate)();
84
- useInitialRedirection();
85
- useParentOrigin(origin);
41
+ (0, _hooks.useInitialRedirection)();
42
+ (0, _hooks.useParentOrigin)(origin);
86
43
  (0, _react.useEffect)(function () {
87
44
  if (!client) return;
88
45
  var exposedMethods = {
@@ -123,13 +80,14 @@ var useExternalBridge = function useExternalBridge(origin) {
123
80
  // Proof of concepts of Twake <-> Cozy URL synchronization
124
81
  updateHistory: function updateHistory(newUrl) {
125
82
  var url = (0, _helpers.extractUrl)(newUrl);
126
- console.log('🟢 Replacing route:', url);
127
- navigate(url, {
83
+ log.debug("Navigating to ".concat(url, " because received ").concat(newUrl, " from embedded app"));
84
+ navigate(_constants.BRIDGE_ROUTE_PREFIX + url, {
128
85
  replace: true
129
86
  });
130
87
  }
131
88
  };
132
- Comlink.expose(exposedMethods, Comlink.windowEndpoint(getIframe().contentWindow, self, origin));
89
+ Comlink.expose(exposedMethods, Comlink.windowEndpoint((0, _helpers.getIframe)().contentWindow, self, origin));
90
+ log.debug('Bridge initialized');
133
91
  }, [navigate, client, origin]);
134
92
  };
135
93
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "cozy-external-bridge",
3
3
  "description": "Library allows communication between a container app and an app embedded in an iframe",
4
- "version": "0.8.0",
4
+ "version": "0.9.0",
5
5
  "author": {
6
6
  "name": "Cozy Cloud",
7
7
  "url": "https://github.com/cozy"
@@ -15,6 +15,7 @@
15
15
  "peerDependencies": {
16
16
  "cozy-client": ">=54.0.0",
17
17
  "cozy-flags": ">=4.7.0",
18
+ "cozy-minilog": ">=3.10.0",
18
19
  "react": ">=16.12.0",
19
20
  "react-dom": ">=16.12.0",
20
21
  "react-router-dom": ">=6.14.2"
@@ -31,6 +32,7 @@
31
32
  "babel-preset-cozy-app": "^2.8.1",
32
33
  "cozy-client": "^54.0.0",
33
34
  "cozy-flags": "^4.7.0",
35
+ "cozy-minilog": "^3.10.0",
34
36
  "jest": "26.6.3",
35
37
  "react": "16.12.0",
36
38
  "react-dom": "16.12.0",
@@ -66,5 +68,5 @@
66
68
  "lint": "cd ../.. && yarn eslint --ext js,jsx,ts packages/cozy-external-bridge"
67
69
  },
68
70
  "types": "dist/index.d.ts",
69
- "gitHead": "40a33c2ba35543add056495d9348501e24909a70"
71
+ "gitHead": "32b4cd0c82173f5b7703066949011d74810f273e"
70
72
  }