Added support for App V2#2
Conversation
Added responses Added routes
Added responses Added routes
|
@copilot review |
Review complete. Found one bug: |
There was a problem hiding this comment.
Pull request overview
This PR updates the SDK to support “App V2” style navigation by introducing a named-route navigation API (navigate.push/replace/back), expanding the route map, and adding request/response correlation (via _id) for postMessage-based hosts.
Changes:
- Reworked navigation API to
push/replace/backand expandedsrc/routes.jsfor theapp(V2) route set. - Added
_idcorrelation + Promise-based responses insendToApp, plus a Flutter bridge path viaflutter_inappwebview. - Updated Jest tests and README to cover the new navigation and messaging behavior; bumped package version.
Reviewed changes
Copilot reviewed 8 out of 10 changed files in this pull request and generated 10 comments.
Show a summary per file
| File | Description |
|---|---|
| test/navigate.test.js | Adds table-driven tests for V2 route building and new navigation methods. |
| test/index.test.js | Updates sendToApp tests for correlation IDs, Promise replies, and Flutter bridge path. |
| src/routes.js | Introduces/updates route mappings for app (V2). |
| src/navigate.js | Replaces old navigation helpers with push/replace/back using route substitution. |
| src/index.js | Adds Promise correlation for postMessage replies and flutter_inappwebview support. |
| README.md | Documents the new navigation API and available routes. |
| package.json | Bumps package version. |
| package-lock.json | Updates lockfile version metadata to match package version. |
| eslint.config.mjs | Adds Jest/Node globals for tests and config files. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| window.addEventListener("message", function (e) { | ||
| const data = e.data; | ||
|
|
||
| // Modern request/response: resolve the matching pending request. | ||
| if (data && typeof data === 'object' && typeof data._id === 'string' && pendingRequests.has(data._id)) { | ||
| const resolve = pendingRequests.get(data._id); | ||
| pendingRequests.delete(data._id); | ||
| resolve(data.result); | ||
| return; | ||
| } |
| const id = generateRequestId(); | ||
| message._id = id; | ||
|
|
||
| const promise = new Promise((resolve) => { | ||
| const timeout = setTimeout(() => { | ||
| if (pendingRequests.has(id)) { | ||
| pendingRequests.delete(id); | ||
| resolve(undefined); | ||
| } | ||
| }, REQUEST_TIMEOUT_MS); | ||
|
|
||
| pendingRequests.set(id, (response) => { | ||
| clearTimeout(timeout); | ||
| resolve(response); | ||
| }); | ||
| }); | ||
|
|
||
| target.postMessage(message, "*"); | ||
|
|
||
| return promise; |
| 'usergroup': 'user_group/:uuid', | ||
| 'usergrouplist': 'user_group', | ||
|
|
| export default { | ||
| navigate: function(route, params) { | ||
| push: function(route, params) { | ||
| return sendToApp("navigate", getRoute(route, params)); | ||
| }, | ||
|
|
||
| back: function() { | ||
| return sendToApp("back"); | ||
| }, | ||
|
|
||
| /** | ||
| * @param newsId string | number legacy apps use ID's the other ones use UUID's | ||
| * @param replace boolean When setting replace to true the current view will be replaced with the new view | ||
| */ | ||
| news: function(newsId, replace = false) { | ||
| return this.navigate('news', { id: newsId, replace: replace }); | ||
| replace: function(route, params) { | ||
| return sendToApp("navigate", {...getRoute(route, params), replace: true}); | ||
| }, | ||
|
|
||
| /** | ||
| * @param categoryId string | number legacy apps use ID's the other ones use UUID's | ||
| * @param replace boolean When setting replace to true the current view will be replaced with the new view | ||
| */ | ||
| newslist: function(categoryId, replace = false) { | ||
| return this.navigate('newslist', { id: categoryId, replace: replace }); | ||
| back: function() { | ||
| return sendToApp("back"); | ||
| }, |
| { | ||
| "name": "@bundeling/app-sdk", | ||
| "version": "1.0.5", | ||
| "version": "1.0.6", |
| test('sendToApp should post a message with a correlation id', () => { | ||
| window.parent.postMessage = jest.fn(); | ||
| sdk.sendToApp('test', { data: 'data' }); | ||
| expect(window.parent.postMessage).toHaveBeenCalledWith(message, originTarget); | ||
|
|
||
| expect(window.parent.postMessage).toHaveBeenCalledTimes(1); | ||
| const [message, targetOrigin] = window.parent.postMessage.mock.calls[0]; | ||
| expect(targetOrigin).toBe('*'); | ||
| expect(message).toEqual(expect.objectContaining({ type: 'test', data: 'data' })); | ||
| expect(typeof message._id).toBe('string'); | ||
| }); |
| ['customer', { uuid: 'abc' }, 'customer/abc'], | ||
| ['customerlist', {}, 'customer'], |
| describe('push', () => { | ||
| test.each(routeCases)('push(%s) routes to %s', (route, params, expected) => { | ||
| navigate.push(route, params); | ||
| expectPosted({ type: 'navigate', route: expected, params: params }); | ||
| }); |
| | alert | message: string, title?: string | Displays an alert dialog with a message and an optional title. | | ||
| | toast | message: string | Displays a toast message at the bottom of the screen. | |
| | Route | Path | Required params | | ||
| |---------------------|-----------------------------------|-----------------| | ||
| | user | user/:uuid | uuid | | ||
| | userlist | user | - | | ||
| | customer | customer/:uuid | uuid | | ||
| | customerlist | customer | - | | ||
| | news | news/:uuid | uuid | | ||
| | newslist | news | - | | ||
| | event | event/:uuid | uuid | | ||
| | eventlist | event | - | |
10d3096 to
486ef4a
Compare
Added responses
Added routes