Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# SmartApp bridge library

This library provides a universal interface for exchanging events with an express client.
Andriod, iOS and Web clients supported.
Andriod, iOS, Aurora and Web clients supported.

All types can be found [here](https://smartapp.ccsteam.xyz/smartapp-bridge/).

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@expressms/smartapp-bridge",
"version": "1.4.5",
"version": "1.5.0-alpha.0",
"description": "SmartApp bridge library",
"main": "build/main/index.js",
"typings": "build/main/index.d.ts",
Expand Down
3 changes: 3 additions & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { PLATFORM } from './lib/constants'
import getPlatform from './lib/platformDetector'
import AndroidBridge from './lib/platforms/android'
import AuroraBridge from './lib/platforms/aurora'
import IosBridge from './lib/platforms/ios'
import WebBridge from './lib/platforms/web'
import { Bridge } from './types/bridgeInterface'
Expand All @@ -15,6 +16,8 @@ const getBridge = (): Bridge | null => {
switch (platform) {
case PLATFORM.ANDROID:
return new AndroidBridge()
case PLATFORM.AURORA:
return new AuroraBridge()
case PLATFORM.IOS:
return new IosBridge()
case PLATFORM.WEB:
Expand Down
1 change: 1 addition & 0 deletions src/lib/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum PLATFORM {
WEB = 'web',
IOS = 'ios',
ANDROID = 'android',
AURORA = 'aurora',
UNKNOWN = 'unknown',
}

Expand Down
6 changes: 5 additions & 1 deletion src/lib/platformDetector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ const detectPlatformByUserAgent = (): PLATFORM => {
)
return PLATFORM.IOS

if (/aurora/i.test(navigator.userAgent)) {
return PLATFORM.AURORA
}

return PLATFORM.WEB
}

Expand All @@ -30,7 +34,7 @@ const detectPlatformByUserAgent = (): PLATFORM => {
* ```typescript
* const platform = getPlatform();
*
* // => 'web' | 'ios' | 'android'
* // => 'web' | 'ios' | 'android' | 'aurora'
* ```
*/
const getPlatform = (): PLATFORM => {
Expand Down
234 changes: 234 additions & 0 deletions src/lib/platforms/aurora.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
import { v4 as uuid } from 'uuid'

import {
Bridge,
BridgeSendBotEventParams,
BridgeSendClientEventParams,
BridgeSendEventParams,
EventEmitterCallback,
} from '../../types'
import { camelCaseToSnakeCase, snakeCaseToCamelCase } from '../case'
import { EVENT_TYPE, HANDLER, RESPONSE_TIMEOUT, SYNC_RESPONSE_TIMEOUT, WEB_COMMAND_TYPE_RPC } from '../constants'
import ExtendedEventEmitter from '../eventEmitter'
import Logger from '../logger'

class AuroraBridge extends Logger implements Bridge {
private readonly eventEmitter: ExtendedEventEmitter
isRenameParamsEnabledForBotx: boolean

constructor() {
super()

this.eventEmitter = new ExtendedEventEmitter()
this.isRenameParamsEnabledForBotx = true
window.handleAuroraEvent = this.handleAuroraEvent.bind(this)
}

private handleAuroraEvent({
ref,
data,
files,
}: {
readonly ref: string
readonly data: {
readonly type: string
}
readonly files: any
}): void {
this.logRecvEvent({ ref, data, files })

const { type, ...payload } = data

const emitterType = ref || EVENT_TYPE.RECEIVE

const eventFiles = this.isRenameParamsEnabledForBotx ? files?.map((file: any) => snakeCaseToCamelCase(file)) : files

const event = {
ref,
type,
payload: this.isRenameParamsEnabledForBotx ? snakeCaseToCamelCase(payload) : payload,
files: eventFiles,
}

this.eventEmitter.emit(emitterType, event)
}

/**
* Set callback function to handle events without **ref**
* (notifications for example).
*
* ```js
* bridge.onRecieve(({ type, handler, payload }) => {
* // Handle event data
* console.log('event', type, handler, payload)
* })
* ```
* @param callback - Callback function.
*/
onReceive(callback: EventEmitterCallback) {
this.eventEmitter.on(EVENT_TYPE.RECEIVE, callback)
}

private sendEvent({
handler,
method,
params,
files,
timeout = RESPONSE_TIMEOUT,
guaranteed_delivery_required = false,
sync_request = false,
sync_request_timeout = SYNC_RESPONSE_TIMEOUT,
hide_send_event_data = false,
hide_recv_event_data = false,
}: BridgeSendEventParams) {
const ref = uuid() // UUID to detect express response.
const isRenameParamsEnabled = handler === HANDLER.BOTX ? this.isRenameParamsEnabledForBotx : true
const eventProps = {
ref,
type: WEB_COMMAND_TYPE_RPC,
method,
handler,
payload: isRenameParamsEnabled ? camelCaseToSnakeCase(params) : params,
guaranteed_delivery_required,
sync_request,
sync_request_timeout,
hide_send_event_data,
hide_recv_event_data,
}

const eventFiles = isRenameParamsEnabled ? files?.map((file: any) => camelCaseToSnakeCase(file)) : files

const event = files ? { ...eventProps, files: eventFiles } : eventProps

this.logSendEvent(event)

const customEvent = new CustomEvent('framescript:action', { detail: event })
document.dispatchEvent(customEvent)

return this.eventEmitter.onceWithTimeout(ref, timeout)
}

/**
* Send event and wait response from express client.
*
* ```js
* bridge
* .sendBotEvent(
* {
* method: 'get_weather',
* params: {
* city: 'Moscow',
* },
* files: []
* }
* )
* .then(data => {
* // Handle response
* console.log('response', data)
* })
* ```
*/
sendBotEvent({
method,
params,
files,
timeout = RESPONSE_TIMEOUT,
guaranteed_delivery_required,
sync_request,
sync_request_timeout,
hide_send_event_data,
hide_recv_event_data,
}: BridgeSendBotEventParams) {
return this.sendEvent({
handler: HANDLER.BOTX,
method,
params,
files,
timeout,
guaranteed_delivery_required,
sync_request,
sync_request_timeout,
hide_send_event_data,
hide_recv_event_data,
})
}

/**
* Send event and wait response from express client.
*
* ```js
* bridge
* .sendClientEvent(
* {
* type: 'get_weather',
* handler: 'express',
* payload: {
* city: 'Moscow',
* },
* }
* )
* .then(data => {
* // Handle response
* console.log('response', data)
* })
* ```
*/
sendClientEvent({
method,
params,
timeout = RESPONSE_TIMEOUT,
hide_send_event_data,
hide_recv_event_data,
}: BridgeSendClientEventParams) {
return this.sendEvent({
handler: HANDLER.EXPRESS,
method,
params,
timeout,
hide_send_event_data,
hide_recv_event_data,
})
}

/**
* Enabling renaming event params from camelCase to snake_case and vice versa
* ```js
* bridge
* .enableRenameParams()
* ```
*/
enableRenameParams() {
this.isRenameParamsEnabledForBotx = true
console.log('Bridge ~ Enabled renaming event params from camelCase to snake_case and vice versa')
}

/**
* Enabling renaming event params from camelCase to snake_case and vice versa
* ```js
* bridge
* .disableRenameParams()
* ```
*/
disableRenameParams() {
this.isRenameParamsEnabledForBotx = false
console.log('Bridge ~ Disabled renaming event params from camelCase to snake_case and vice versa')
}

/**
* Write log to client
* @param data Any data to log
*/
log(data: string | object): void {
let value: typeof data = ''
if (typeof data === 'string') {
value = data
} else if (typeof data === 'object') {
value = JSON.stringify(data, null, 2)
} else return

const event = new CustomEvent('framescript:action', { detail: { 'SmartApp Log': value } })
document.dispatchEvent(event)
}
}

export default AuroraBridge
3 changes: 3 additions & 0 deletions src/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ declare global {
}
}
}

// Aurora interface
handleAuroraEvent: Function
}
}
2 changes: 1 addition & 1 deletion src/version.ts
Original file line number Diff line number Diff line change
@@ -1 +1 @@
export const LIB_VERSION = "1.4.4";
export const LIB_VERSION = "1.5.0";
49 changes: 49 additions & 0 deletions test/aurora.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>SmartApp bridge testing</title>
<style>
* {
font-family: Arial, Helvetica, sans-serif;
}
</style>
</head>

<body>
<h1>Test bridge for Aurora</h1>
<button onclick="sendMessageToClient()">Send message to client</button>
<textarea style="width: 100%; height: 80vh; margin-top: 10px;" id="log"></textarea>
<script>
function log(...data) {
var value = data.map(d => typeof d === 'object' && JSON.stringify(d) || `${d}`).join(", ");
document.getElementById("log").value += `${value}\r\n`;
}

function send(topic) {
var customEvent = new CustomEvent("framescript:action",
{detail: { topic: topic}});
document.dispatchEvent(customEvent);
}

window.addEventListener("DOMContentLoaded", function (event) {
log('originalTarget', event.originalTarget);
log('originalTarget name =',
event.originalTarget &&
event.originalTarget.__proto__ &&
event.originalTarget.__proto__.constructor &&
event.originalTarget.__proto__.constructor.name
);
});

// Отправка события
function sendMessageToClient() {
send('hello world')
log('Event sent');
}
</script>
</body>

</html>
Loading