@ionic/portals-react-native 0.2.0 → 0.4.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 +2 -2
- package/ReactNativePortals.podspec +14 -14
- package/android/build.gradle +4 -5
- package/android/gradle.properties +1 -1
- package/android/src/main/java/io/ionic/portals/reactnative/PortalView.kt +14 -4
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativeLiveUpdatesModule.kt +57 -74
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalManager.kt +84 -21
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsModule.kt +19 -22
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativePortalsPackage.kt +1 -0
- package/android/src/main/java/io/ionic/portals/reactnative/ReactNativeWebVitalsModule.kt +52 -0
- package/ios/AssetMap+Dict.swift +28 -0
- package/ios/ConcurrentDictionary.swift +45 -0
- package/ios/LiveUpdateManager+Async.swift +7 -7
- package/ios/Podfile +3 -4
- package/ios/Podfile.lock +13 -13
- package/ios/Portal.swift +108 -0
- package/ios/PortalManager.m +1 -1
- package/ios/PortalView.swift +1 -1
- package/ios/PortalWebVitals.m +15 -0
- package/ios/PortalsConfig.swift +18 -7
- package/ios/PortalsPubSub.swift +1 -0
- package/ios/PortalsReactNative.swift +1 -1
- package/ios/ReactNativePortals.xcodeproj/project.pbxproj +24 -4
- package/ios/SyncResult+Dict.swift +35 -0
- package/ios/WebVitals.swift +35 -0
- package/lib/commonjs/PortalView.android.js.map +1 -1
- package/lib/commonjs/PortalView.js.map +1 -1
- package/lib/commonjs/index.js +63 -3
- package/lib/commonjs/index.js.map +1 -1
- package/lib/module/PortalView.android.js.map +1 -1
- package/lib/module/PortalView.js.map +1 -1
- package/lib/module/index.js +55 -2
- package/lib/module/index.js.map +1 -1
- package/lib/typescript/index.d.ts +51 -7
- package/package.json +1 -1
- package/src/index.ts +128 -5
- package/ios/Portal+Dict.swift +0 -35
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["IONPortalPubSub","IONPortalsReactNative","NativeModules","PortalsPubSub","NativeEventEmitter","subscriptionMap","Map","subscribe","topic","onMessageReceived","subscriptionRef","subscriber","addListener","message","set","unsubscribe","subRef","subscription","get","undefined","remove","delete","publish","data","msg","register","key","addPortal","portal","addPortals","portals","getPortal","name","enableSecureLiveUpdates","pathToKey","syncOne","appId","syncSome","appIds","syncAll"],"sources":["index.ts"],"sourcesContent":["import {\n EmitterSubscription,\n NativeEventEmitter,\n NativeModules,\n ViewProps,\n} from 'react-native';\n\nconst { IONPortalPubSub, IONPortalsReactNative } = NativeModules;\n\nexport { default as PortalView } from './PortalView';\n\n/**\n * The data that is received from a subscription event.\n */\nexport interface Message {\n /** The unique subscription reference received from {@link subscribe}*/\n subscriptionRef: number;\n data: any;\n /** The topic the message was sent from */\n topic: string;\n}\n\nconst PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);\n\nconst subscriptionMap = new Map<number, EmitterSubscription>();\n\n/**\n * Subscribes to messages for a topic\n *\n * @param topic The topic to subscribe to\n * @param onMessageReceived The callback to invoke when a message is received\n * @returns A Promise<number> containing the unique subscription reference. This will need to be stored for calling {@link unsubscribe}.\n */\nexport const subscribe = async (\n topic: string,\n onMessageReceived: (message: Message) => void\n): Promise<number> => {\n const subscriptionRef = await IONPortalPubSub.subscribe(topic);\n\n const subscriber = PortalsPubSub.addListener(\n 'PortalsSubscription',\n (message: Message) => {\n if (message.subscriptionRef === subscriptionRef) {\n onMessageReceived(message);\n }\n }\n );\n\n subscriptionMap.set(subscriptionRef, subscriber);\n\n return subscriptionRef;\n};\n\n/**\n * Unsubscribes from events for the provided topic and subscription reference\n *\n * @param topic The topic to unsubscribe from\n * @param subRef The unique subscription reference received when initially calling {@link subscribe}\n */\nexport const unsubscribe = (topic: string, subRef: number) => {\n IONPortalPubSub.unsubscribe(topic, subRef);\n\n const subscription = subscriptionMap.get(subRef);\n if (subscription !== undefined) {\n subscription.remove();\n subscriptionMap.delete(subRef);\n }\n};\n\n/**\n * Publishes a message to the provided topic\n *\n * @param topic The topic to publish the message to\n * @param data The data to publish to subscribers\n */\nexport const publish = (topic: string, data: any) => {\n const msg = { message: data };\n IONPortalPubSub.publish(topic, msg);\n};\n\n/**\n * Validates that a valid registration key has been procured from http://ionic.io/register-portals\n * @param key The registration key\n * @returns Promise<void>\n */\nexport const register = async (key: string): Promise<void> => {\n return IONPortalsReactNative.register(key);\n};\n\n/**\n * The configuration of a web application to be embedded in a React Native application.\n */\nexport interface Portal {\n /** The name of the Portal to be referenced. Must be **unique** */\n name: string;\n /** The classpath of all Capacitor plugins used in Android. (e.g. com.capacitorjs.plugins.camera.CameraPlugin) */\n androidPlugins?: string[];\n /**\n * The root directory of the web application relative to Bundle.main on iOS\n * and src/main/assets on Android. If omitted, `name` is used.\n */\n startDir?: string;\n /** The name of the initial file to load. If omitted, 'index.html' is used. */\n index?: string;\n /** Any data needed at initial render when a portal is loaded. */\n initialContext?: {\n [key: string]: any;\n };\n liveUpdate?: LiveUpdateConfig;\n}\n\n/**\n * A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override\n * any initialContext defined in the original {@link Portal} definition.\n */\nexport type PortalProp = {\n portal: Pick<Portal, 'name' | 'initialContext'>;\n};\n\n/**\n * Props needed for rendering a {@link Portal}\n */\nexport type PortalProps = PortalProp & ViewProps;\n\n/**\n * Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.\n *\n * @param portal The portal to add to the internal registry.\n * @returns Promise containing the Portal that was added to the registry.\n */\nexport const addPortal = async (portal: Portal): Promise<Portal> => {\n return IONPortalsReactNative.addPortal(portal);\n};\n\n/**\n * Adds all portals to an internal registry. This or {@link addPortal} must be called before attempting to render a {@link PortalView}\n *\n * @param portals The portals to add to the internal registry.\n * @returns Promise containing the Portals that were added to the registry.\n */\nexport const addPortals = async (portals: Portal[]): Promise<Portal[]> => {\n return IONPortalsReactNative.addPortals(portals);\n};\n\n/**\n * Gets a {@link Portal} previously registered via {@link addPortal} or {@link addPortals}.\n *\n * @param name The portal name to retrieve from the internal registry.\n * @returns Promise containing the registered {@link Portal}. If the {@link Portal} was not registered, the Promise will fail.\n */\nexport const getPortal = async (name: string): Promise<Portal> => {\n return IONPortalsReactNative.getPortal(name);\n};\n\nexport interface LiveUpdate {\n /** The AppFlow application ID */\n appId: string;\n /** The AppFlow distribution channel */\n channel: string;\n}\n\n/** Data needed to register a live update to be managed */\nexport type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };\n\nexport interface LiveUpdateError {\n /** The AppFlow application ID relating to the failure */\n appId: string;\n /** The step in the sync process the LiveUpdate failed on. (e.g. CHECK, UNPACK)*/\n failStep: string;\n /** A human readable error message */\n message: string;\n}\n\n/** Used for communicating sync results of multiple live updates */\nexport interface SyncResults {\n liveUpdates: LiveUpdate[];\n errors: LiveUpdateError[];\n}\n\n/**\n * Configures LiveUpdates to cyrptographically verify the contents of the downloaded bundles.\n * This method must be called before any LiveUpdates are registered otherwise they will no longer be tracked.\n *\n * @param pathToKey The *relative* path to the public key for verification.\n * This path should be the same relatibe to the main application bundle on iOS and the assets directory on Android.\n * @returns Promise<void>\n */\nexport const enableSecureLiveUpdates = async (\n pathToKey: string\n): Promise<void> => {\n return IONPortalsReactNative.enableSecureLiveUpdates(pathToKey);\n};\n\n/**\n * Syncs a single live update.\n *\n * @param appId The AppFlow application ID to sync.\n * @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.\n */\nexport const syncOne = async (appId: string): Promise<LiveUpdate> => {\n return IONPortalsReactNative.syncOne(appId);\n};\n\n/**\n * Syncs many live updates.\n *\n * @param appIds The AppFlow application IDs to sync.\n * @returns Promise<SyncResults>\n */\nexport const syncSome = async (appIds: string[]): Promise<SyncResults> => {\n return IONPortalsReactNative.syncSome(appIds);\n};\n\n/**\n * Syncs all registered LiveUpdates\n * @returns Promise<SyncResults>\n */\nexport const syncAll = async (): Promise<SyncResults> => {\n return IONPortalsReactNative.syncAll();\n};\n"],"mappings":";;;;;;;;;;;;AAAA;AASA;AAAqD;AAFrD,MAAM;EAAEA,eAAe;EAAEC;AAAsB,CAAC,GAAGC,0BAAa;AAehE,MAAMC,aAAa,GAAG,IAAIC,+BAAkB,CAACJ,eAAe,CAAC;AAE7D,MAAMK,eAAe,GAAG,IAAIC,GAAG,EAA+B;;AAE9D;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,SAAS,GAAG,OACvBC,KAAa,EACbC,iBAA6C,KACzB;EACpB,MAAMC,eAAe,GAAG,MAAMV,eAAe,CAACO,SAAS,CAACC,KAAK,CAAC;EAE9D,MAAMG,UAAU,GAAGR,aAAa,CAACS,WAAW,CAC1C,qBAAqB,EACpBC,OAAgB,IAAK;IACpB,IAAIA,OAAO,CAACH,eAAe,KAAKA,eAAe,EAAE;MAC/CD,iBAAiB,CAACI,OAAO,CAAC;IAC5B;EACF,CAAC,CACF;EAEDR,eAAe,CAACS,GAAG,CAACJ,eAAe,EAAEC,UAAU,CAAC;EAEhD,OAAOD,eAAe;AACxB,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALA;AAMO,MAAMK,WAAW,GAAG,CAACP,KAAa,EAAEQ,MAAc,KAAK;EAC5DhB,eAAe,CAACe,WAAW,CAACP,KAAK,EAAEQ,MAAM,CAAC;EAE1C,MAAMC,YAAY,GAAGZ,eAAe,CAACa,GAAG,CAACF,MAAM,CAAC;EAChD,IAAIC,YAAY,KAAKE,SAAS,EAAE;IAC9BF,YAAY,CAACG,MAAM,EAAE;IACrBf,eAAe,CAACgB,MAAM,CAACL,MAAM,CAAC;EAChC;AACF,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALA;AAMO,MAAMM,OAAO,GAAG,CAACd,KAAa,EAAEe,IAAS,KAAK;EACnD,MAAMC,GAAG,GAAG;IAAEX,OAAO,EAAEU;EAAK,CAAC;EAC7BvB,eAAe,CAACsB,OAAO,CAACd,KAAK,EAAEgB,GAAG,CAAC;AACrC,CAAC;;AAED;AACA;AACA;AACA;AACA;AAJA;AAKO,MAAMC,QAAQ,GAAG,MAAOC,GAAW,IAAoB;EAC5D,OAAOzB,qBAAqB,CAACwB,QAAQ,CAACC,GAAG,CAAC;AAC5C,CAAC;;AAED;AACA;AACA;AAFA;AAmCA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,SAAS,GAAG,MAAOC,MAAc,IAAsB;EAClE,OAAO3B,qBAAqB,CAAC0B,SAAS,CAACC,MAAM,CAAC;AAChD,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALA;AAMO,MAAMC,UAAU,GAAG,MAAOC,OAAiB,IAAwB;EACxE,OAAO7B,qBAAqB,CAAC4B,UAAU,CAACC,OAAO,CAAC;AAClD,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALA;AAMO,MAAMC,SAAS,GAAG,MAAOC,IAAY,IAAsB;EAChE,OAAO/B,qBAAqB,CAAC8B,SAAS,CAACC,IAAI,CAAC;AAC9C,CAAC;AAAC;AA2BF;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,MAAMC,uBAAuB,GAAG,MACrCC,SAAiB,IACC;EAClB,OAAOjC,qBAAqB,CAACgC,uBAAuB,CAACC,SAAS,CAAC;AACjE,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALA;AAMO,MAAMC,OAAO,GAAG,MAAOC,KAAa,IAA0B;EACnE,OAAOnC,qBAAqB,CAACkC,OAAO,CAACC,KAAK,CAAC;AAC7C,CAAC;;AAED;AACA;AACA;AACA;AACA;AACA;AALA;AAMO,MAAMC,QAAQ,GAAG,MAAOC,MAAgB,IAA2B;EACxE,OAAOrC,qBAAqB,CAACoC,QAAQ,CAACC,MAAM,CAAC;AAC/C,CAAC;;AAED;AACA;AACA;AACA;AAHA;AAIO,MAAMC,OAAO,GAAG,YAAkC;EACvD,OAAOtC,qBAAqB,CAACsC,OAAO,EAAE;AACxC,CAAC;AAAC"}
|
|
1
|
+
{"version":3,"names":["_reactNative","require","_PortalView","_interopRequireDefault","obj","__esModule","default","IONPortalPubSub","IONPortalsReactNative","IONPortalsWebVitals","NativeModules","PortalsPubSub","NativeEventEmitter","subscriptionMap","Map","subscribe","topic","onMessageReceived","subscriptionRef","subscriber","addListener","message","set","exports","webVitalsMap","WebVitals","onFirstContentfulPaint","portalName","callback","listener","event","duration","registerOnFirstContentfulPaint","onFirstInputDelay","Platform","OS","registerOnFirstInputDelay","onTimeToFirstByte","registerOnTimeToFirstByte","registerWebVitals","firstContentfulPaint","firstInputDelay","timeToFirstByte","unsubscribe","subRef","subscription","get","undefined","remove","delete","publish","data","msg","register","key","addPortal","portal","addPortals","portals","getPortal","name","enableSecureLiveUpdates","pathToKey","syncOne","appId","syncSome","appIds","syncAll"],"sources":["index.ts"],"sourcesContent":["import {\n EmitterSubscription,\n NativeEventEmitter,\n NativeModules,\n Platform,\n ViewProps,\n} from 'react-native';\n\nconst { IONPortalPubSub, IONPortalsReactNative, IONPortalsWebVitals } =\n NativeModules;\n\nexport { default as PortalView } from './PortalView';\n\n/**\n * The data that is received from a subscription event.\n */\nexport interface Message {\n /** The unique subscription reference received from {@link subscribe}*/\n subscriptionRef: number;\n data: any;\n /** The topic the message was sent from */\n topic: string;\n}\n\nconst PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);\n\nconst subscriptionMap = new Map<number, EmitterSubscription>();\n\n/**\n * Subscribes to messages for a topic\n *\n * @param topic The topic to subscribe to\n * @param onMessageReceived The callback to invoke when a message is received\n * @returns A Promise<number> containing the unique subscription reference. This will need to be stored for calling {@link unsubscribe}.\n */\nexport const subscribe = async (\n topic: string,\n onMessageReceived: (message: Message) => void\n): Promise<number> => {\n const subscriptionRef = await IONPortalPubSub.subscribe(topic);\n\n const subscriber = PortalsPubSub.addListener(\n 'PortalsSubscription',\n (message: Message) => {\n if (message.subscriptionRef === subscriptionRef) {\n onMessageReceived(message);\n }\n }\n );\n\n subscriptionMap.set(subscriptionRef, subscriber);\n\n return subscriptionRef;\n};\n\nconst webVitalsMap = new Map<string, EmitterSubscription>();\nconst WebVitals = new NativeEventEmitter(IONPortalsWebVitals);\n\ninterface WebVitalsEvent {\n portalName: string;\n duration: number;\n}\n\nexport const onFirstContentfulPaint = async (\n portalName: string,\n callback: (duration: number) => void\n): Promise<void> => {\n const listener = WebVitals.addListener(\n 'vitals:fcp',\n (event: WebVitalsEvent) => {\n if (event.portalName === portalName) {\n callback(event.duration);\n }\n }\n );\n\n await IONPortalsWebVitals.registerOnFirstContentfulPaint(portalName);\n\n webVitalsMap.set(`${portalName}-vitals:fcp`, listener);\n};\n\nexport const onFirstInputDelay = async (\n portalName: string,\n callback: (duration: number) => void\n) => {\n if (Platform.OS === 'android') {\n const listener = WebVitals.addListener(\n 'vitals:fid',\n (event: WebVitalsEvent) => {\n if (event.portalName === portalName) {\n callback(event.duration);\n }\n }\n );\n\n await IONPortalsWebVitals.registerOnFirstInputDelay(portalName);\n\n webVitalsMap.set(`${portalName}-vitals:fcp`, listener);\n }\n};\n\nexport const onTimeToFirstByte = async (\n portalName: string,\n callback: (duration: number) => void\n) => {\n if (Platform.OS === 'android') {\n const listener = WebVitals.addListener(\n 'vitals:ttfb',\n (event: WebVitalsEvent) => {\n if (event.portalName === portalName) {\n callback(event.duration);\n }\n }\n );\n\n await IONPortalsWebVitals.registerOnTimeToFirstByte(portalName);\n\n webVitalsMap.set(`${portalName}-vitals:ttfb`, listener);\n }\n};\n\nexport const registerWebVitals = async (\n portalName: string,\n firstContentfulPaint: (duration: number) => void,\n firstInputDelay: (duration: number) => void,\n timeToFirstByte: (duration: number) => void\n) => {\n onFirstContentfulPaint(portalName, firstContentfulPaint);\n onFirstInputDelay(portalName, firstInputDelay);\n onTimeToFirstByte(portalName, timeToFirstByte);\n};\n\n/**\n * Unsubscribes from events for the provided topic and subscription reference\n *\n * @param topic The topic to unsubscribe from\n * @param subRef The unique subscription reference received when initially calling {@link subscribe}\n */\nexport const unsubscribe = (topic: string, subRef: number) => {\n IONPortalPubSub.unsubscribe(topic, subRef);\n\n const subscription = subscriptionMap.get(subRef);\n if (subscription !== undefined) {\n subscription.remove();\n subscriptionMap.delete(subRef);\n }\n};\n\n/**\n * Publishes a message to the provided topic\n *\n * @param topic The topic to publish the message to\n * @param data The data to publish to subscribers\n */\nexport const publish = (topic: string, data: any) => {\n const msg = { message: data };\n IONPortalPubSub.publish(topic, msg);\n};\n\n/**\n * Validates that a valid registration key has been procured from http://ionic.io/register-portals\n * @param key The registration key\n * @returns Promise<void>\n */\nexport const register = async (key: string): Promise<void> => {\n return IONPortalsReactNative.register(key);\n};\n\n/**\n * The configuration of a web application to be embedded in a React Native application.\n */\nexport interface Portal {\n /** The name of the Portal to be referenced. Must be **unique** */\n name: string;\n /** Any Capacitor plugins to be made available to the Portal */\n plugins?: CapacitorPlugin[];\n /**\n * The root directory of the web application relative to Bundle.main on iOS\n * and src/main/assets on Android. If omitted, `name` is used.\n */\n startDir?: string;\n /** The name of the initial file to load. If omitted, 'index.html' is used. */\n index?: string;\n /** Any data needed at initial render when a portal is loaded. */\n initialContext?: {\n [key: string]: any;\n };\n assetMaps?: AssetMap[];\n liveUpdate?: LiveUpdateConfig;\n}\n\nexport interface CapacitorPlugin {\n /** The classpath of the plugin to be used in Android. (e.g. com.capacitorjs.plugins.camera.CameraPlugin) */\n androidClassPath: string;\n /** The class name of the plugin to be used in iOS.\n * This must be the name as it is exposed to the Objective-C runtime.\n * For example, The CameraPlugin swift class is exposed to Objective-C as CAPCameraPlugin.\n */\n iosClassName: string;\n}\n\nexport interface AssetMap {\n /** The name to index the asset map by */\n name: string;\n /** Any path to match via the web. If omitted, {@link AssetMap#name} will be used. */\n virtualPath?: string;\n /** The root directory of the assets relative to Bundle.main on iOS\n * and src/main/assets on Android. If omitted, the root of Bundle.main\n * and src/main/assets will be used.\n */\n startDir?: string;\n}\n\n/**\n * A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override\n * any initialContext defined in the original {@link Portal} definition.\n */\nexport type PortalProp = {\n portal: Pick<Portal, 'name' | 'initialContext'>;\n};\n\n/**\n * Props needed for rendering a {@link Portal}\n */\nexport type PortalProps = PortalProp & ViewProps;\n\n/**\n * Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.\n *\n * @param portal The portal to add to the internal registry.\n * @returns Promise containing the Portal that was added to the registry.\n */\nexport const addPortal = async (portal: Portal): Promise<Portal> => {\n return IONPortalsReactNative.addPortal(portal);\n};\n\n/**\n * Adds all portals to an internal registry. This or {@link addPortal} must be called before attempting to render a {@link PortalView}\n *\n * @param portals The portals to add to the internal registry.\n * @returns Promise containing the Portals that were added to the registry.\n */\nexport const addPortals = async (portals: Portal[]): Promise<Portal[]> => {\n return IONPortalsReactNative.addPortals(portals);\n};\n\n/**\n * Gets a {@link Portal} previously registered via {@link addPortal} or {@link addPortals}.\n *\n * @param name The portal name to retrieve from the internal registry.\n * @returns Promise containing the registered {@link Portal}. If the {@link Portal} was not registered, the Promise will fail.\n */\nexport const getPortal = async (name: string): Promise<Portal> => {\n return IONPortalsReactNative.getPortal(name);\n};\n\nexport interface LiveUpdate {\n /** The AppFlow application ID */\n appId: string;\n /** The AppFlow distribution channel */\n channel: string;\n}\n\n/** Data needed to register a live update to be managed */\nexport type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };\n\nexport interface LiveUpdateError {\n /** The AppFlow application ID relating to the failure */\n appId: string;\n /** The step in the sync process the LiveUpdate failed on. (e.g. CHECK, UNPACK)*/\n failStep: string;\n /** A human readable error message */\n message: string;\n}\n\nexport interface Snapshot {\n /** The snapshot id as found in AppFlow */\n id: string;\n /** The AppFlow build id that produced the snapshot */\n buildId: string;\n}\n\nexport interface SyncResult {\n /** The {@link LiveUpdate} associated with the result */\n liveUpdate: LiveUpdate;\n /** The {@link Snapshot} that was sync'd */\n snapshot: Snapshot | null;\n /** Whether the snapshot was downloaded or already on disk */\n source: 'download' | 'cache';\n /** If the active application path was changed. A `false` value would indicate\n * the application already has the latest code for the associated {@link LiveUpdate}\n * configuration.\n */\n activeApplicationPathChanged: boolean;\n}\n\n/** Used for communicating sync results of multiple live updates */\nexport interface SyncResults {\n results: SyncResult[];\n errors: LiveUpdateError[];\n}\n\n/**\n * Configures LiveUpdates to cyrptographically verify the contents of the downloaded bundles.\n * This method must be called before any LiveUpdates are registered otherwise they will no longer be tracked.\n *\n * @param pathToKey The *relative* path to the public key for verification.\n * This path should be the same relatibe to the main application bundle on iOS and the assets directory on Android.\n * @returns Promise<void>\n */\nexport const enableSecureLiveUpdates = async (\n pathToKey: string\n): Promise<void> => {\n return IONPortalsReactNative.enableSecureLiveUpdates(pathToKey);\n};\n\n/**\n * Syncs a single live update.\n *\n * @param appId The AppFlow application ID to sync.\n * @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.\n */\nexport const syncOne = async (appId: string): Promise<SyncResult> => {\n return IONPortalsReactNative.syncOne(appId);\n};\n\n/**\n * Syncs many live updates.\n *\n * @param appIds The AppFlow application IDs to sync.\n * @returns Promise<SyncResults>\n */\nexport const syncSome = async (appIds: string[]): Promise<SyncResults> => {\n return IONPortalsReactNative.syncSome(appIds);\n};\n\n/**\n * Syncs all registered LiveUpdates\n * @returns Promise<SyncResults>\n */\nexport const syncAll = async (): Promise<SyncResults> => {\n return IONPortalsReactNative.syncAll();\n};\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","useEffect","useRef","findNodeHandle","requireNativeComponent","UIManager","PortalViewManager","createFragment","viewId","dispatchViewManagerCommand","AndroidPortalView","Commands","create","toString","PortalView","props","ref","current"],"sources":["PortalView.android.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport {\n findNodeHandle,\n requireNativeComponent,\n UIManager,\n} from 'react-native';\nimport type { PortalProps } from '.';\n\nconst PortalViewManager = requireNativeComponent('AndroidPortalView');\n\nconst createFragment = (viewId: number | null) =>\n UIManager.dispatchViewManagerCommand(\n viewId,\n // we are calling the 'create' command\n // @ts-expect-error\n UIManager.AndroidPortalView.Commands.create.toString(),\n [viewId]\n );\n\nconst PortalView = (props: PortalProps) => {\n const ref = useRef(null);\n\n useEffect(() => {\n const viewId = findNodeHandle(ref.current);\n createFragment(viewId);\n }, []);\n\n return <PortalViewManager {...props} ref={ref} />;\n};\n\nexport default PortalView;\n"],"mappings":";AAAA,OAAOA,KAAK,IAAIC,SAAS,EAAEC,MAAM,QAAQ,OAAO;AAChD,SACEC,cAAc,EACdC,sBAAsB,EACtBC,SAAS,QACJ,cAAc;AAGrB,MAAMC,iBAAiB,GAAGF,sBAAsB,CAAC,mBAAmB,CAAC;AAErE,MAAMG,cAAc,GAAIC,MAAqB,IAC3CH,SAAS,CAACI,0BAA0B,CAClCD,MAAM;AACN;AACA;AACAH,SAAS,CAACK,iBAAiB,CAACC,QAAQ,CAACC,MAAM,CAACC,QAAQ,EAAE,EACtD,CAACL,MAAM,CAAC,CACT;AAEH,MAAMM,UAAU,GAAIC,KAAkB,IAAK;EACzC,MAAMC,GAAG,GAAGd,MAAM,CAAC,IAAI,CAAC;EAExBD,SAAS,CAAC,MAAM;IACd,MAAMO,MAAM,GAAGL,cAAc,CAACa,GAAG,CAACC,OAAO,CAAC;IAC1CV,cAAc,CAACC,MAAM,CAAC;EACxB,CAAC,EAAE,EAAE,CAAC;EAEN,
|
|
1
|
+
{"version":3,"names":["React","useEffect","useRef","findNodeHandle","requireNativeComponent","UIManager","PortalViewManager","createFragment","viewId","dispatchViewManagerCommand","AndroidPortalView","Commands","create","toString","PortalView","props","ref","current","createElement","_extends"],"sources":["PortalView.android.tsx"],"sourcesContent":["import React, { useEffect, useRef } from 'react';\nimport {\n findNodeHandle,\n requireNativeComponent,\n UIManager,\n} from 'react-native';\nimport type { PortalProps } from '.';\n\nconst PortalViewManager = requireNativeComponent('AndroidPortalView');\n\nconst createFragment = (viewId: number | null) =>\n UIManager.dispatchViewManagerCommand(\n viewId,\n // we are calling the 'create' command\n // @ts-expect-error\n UIManager.AndroidPortalView.Commands.create.toString(),\n [viewId]\n );\n\nconst PortalView = (props: PortalProps) => {\n const ref = useRef(null);\n\n useEffect(() => {\n const viewId = findNodeHandle(ref.current);\n createFragment(viewId);\n }, []);\n\n return <PortalViewManager {...props} ref={ref} />;\n};\n\nexport default PortalView;\n"],"mappings":";AAAA,OAAOA,KAAK,IAAIC,SAAS,EAAEC,MAAM,QAAQ,OAAO;AAChD,SACEC,cAAc,EACdC,sBAAsB,EACtBC,SAAS,QACJ,cAAc;AAGrB,MAAMC,iBAAiB,GAAGF,sBAAsB,CAAC,mBAAmB,CAAC;AAErE,MAAMG,cAAc,GAAIC,MAAqB,IAC3CH,SAAS,CAACI,0BAA0B,CAClCD,MAAM;AACN;AACA;AACAH,SAAS,CAACK,iBAAiB,CAACC,QAAQ,CAACC,MAAM,CAACC,QAAQ,EAAE,EACtD,CAACL,MAAM,CAAC,CACT;AAEH,MAAMM,UAAU,GAAIC,KAAkB,IAAK;EACzC,MAAMC,GAAG,GAAGd,MAAM,CAAC,IAAI,CAAC;EAExBD,SAAS,CAAC,MAAM;IACd,MAAMO,MAAM,GAAGL,cAAc,CAACa,GAAG,CAACC,OAAO,CAAC;IAC1CV,cAAc,CAACC,MAAM,CAAC;EACxB,CAAC,EAAE,EAAE,CAAC;EAEN,oBAAOR,KAAA,CAAAkB,aAAA,CAACZ,iBAAiB,EAAAa,QAAA,KAAKJ,KAAK;IAAEC,GAAG,EAAEA;EAAI,GAAG;AACnD,CAAC;AAED,eAAeF,UAAU"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","requireNativeComponent","HostComponentPortal","PortalView","props"],"sources":["PortalView.tsx"],"sourcesContent":["import React from 'react';\nimport { requireNativeComponent } from 'react-native';\nimport type { PortalProps } from '.';\n\nconst HostComponentPortal = requireNativeComponent('IONPortalView');\n\nconst PortalView = (props: PortalProps) => {\n return <HostComponentPortal {...props} />;\n};\n\nexport default PortalView;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,sBAAsB,QAAQ,cAAc;AAGrD,MAAMC,mBAAmB,GAAGD,sBAAsB,CAAC,eAAe,CAAC;AAEnE,MAAME,UAAU,GAAIC,KAAkB,IAAK;EACzC,
|
|
1
|
+
{"version":3,"names":["React","requireNativeComponent","HostComponentPortal","PortalView","props","createElement"],"sources":["PortalView.tsx"],"sourcesContent":["import React from 'react';\nimport { requireNativeComponent } from 'react-native';\nimport type { PortalProps } from '.';\n\nconst HostComponentPortal = requireNativeComponent('IONPortalView');\n\nconst PortalView = (props: PortalProps) => {\n return <HostComponentPortal {...props} />;\n};\n\nexport default PortalView;\n"],"mappings":"AAAA,OAAOA,KAAK,MAAM,OAAO;AACzB,SAASC,sBAAsB,QAAQ,cAAc;AAGrD,MAAMC,mBAAmB,GAAGD,sBAAsB,CAAC,eAAe,CAAC;AAEnE,MAAME,UAAU,GAAIC,KAAkB,IAAK;EACzC,oBAAOJ,KAAA,CAAAK,aAAA,CAACH,mBAAmB,EAAKE,KAAK,CAAI;AAC3C,CAAC;AAED,eAAeD,UAAU"}
|
package/lib/module/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { NativeEventEmitter, NativeModules } from 'react-native';
|
|
1
|
+
import { NativeEventEmitter, NativeModules, Platform } from 'react-native';
|
|
2
2
|
const {
|
|
3
3
|
IONPortalPubSub,
|
|
4
|
-
IONPortalsReactNative
|
|
4
|
+
IONPortalsReactNative,
|
|
5
|
+
IONPortalsWebVitals
|
|
5
6
|
} = NativeModules;
|
|
6
7
|
export { default as PortalView } from './PortalView';
|
|
7
8
|
|
|
@@ -29,6 +30,44 @@ export const subscribe = async (topic, onMessageReceived) => {
|
|
|
29
30
|
subscriptionMap.set(subscriptionRef, subscriber);
|
|
30
31
|
return subscriptionRef;
|
|
31
32
|
};
|
|
33
|
+
const webVitalsMap = new Map();
|
|
34
|
+
const WebVitals = new NativeEventEmitter(IONPortalsWebVitals);
|
|
35
|
+
export const onFirstContentfulPaint = async (portalName, callback) => {
|
|
36
|
+
const listener = WebVitals.addListener('vitals:fcp', event => {
|
|
37
|
+
if (event.portalName === portalName) {
|
|
38
|
+
callback(event.duration);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
await IONPortalsWebVitals.registerOnFirstContentfulPaint(portalName);
|
|
42
|
+
webVitalsMap.set(`${portalName}-vitals:fcp`, listener);
|
|
43
|
+
};
|
|
44
|
+
export const onFirstInputDelay = async (portalName, callback) => {
|
|
45
|
+
if (Platform.OS === 'android') {
|
|
46
|
+
const listener = WebVitals.addListener('vitals:fid', event => {
|
|
47
|
+
if (event.portalName === portalName) {
|
|
48
|
+
callback(event.duration);
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
await IONPortalsWebVitals.registerOnFirstInputDelay(portalName);
|
|
52
|
+
webVitalsMap.set(`${portalName}-vitals:fcp`, listener);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
export const onTimeToFirstByte = async (portalName, callback) => {
|
|
56
|
+
if (Platform.OS === 'android') {
|
|
57
|
+
const listener = WebVitals.addListener('vitals:ttfb', event => {
|
|
58
|
+
if (event.portalName === portalName) {
|
|
59
|
+
callback(event.duration);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
await IONPortalsWebVitals.registerOnTimeToFirstByte(portalName);
|
|
63
|
+
webVitalsMap.set(`${portalName}-vitals:ttfb`, listener);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
export const registerWebVitals = async (portalName, firstContentfulPaint, firstInputDelay, timeToFirstByte) => {
|
|
67
|
+
onFirstContentfulPaint(portalName, firstContentfulPaint);
|
|
68
|
+
onFirstInputDelay(portalName, firstInputDelay);
|
|
69
|
+
onTimeToFirstByte(portalName, timeToFirstByte);
|
|
70
|
+
};
|
|
32
71
|
|
|
33
72
|
/**
|
|
34
73
|
* Unsubscribes from events for the provided topic and subscription reference
|
|
@@ -71,6 +110,15 @@ export const register = async key => {
|
|
|
71
110
|
* The configuration of a web application to be embedded in a React Native application.
|
|
72
111
|
*/
|
|
73
112
|
|
|
113
|
+
/**
|
|
114
|
+
* A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override
|
|
115
|
+
* any initialContext defined in the original {@link Portal} definition.
|
|
116
|
+
*/
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Props needed for rendering a {@link Portal}
|
|
120
|
+
*/
|
|
121
|
+
|
|
74
122
|
/**
|
|
75
123
|
* Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.
|
|
76
124
|
*
|
|
@@ -100,6 +148,11 @@ export const addPortals = async portals => {
|
|
|
100
148
|
export const getPortal = async name => {
|
|
101
149
|
return IONPortalsReactNative.getPortal(name);
|
|
102
150
|
};
|
|
151
|
+
|
|
152
|
+
/** Data needed to register a live update to be managed */
|
|
153
|
+
|
|
154
|
+
/** Used for communicating sync results of multiple live updates */
|
|
155
|
+
|
|
103
156
|
/**
|
|
104
157
|
* Configures LiveUpdates to cyrptographically verify the contents of the downloaded bundles.
|
|
105
158
|
* This method must be called before any LiveUpdates are registered otherwise they will no longer be tracked.
|
package/lib/module/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["NativeEventEmitter","NativeModules","IONPortalPubSub","IONPortalsReactNative","default","PortalView","PortalsPubSub","subscriptionMap","Map","subscribe","topic","onMessageReceived","subscriptionRef","subscriber","addListener","message","set","unsubscribe","subRef","subscription","get","undefined","remove","delete","publish","data","msg","register","key","addPortal","portal","addPortals","portals","getPortal","name","enableSecureLiveUpdates","pathToKey","syncOne","appId","syncSome","appIds","syncAll"],"sources":["index.ts"],"sourcesContent":["import {\n EmitterSubscription,\n NativeEventEmitter,\n NativeModules,\n ViewProps,\n} from 'react-native';\n\nconst { IONPortalPubSub, IONPortalsReactNative } = NativeModules;\n\nexport { default as PortalView } from './PortalView';\n\n/**\n * The data that is received from a subscription event.\n */\nexport interface Message {\n /** The unique subscription reference received from {@link subscribe}*/\n subscriptionRef: number;\n data: any;\n /** The topic the message was sent from */\n topic: string;\n}\n\nconst PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);\n\nconst subscriptionMap = new Map<number, EmitterSubscription>();\n\n/**\n * Subscribes to messages for a topic\n *\n * @param topic The topic to subscribe to\n * @param onMessageReceived The callback to invoke when a message is received\n * @returns A Promise<number> containing the unique subscription reference. This will need to be stored for calling {@link unsubscribe}.\n */\nexport const subscribe = async (\n topic: string,\n onMessageReceived: (message: Message) => void\n): Promise<number> => {\n const subscriptionRef = await IONPortalPubSub.subscribe(topic);\n\n const subscriber = PortalsPubSub.addListener(\n 'PortalsSubscription',\n (message: Message) => {\n if (message.subscriptionRef === subscriptionRef) {\n onMessageReceived(message);\n }\n }\n );\n\n subscriptionMap.set(subscriptionRef, subscriber);\n\n return subscriptionRef;\n};\n\n/**\n * Unsubscribes from events for the provided topic and subscription reference\n *\n * @param topic The topic to unsubscribe from\n * @param subRef The unique subscription reference received when initially calling {@link subscribe}\n */\nexport const unsubscribe = (topic: string, subRef: number) => {\n IONPortalPubSub.unsubscribe(topic, subRef);\n\n const subscription = subscriptionMap.get(subRef);\n if (subscription !== undefined) {\n subscription.remove();\n subscriptionMap.delete(subRef);\n }\n};\n\n/**\n * Publishes a message to the provided topic\n *\n * @param topic The topic to publish the message to\n * @param data The data to publish to subscribers\n */\nexport const publish = (topic: string, data: any) => {\n const msg = { message: data };\n IONPortalPubSub.publish(topic, msg);\n};\n\n/**\n * Validates that a valid registration key has been procured from http://ionic.io/register-portals\n * @param key The registration key\n * @returns Promise<void>\n */\nexport const register = async (key: string): Promise<void> => {\n return IONPortalsReactNative.register(key);\n};\n\n/**\n * The configuration of a web application to be embedded in a React Native application.\n */\nexport interface Portal {\n /** The name of the Portal to be referenced. Must be **unique** */\n name: string;\n /** The classpath of all Capacitor plugins used in Android. (e.g. com.capacitorjs.plugins.camera.CameraPlugin) */\n androidPlugins?: string[];\n /**\n * The root directory of the web application relative to Bundle.main on iOS\n * and src/main/assets on Android. If omitted, `name` is used.\n */\n startDir?: string;\n /** The name of the initial file to load. If omitted, 'index.html' is used. */\n index?: string;\n /** Any data needed at initial render when a portal is loaded. */\n initialContext?: {\n [key: string]: any;\n };\n liveUpdate?: LiveUpdateConfig;\n}\n\n/**\n * A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override\n * any initialContext defined in the original {@link Portal} definition.\n */\nexport type PortalProp = {\n portal: Pick<Portal, 'name' | 'initialContext'>;\n};\n\n/**\n * Props needed for rendering a {@link Portal}\n */\nexport type PortalProps = PortalProp & ViewProps;\n\n/**\n * Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.\n *\n * @param portal The portal to add to the internal registry.\n * @returns Promise containing the Portal that was added to the registry.\n */\nexport const addPortal = async (portal: Portal): Promise<Portal> => {\n return IONPortalsReactNative.addPortal(portal);\n};\n\n/**\n * Adds all portals to an internal registry. This or {@link addPortal} must be called before attempting to render a {@link PortalView}\n *\n * @param portals The portals to add to the internal registry.\n * @returns Promise containing the Portals that were added to the registry.\n */\nexport const addPortals = async (portals: Portal[]): Promise<Portal[]> => {\n return IONPortalsReactNative.addPortals(portals);\n};\n\n/**\n * Gets a {@link Portal} previously registered via {@link addPortal} or {@link addPortals}.\n *\n * @param name The portal name to retrieve from the internal registry.\n * @returns Promise containing the registered {@link Portal}. If the {@link Portal} was not registered, the Promise will fail.\n */\nexport const getPortal = async (name: string): Promise<Portal> => {\n return IONPortalsReactNative.getPortal(name);\n};\n\nexport interface LiveUpdate {\n /** The AppFlow application ID */\n appId: string;\n /** The AppFlow distribution channel */\n channel: string;\n}\n\n/** Data needed to register a live update to be managed */\nexport type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };\n\nexport interface LiveUpdateError {\n /** The AppFlow application ID relating to the failure */\n appId: string;\n /** The step in the sync process the LiveUpdate failed on. (e.g. CHECK, UNPACK)*/\n failStep: string;\n /** A human readable error message */\n message: string;\n}\n\n/** Used for communicating sync results of multiple live updates */\nexport interface SyncResults {\n liveUpdates: LiveUpdate[];\n errors: LiveUpdateError[];\n}\n\n/**\n * Configures LiveUpdates to cyrptographically verify the contents of the downloaded bundles.\n * This method must be called before any LiveUpdates are registered otherwise they will no longer be tracked.\n *\n * @param pathToKey The *relative* path to the public key for verification.\n * This path should be the same relatibe to the main application bundle on iOS and the assets directory on Android.\n * @returns Promise<void>\n */\nexport const enableSecureLiveUpdates = async (\n pathToKey: string\n): Promise<void> => {\n return IONPortalsReactNative.enableSecureLiveUpdates(pathToKey);\n};\n\n/**\n * Syncs a single live update.\n *\n * @param appId The AppFlow application ID to sync.\n * @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.\n */\nexport const syncOne = async (appId: string): Promise<LiveUpdate> => {\n return IONPortalsReactNative.syncOne(appId);\n};\n\n/**\n * Syncs many live updates.\n *\n * @param appIds The AppFlow application IDs to sync.\n * @returns Promise<SyncResults>\n */\nexport const syncSome = async (appIds: string[]): Promise<SyncResults> => {\n return IONPortalsReactNative.syncSome(appIds);\n};\n\n/**\n * Syncs all registered LiveUpdates\n * @returns Promise<SyncResults>\n */\nexport const syncAll = async (): Promise<SyncResults> => {\n return IONPortalsReactNative.syncAll();\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"names":["NativeEventEmitter","NativeModules","Platform","IONPortalPubSub","IONPortalsReactNative","IONPortalsWebVitals","default","PortalView","PortalsPubSub","subscriptionMap","Map","subscribe","topic","onMessageReceived","subscriptionRef","subscriber","addListener","message","set","webVitalsMap","WebVitals","onFirstContentfulPaint","portalName","callback","listener","event","duration","registerOnFirstContentfulPaint","onFirstInputDelay","OS","registerOnFirstInputDelay","onTimeToFirstByte","registerOnTimeToFirstByte","registerWebVitals","firstContentfulPaint","firstInputDelay","timeToFirstByte","unsubscribe","subRef","subscription","get","undefined","remove","delete","publish","data","msg","register","key","addPortal","portal","addPortals","portals","getPortal","name","enableSecureLiveUpdates","pathToKey","syncOne","appId","syncSome","appIds","syncAll"],"sources":["index.ts"],"sourcesContent":["import {\n EmitterSubscription,\n NativeEventEmitter,\n NativeModules,\n Platform,\n ViewProps,\n} from 'react-native';\n\nconst { IONPortalPubSub, IONPortalsReactNative, IONPortalsWebVitals } =\n NativeModules;\n\nexport { default as PortalView } from './PortalView';\n\n/**\n * The data that is received from a subscription event.\n */\nexport interface Message {\n /** The unique subscription reference received from {@link subscribe}*/\n subscriptionRef: number;\n data: any;\n /** The topic the message was sent from */\n topic: string;\n}\n\nconst PortalsPubSub = new NativeEventEmitter(IONPortalPubSub);\n\nconst subscriptionMap = new Map<number, EmitterSubscription>();\n\n/**\n * Subscribes to messages for a topic\n *\n * @param topic The topic to subscribe to\n * @param onMessageReceived The callback to invoke when a message is received\n * @returns A Promise<number> containing the unique subscription reference. This will need to be stored for calling {@link unsubscribe}.\n */\nexport const subscribe = async (\n topic: string,\n onMessageReceived: (message: Message) => void\n): Promise<number> => {\n const subscriptionRef = await IONPortalPubSub.subscribe(topic);\n\n const subscriber = PortalsPubSub.addListener(\n 'PortalsSubscription',\n (message: Message) => {\n if (message.subscriptionRef === subscriptionRef) {\n onMessageReceived(message);\n }\n }\n );\n\n subscriptionMap.set(subscriptionRef, subscriber);\n\n return subscriptionRef;\n};\n\nconst webVitalsMap = new Map<string, EmitterSubscription>();\nconst WebVitals = new NativeEventEmitter(IONPortalsWebVitals);\n\ninterface WebVitalsEvent {\n portalName: string;\n duration: number;\n}\n\nexport const onFirstContentfulPaint = async (\n portalName: string,\n callback: (duration: number) => void\n): Promise<void> => {\n const listener = WebVitals.addListener(\n 'vitals:fcp',\n (event: WebVitalsEvent) => {\n if (event.portalName === portalName) {\n callback(event.duration);\n }\n }\n );\n\n await IONPortalsWebVitals.registerOnFirstContentfulPaint(portalName);\n\n webVitalsMap.set(`${portalName}-vitals:fcp`, listener);\n};\n\nexport const onFirstInputDelay = async (\n portalName: string,\n callback: (duration: number) => void\n) => {\n if (Platform.OS === 'android') {\n const listener = WebVitals.addListener(\n 'vitals:fid',\n (event: WebVitalsEvent) => {\n if (event.portalName === portalName) {\n callback(event.duration);\n }\n }\n );\n\n await IONPortalsWebVitals.registerOnFirstInputDelay(portalName);\n\n webVitalsMap.set(`${portalName}-vitals:fcp`, listener);\n }\n};\n\nexport const onTimeToFirstByte = async (\n portalName: string,\n callback: (duration: number) => void\n) => {\n if (Platform.OS === 'android') {\n const listener = WebVitals.addListener(\n 'vitals:ttfb',\n (event: WebVitalsEvent) => {\n if (event.portalName === portalName) {\n callback(event.duration);\n }\n }\n );\n\n await IONPortalsWebVitals.registerOnTimeToFirstByte(portalName);\n\n webVitalsMap.set(`${portalName}-vitals:ttfb`, listener);\n }\n};\n\nexport const registerWebVitals = async (\n portalName: string,\n firstContentfulPaint: (duration: number) => void,\n firstInputDelay: (duration: number) => void,\n timeToFirstByte: (duration: number) => void\n) => {\n onFirstContentfulPaint(portalName, firstContentfulPaint);\n onFirstInputDelay(portalName, firstInputDelay);\n onTimeToFirstByte(portalName, timeToFirstByte);\n};\n\n/**\n * Unsubscribes from events for the provided topic and subscription reference\n *\n * @param topic The topic to unsubscribe from\n * @param subRef The unique subscription reference received when initially calling {@link subscribe}\n */\nexport const unsubscribe = (topic: string, subRef: number) => {\n IONPortalPubSub.unsubscribe(topic, subRef);\n\n const subscription = subscriptionMap.get(subRef);\n if (subscription !== undefined) {\n subscription.remove();\n subscriptionMap.delete(subRef);\n }\n};\n\n/**\n * Publishes a message to the provided topic\n *\n * @param topic The topic to publish the message to\n * @param data The data to publish to subscribers\n */\nexport const publish = (topic: string, data: any) => {\n const msg = { message: data };\n IONPortalPubSub.publish(topic, msg);\n};\n\n/**\n * Validates that a valid registration key has been procured from http://ionic.io/register-portals\n * @param key The registration key\n * @returns Promise<void>\n */\nexport const register = async (key: string): Promise<void> => {\n return IONPortalsReactNative.register(key);\n};\n\n/**\n * The configuration of a web application to be embedded in a React Native application.\n */\nexport interface Portal {\n /** The name of the Portal to be referenced. Must be **unique** */\n name: string;\n /** Any Capacitor plugins to be made available to the Portal */\n plugins?: CapacitorPlugin[];\n /**\n * The root directory of the web application relative to Bundle.main on iOS\n * and src/main/assets on Android. If omitted, `name` is used.\n */\n startDir?: string;\n /** The name of the initial file to load. If omitted, 'index.html' is used. */\n index?: string;\n /** Any data needed at initial render when a portal is loaded. */\n initialContext?: {\n [key: string]: any;\n };\n assetMaps?: AssetMap[];\n liveUpdate?: LiveUpdateConfig;\n}\n\nexport interface CapacitorPlugin {\n /** The classpath of the plugin to be used in Android. (e.g. com.capacitorjs.plugins.camera.CameraPlugin) */\n androidClassPath: string;\n /** The class name of the plugin to be used in iOS.\n * This must be the name as it is exposed to the Objective-C runtime.\n * For example, The CameraPlugin swift class is exposed to Objective-C as CAPCameraPlugin.\n */\n iosClassName: string;\n}\n\nexport interface AssetMap {\n /** The name to index the asset map by */\n name: string;\n /** Any path to match via the web. If omitted, {@link AssetMap#name} will be used. */\n virtualPath?: string;\n /** The root directory of the assets relative to Bundle.main on iOS\n * and src/main/assets on Android. If omitted, the root of Bundle.main\n * and src/main/assets will be used.\n */\n startDir?: string;\n}\n\n/**\n * A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override\n * any initialContext defined in the original {@link Portal} definition.\n */\nexport type PortalProp = {\n portal: Pick<Portal, 'name' | 'initialContext'>;\n};\n\n/**\n * Props needed for rendering a {@link Portal}\n */\nexport type PortalProps = PortalProp & ViewProps;\n\n/**\n * Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.\n *\n * @param portal The portal to add to the internal registry.\n * @returns Promise containing the Portal that was added to the registry.\n */\nexport const addPortal = async (portal: Portal): Promise<Portal> => {\n return IONPortalsReactNative.addPortal(portal);\n};\n\n/**\n * Adds all portals to an internal registry. This or {@link addPortal} must be called before attempting to render a {@link PortalView}\n *\n * @param portals The portals to add to the internal registry.\n * @returns Promise containing the Portals that were added to the registry.\n */\nexport const addPortals = async (portals: Portal[]): Promise<Portal[]> => {\n return IONPortalsReactNative.addPortals(portals);\n};\n\n/**\n * Gets a {@link Portal} previously registered via {@link addPortal} or {@link addPortals}.\n *\n * @param name The portal name to retrieve from the internal registry.\n * @returns Promise containing the registered {@link Portal}. If the {@link Portal} was not registered, the Promise will fail.\n */\nexport const getPortal = async (name: string): Promise<Portal> => {\n return IONPortalsReactNative.getPortal(name);\n};\n\nexport interface LiveUpdate {\n /** The AppFlow application ID */\n appId: string;\n /** The AppFlow distribution channel */\n channel: string;\n}\n\n/** Data needed to register a live update to be managed */\nexport type LiveUpdateConfig = LiveUpdate & { syncOnAdd: boolean };\n\nexport interface LiveUpdateError {\n /** The AppFlow application ID relating to the failure */\n appId: string;\n /** The step in the sync process the LiveUpdate failed on. (e.g. CHECK, UNPACK)*/\n failStep: string;\n /** A human readable error message */\n message: string;\n}\n\nexport interface Snapshot {\n /** The snapshot id as found in AppFlow */\n id: string;\n /** The AppFlow build id that produced the snapshot */\n buildId: string;\n}\n\nexport interface SyncResult {\n /** The {@link LiveUpdate} associated with the result */\n liveUpdate: LiveUpdate;\n /** The {@link Snapshot} that was sync'd */\n snapshot: Snapshot | null;\n /** Whether the snapshot was downloaded or already on disk */\n source: 'download' | 'cache';\n /** If the active application path was changed. A `false` value would indicate\n * the application already has the latest code for the associated {@link LiveUpdate}\n * configuration.\n */\n activeApplicationPathChanged: boolean;\n}\n\n/** Used for communicating sync results of multiple live updates */\nexport interface SyncResults {\n results: SyncResult[];\n errors: LiveUpdateError[];\n}\n\n/**\n * Configures LiveUpdates to cyrptographically verify the contents of the downloaded bundles.\n * This method must be called before any LiveUpdates are registered otherwise they will no longer be tracked.\n *\n * @param pathToKey The *relative* path to the public key for verification.\n * This path should be the same relatibe to the main application bundle on iOS and the assets directory on Android.\n * @returns Promise<void>\n */\nexport const enableSecureLiveUpdates = async (\n pathToKey: string\n): Promise<void> => {\n return IONPortalsReactNative.enableSecureLiveUpdates(pathToKey);\n};\n\n/**\n * Syncs a single live update.\n *\n * @param appId The AppFlow application ID to sync.\n * @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.\n */\nexport const syncOne = async (appId: string): Promise<SyncResult> => {\n return IONPortalsReactNative.syncOne(appId);\n};\n\n/**\n * Syncs many live updates.\n *\n * @param appIds The AppFlow application IDs to sync.\n * @returns Promise<SyncResults>\n */\nexport const syncSome = async (appIds: string[]): Promise<SyncResults> => {\n return IONPortalsReactNative.syncSome(appIds);\n};\n\n/**\n * Syncs all registered LiveUpdates\n * @returns Promise<SyncResults>\n */\nexport const syncAll = async (): Promise<SyncResults> => {\n return IONPortalsReactNative.syncAll();\n};\n"],"mappings":"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"}
|
|
@@ -18,6 +18,10 @@ export interface Message {
|
|
|
18
18
|
* @returns A Promise<number> containing the unique subscription reference. This will need to be stored for calling {@link unsubscribe}.
|
|
19
19
|
*/
|
|
20
20
|
export declare const subscribe: (topic: string, onMessageReceived: (message: Message) => void) => Promise<number>;
|
|
21
|
+
export declare const onFirstContentfulPaint: (portalName: string, callback: (duration: number) => void) => Promise<void>;
|
|
22
|
+
export declare const onFirstInputDelay: (portalName: string, callback: (duration: number) => void) => Promise<void>;
|
|
23
|
+
export declare const onTimeToFirstByte: (portalName: string, callback: (duration: number) => void) => Promise<void>;
|
|
24
|
+
export declare const registerWebVitals: (portalName: string, firstContentfulPaint: (duration: number) => void, firstInputDelay: (duration: number) => void, timeToFirstByte: (duration: number) => void) => Promise<void>;
|
|
21
25
|
/**
|
|
22
26
|
* Unsubscribes from events for the provided topic and subscription reference
|
|
23
27
|
*
|
|
@@ -44,8 +48,8 @@ export declare const register: (key: string) => Promise<void>;
|
|
|
44
48
|
export interface Portal {
|
|
45
49
|
/** The name of the Portal to be referenced. Must be **unique** */
|
|
46
50
|
name: string;
|
|
47
|
-
/**
|
|
48
|
-
|
|
51
|
+
/** Any Capacitor plugins to be made available to the Portal */
|
|
52
|
+
plugins?: CapacitorPlugin[];
|
|
49
53
|
/**
|
|
50
54
|
* The root directory of the web application relative to Bundle.main on iOS
|
|
51
55
|
* and src/main/assets on Android. If omitted, `name` is used.
|
|
@@ -57,19 +61,40 @@ export interface Portal {
|
|
|
57
61
|
initialContext?: {
|
|
58
62
|
[key: string]: any;
|
|
59
63
|
};
|
|
64
|
+
assetMaps?: AssetMap[];
|
|
60
65
|
liveUpdate?: LiveUpdateConfig;
|
|
61
66
|
}
|
|
67
|
+
export interface CapacitorPlugin {
|
|
68
|
+
/** The classpath of the plugin to be used in Android. (e.g. com.capacitorjs.plugins.camera.CameraPlugin) */
|
|
69
|
+
androidClassPath: string;
|
|
70
|
+
/** The class name of the plugin to be used in iOS.
|
|
71
|
+
* This must be the name as it is exposed to the Objective-C runtime.
|
|
72
|
+
* For example, The CameraPlugin swift class is exposed to Objective-C as CAPCameraPlugin.
|
|
73
|
+
*/
|
|
74
|
+
iosClassName: string;
|
|
75
|
+
}
|
|
76
|
+
export interface AssetMap {
|
|
77
|
+
/** The name to index the asset map by */
|
|
78
|
+
name: string;
|
|
79
|
+
/** Any path to match via the web. If omitted, {@link AssetMap#name} will be used. */
|
|
80
|
+
virtualPath?: string;
|
|
81
|
+
/** The root directory of the assets relative to Bundle.main on iOS
|
|
82
|
+
* and src/main/assets on Android. If omitted, the root of Bundle.main
|
|
83
|
+
* and src/main/assets will be used.
|
|
84
|
+
*/
|
|
85
|
+
startDir?: string;
|
|
86
|
+
}
|
|
62
87
|
/**
|
|
63
88
|
* A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override
|
|
64
89
|
* any initialContext defined in the original {@link Portal} definition.
|
|
65
90
|
*/
|
|
66
|
-
export
|
|
91
|
+
export type PortalProp = {
|
|
67
92
|
portal: Pick<Portal, 'name' | 'initialContext'>;
|
|
68
93
|
};
|
|
69
94
|
/**
|
|
70
95
|
* Props needed for rendering a {@link Portal}
|
|
71
96
|
*/
|
|
72
|
-
export
|
|
97
|
+
export type PortalProps = PortalProp & ViewProps;
|
|
73
98
|
/**
|
|
74
99
|
* Adds a Portal to an internal registry. Must be called before attempting to render a {@link PortalView}.
|
|
75
100
|
*
|
|
@@ -98,7 +123,7 @@ export interface LiveUpdate {
|
|
|
98
123
|
channel: string;
|
|
99
124
|
}
|
|
100
125
|
/** Data needed to register a live update to be managed */
|
|
101
|
-
export
|
|
126
|
+
export type LiveUpdateConfig = LiveUpdate & {
|
|
102
127
|
syncOnAdd: boolean;
|
|
103
128
|
};
|
|
104
129
|
export interface LiveUpdateError {
|
|
@@ -109,9 +134,28 @@ export interface LiveUpdateError {
|
|
|
109
134
|
/** A human readable error message */
|
|
110
135
|
message: string;
|
|
111
136
|
}
|
|
137
|
+
export interface Snapshot {
|
|
138
|
+
/** The snapshot id as found in AppFlow */
|
|
139
|
+
id: string;
|
|
140
|
+
/** The AppFlow build id that produced the snapshot */
|
|
141
|
+
buildId: string;
|
|
142
|
+
}
|
|
143
|
+
export interface SyncResult {
|
|
144
|
+
/** The {@link LiveUpdate} associated with the result */
|
|
145
|
+
liveUpdate: LiveUpdate;
|
|
146
|
+
/** The {@link Snapshot} that was sync'd */
|
|
147
|
+
snapshot: Snapshot | null;
|
|
148
|
+
/** Whether the snapshot was downloaded or already on disk */
|
|
149
|
+
source: 'download' | 'cache';
|
|
150
|
+
/** If the active application path was changed. A `false` value would indicate
|
|
151
|
+
* the application already has the latest code for the associated {@link LiveUpdate}
|
|
152
|
+
* configuration.
|
|
153
|
+
*/
|
|
154
|
+
activeApplicationPathChanged: boolean;
|
|
155
|
+
}
|
|
112
156
|
/** Used for communicating sync results of multiple live updates */
|
|
113
157
|
export interface SyncResults {
|
|
114
|
-
|
|
158
|
+
results: SyncResult[];
|
|
115
159
|
errors: LiveUpdateError[];
|
|
116
160
|
}
|
|
117
161
|
/**
|
|
@@ -129,7 +173,7 @@ export declare const enableSecureLiveUpdates: (pathToKey: string) => Promise<voi
|
|
|
129
173
|
* @param appId The AppFlow application ID to sync.
|
|
130
174
|
* @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.
|
|
131
175
|
*/
|
|
132
|
-
export declare const syncOne: (appId: string) => Promise<
|
|
176
|
+
export declare const syncOne: (appId: string) => Promise<SyncResult>;
|
|
133
177
|
/**
|
|
134
178
|
* Syncs many live updates.
|
|
135
179
|
*
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -2,10 +2,12 @@ import {
|
|
|
2
2
|
EmitterSubscription,
|
|
3
3
|
NativeEventEmitter,
|
|
4
4
|
NativeModules,
|
|
5
|
+
Platform,
|
|
5
6
|
ViewProps,
|
|
6
7
|
} from 'react-native';
|
|
7
8
|
|
|
8
|
-
const { IONPortalPubSub, IONPortalsReactNative } =
|
|
9
|
+
const { IONPortalPubSub, IONPortalsReactNative, IONPortalsWebVitals } =
|
|
10
|
+
NativeModules;
|
|
9
11
|
|
|
10
12
|
export { default as PortalView } from './PortalView';
|
|
11
13
|
|
|
@@ -51,6 +53,83 @@ export const subscribe = async (
|
|
|
51
53
|
return subscriptionRef;
|
|
52
54
|
};
|
|
53
55
|
|
|
56
|
+
const webVitalsMap = new Map<string, EmitterSubscription>();
|
|
57
|
+
const WebVitals = new NativeEventEmitter(IONPortalsWebVitals);
|
|
58
|
+
|
|
59
|
+
interface WebVitalsEvent {
|
|
60
|
+
portalName: string;
|
|
61
|
+
duration: number;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const onFirstContentfulPaint = async (
|
|
65
|
+
portalName: string,
|
|
66
|
+
callback: (duration: number) => void
|
|
67
|
+
): Promise<void> => {
|
|
68
|
+
const listener = WebVitals.addListener(
|
|
69
|
+
'vitals:fcp',
|
|
70
|
+
(event: WebVitalsEvent) => {
|
|
71
|
+
if (event.portalName === portalName) {
|
|
72
|
+
callback(event.duration);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
await IONPortalsWebVitals.registerOnFirstContentfulPaint(portalName);
|
|
78
|
+
|
|
79
|
+
webVitalsMap.set(`${portalName}-vitals:fcp`, listener);
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
export const onFirstInputDelay = async (
|
|
83
|
+
portalName: string,
|
|
84
|
+
callback: (duration: number) => void
|
|
85
|
+
) => {
|
|
86
|
+
if (Platform.OS === 'android') {
|
|
87
|
+
const listener = WebVitals.addListener(
|
|
88
|
+
'vitals:fid',
|
|
89
|
+
(event: WebVitalsEvent) => {
|
|
90
|
+
if (event.portalName === portalName) {
|
|
91
|
+
callback(event.duration);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
await IONPortalsWebVitals.registerOnFirstInputDelay(portalName);
|
|
97
|
+
|
|
98
|
+
webVitalsMap.set(`${portalName}-vitals:fcp`, listener);
|
|
99
|
+
}
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
export const onTimeToFirstByte = async (
|
|
103
|
+
portalName: string,
|
|
104
|
+
callback: (duration: number) => void
|
|
105
|
+
) => {
|
|
106
|
+
if (Platform.OS === 'android') {
|
|
107
|
+
const listener = WebVitals.addListener(
|
|
108
|
+
'vitals:ttfb',
|
|
109
|
+
(event: WebVitalsEvent) => {
|
|
110
|
+
if (event.portalName === portalName) {
|
|
111
|
+
callback(event.duration);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
await IONPortalsWebVitals.registerOnTimeToFirstByte(portalName);
|
|
117
|
+
|
|
118
|
+
webVitalsMap.set(`${portalName}-vitals:ttfb`, listener);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
export const registerWebVitals = async (
|
|
123
|
+
portalName: string,
|
|
124
|
+
firstContentfulPaint: (duration: number) => void,
|
|
125
|
+
firstInputDelay: (duration: number) => void,
|
|
126
|
+
timeToFirstByte: (duration: number) => void
|
|
127
|
+
) => {
|
|
128
|
+
onFirstContentfulPaint(portalName, firstContentfulPaint);
|
|
129
|
+
onFirstInputDelay(portalName, firstInputDelay);
|
|
130
|
+
onTimeToFirstByte(portalName, timeToFirstByte);
|
|
131
|
+
};
|
|
132
|
+
|
|
54
133
|
/**
|
|
55
134
|
* Unsubscribes from events for the provided topic and subscription reference
|
|
56
135
|
*
|
|
@@ -93,8 +172,8 @@ export const register = async (key: string): Promise<void> => {
|
|
|
93
172
|
export interface Portal {
|
|
94
173
|
/** The name of the Portal to be referenced. Must be **unique** */
|
|
95
174
|
name: string;
|
|
96
|
-
/**
|
|
97
|
-
|
|
175
|
+
/** Any Capacitor plugins to be made available to the Portal */
|
|
176
|
+
plugins?: CapacitorPlugin[];
|
|
98
177
|
/**
|
|
99
178
|
* The root directory of the web application relative to Bundle.main on iOS
|
|
100
179
|
* and src/main/assets on Android. If omitted, `name` is used.
|
|
@@ -106,9 +185,32 @@ export interface Portal {
|
|
|
106
185
|
initialContext?: {
|
|
107
186
|
[key: string]: any;
|
|
108
187
|
};
|
|
188
|
+
assetMaps?: AssetMap[];
|
|
109
189
|
liveUpdate?: LiveUpdateConfig;
|
|
110
190
|
}
|
|
111
191
|
|
|
192
|
+
export interface CapacitorPlugin {
|
|
193
|
+
/** The classpath of the plugin to be used in Android. (e.g. com.capacitorjs.plugins.camera.CameraPlugin) */
|
|
194
|
+
androidClassPath: string;
|
|
195
|
+
/** The class name of the plugin to be used in iOS.
|
|
196
|
+
* This must be the name as it is exposed to the Objective-C runtime.
|
|
197
|
+
* For example, The CameraPlugin swift class is exposed to Objective-C as CAPCameraPlugin.
|
|
198
|
+
*/
|
|
199
|
+
iosClassName: string;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export interface AssetMap {
|
|
203
|
+
/** The name to index the asset map by */
|
|
204
|
+
name: string;
|
|
205
|
+
/** Any path to match via the web. If omitted, {@link AssetMap#name} will be used. */
|
|
206
|
+
virtualPath?: string;
|
|
207
|
+
/** The root directory of the assets relative to Bundle.main on iOS
|
|
208
|
+
* and src/main/assets on Android. If omitted, the root of Bundle.main
|
|
209
|
+
* and src/main/assets will be used.
|
|
210
|
+
*/
|
|
211
|
+
startDir?: string;
|
|
212
|
+
}
|
|
213
|
+
|
|
112
214
|
/**
|
|
113
215
|
* A subset of {@link Portal} properties needed for rendering a Portal. `initialContext` can be used to override
|
|
114
216
|
* any initialContext defined in the original {@link Portal} definition.
|
|
@@ -171,9 +273,30 @@ export interface LiveUpdateError {
|
|
|
171
273
|
message: string;
|
|
172
274
|
}
|
|
173
275
|
|
|
276
|
+
export interface Snapshot {
|
|
277
|
+
/** The snapshot id as found in AppFlow */
|
|
278
|
+
id: string;
|
|
279
|
+
/** The AppFlow build id that produced the snapshot */
|
|
280
|
+
buildId: string;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
export interface SyncResult {
|
|
284
|
+
/** The {@link LiveUpdate} associated with the result */
|
|
285
|
+
liveUpdate: LiveUpdate;
|
|
286
|
+
/** The {@link Snapshot} that was sync'd */
|
|
287
|
+
snapshot: Snapshot | null;
|
|
288
|
+
/** Whether the snapshot was downloaded or already on disk */
|
|
289
|
+
source: 'download' | 'cache';
|
|
290
|
+
/** If the active application path was changed. A `false` value would indicate
|
|
291
|
+
* the application already has the latest code for the associated {@link LiveUpdate}
|
|
292
|
+
* configuration.
|
|
293
|
+
*/
|
|
294
|
+
activeApplicationPathChanged: boolean;
|
|
295
|
+
}
|
|
296
|
+
|
|
174
297
|
/** Used for communicating sync results of multiple live updates */
|
|
175
298
|
export interface SyncResults {
|
|
176
|
-
|
|
299
|
+
results: SyncResult[];
|
|
177
300
|
errors: LiveUpdateError[];
|
|
178
301
|
}
|
|
179
302
|
|
|
@@ -197,7 +320,7 @@ export const enableSecureLiveUpdates = async (
|
|
|
197
320
|
* @param appId The AppFlow application ID to sync.
|
|
198
321
|
* @returns A Promise<LiveUpdate>. A failure should result in a {@link LiveUpdateError}.
|
|
199
322
|
*/
|
|
200
|
-
export const syncOne = async (appId: string): Promise<
|
|
323
|
+
export const syncOne = async (appId: string): Promise<SyncResult> => {
|
|
201
324
|
return IONPortalsReactNative.syncOne(appId);
|
|
202
325
|
};
|
|
203
326
|
|
package/ios/Portal+Dict.swift
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
//
|
|
2
|
-
// Portal+Dict.swift
|
|
3
|
-
// ReactNativePortals
|
|
4
|
-
//
|
|
5
|
-
// Created by Steven Sherry on 10/5/22.
|
|
6
|
-
// Copyright © 2022 Ionic. All rights reserved.
|
|
7
|
-
//
|
|
8
|
-
|
|
9
|
-
import Capacitor
|
|
10
|
-
import IonicLiveUpdates
|
|
11
|
-
import IonicPortals
|
|
12
|
-
|
|
13
|
-
extension Portal {
|
|
14
|
-
init?(_ dict: [String: Any], _ liveUpdateManager: LiveUpdateManager) {
|
|
15
|
-
guard let name = dict["name"] as? String else { return nil }
|
|
16
|
-
self.init(
|
|
17
|
-
name: name,
|
|
18
|
-
startDir: dict["startDir"] as? String,
|
|
19
|
-
index: dict["index"] as? String ?? "index.html",
|
|
20
|
-
initialContext: JSTypes.coerceDictionaryToJSObject(dict["initialContext"] as? [String: Any]) ?? [:],
|
|
21
|
-
liveUpdateManager: liveUpdateManager,
|
|
22
|
-
liveUpdateConfig: (dict["liveUpdate"] as? [String: Any]).flatMap(LiveUpdate.init)
|
|
23
|
-
)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
var dict: [String: Any] {
|
|
27
|
-
return [
|
|
28
|
-
"name": name,
|
|
29
|
-
"startDir": startDir,
|
|
30
|
-
"index": index,
|
|
31
|
-
"initialContext": initialContext,
|
|
32
|
-
"liveUpdateConfig": liveUpdateConfig?.dict as Any
|
|
33
|
-
]
|
|
34
|
-
}
|
|
35
|
-
}
|