@capgo/capacitor-stream-call 0.0.2
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/Package.swift +31 -0
- package/README.md +340 -0
- package/StreamCall.podspec +19 -0
- package/android/build.gradle +74 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/CallOverlayView.kt +281 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/CustomNotificationHandler.kt +142 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/IncomingCallView.kt +147 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/RingtonePlayer.kt +164 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/StreamCallPlugin.kt +1014 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/TouchInterceptWrapper.kt +31 -0
- package/android/src/main/java/ee/forgr/capacitor/streamcall/UserRepository.kt +111 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/android/src/main/res/values/strings.xml +7 -0
- package/dist/docs.json +533 -0
- package/dist/esm/definitions.d.ts +169 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +32 -0
- package/dist/esm/web.js +323 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +337 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +339 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Sources/StreamCallPlugin/CallOverlayView.swift +147 -0
- package/ios/Sources/StreamCallPlugin/CustomCallParticipantImageView.swift +60 -0
- package/ios/Sources/StreamCallPlugin/CustomCallView.swift +257 -0
- package/ios/Sources/StreamCallPlugin/CustomVideoParticipantsView.swift +107 -0
- package/ios/Sources/StreamCallPlugin/ParticipantsView.swift +206 -0
- package/ios/Sources/StreamCallPlugin/StreamCallPlugin.swift +722 -0
- package/ios/Sources/StreamCallPlugin/TouchInterceptView.swift +177 -0
- package/ios/Sources/StreamCallPlugin/UserRepository.swift +96 -0
- package/ios/Sources/StreamCallPlugin/WebviewNavigationDelegate.swift +68 -0
- package/ios/Tests/StreamCallPluginTests/StreamCallPluginTests.swift +15 -0
- package/package.json +96 -0
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
import UIKit
|
|
2
|
+
|
|
3
|
+
class TouchInterceptView: UIView {
|
|
4
|
+
private var webView: UIView?
|
|
5
|
+
private var overlayView: UIView?
|
|
6
|
+
private var labeledFrames: [ViewFramePreferenceData] = []
|
|
7
|
+
|
|
8
|
+
override init(frame: CGRect) {
|
|
9
|
+
super.init(frame: frame)
|
|
10
|
+
isUserInteractionEnabled = true
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
required init?(coder: NSCoder) {
|
|
14
|
+
super.init(coder: coder)
|
|
15
|
+
isUserInteractionEnabled = true
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
func setupWithWebView(_ webView: UIView, overlayView: UIView) {
|
|
19
|
+
self.webView = webView
|
|
20
|
+
self.overlayView = overlayView
|
|
21
|
+
|
|
22
|
+
// Add both views as subviews
|
|
23
|
+
addSubview(overlayView)
|
|
24
|
+
addSubview(webView)
|
|
25
|
+
|
|
26
|
+
// Ensure both views can receive touches
|
|
27
|
+
webView.isUserInteractionEnabled = true
|
|
28
|
+
overlayView.isUserInteractionEnabled = true
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
32
|
+
guard let webView = webView,
|
|
33
|
+
let overlayView = overlayView else {
|
|
34
|
+
super.touchesBegan(touches, with: event)
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Convert touch locations and check labeled frames
|
|
39
|
+
if let touch = touches.first {
|
|
40
|
+
let point = touch.location(in: self)
|
|
41
|
+
let globalPoint = convert(point, to: nil)
|
|
42
|
+
|
|
43
|
+
// If touch is in a labeled frame, only send to overlay
|
|
44
|
+
if labeledFrames.contains(where: { $0.frame.contains(globalPoint) }) {
|
|
45
|
+
overlayView.touchesBegan(touches, with: event)
|
|
46
|
+
} else {
|
|
47
|
+
// Otherwise broadcast to both views
|
|
48
|
+
webView.touchesBegan(touches, with: event)
|
|
49
|
+
overlayView.touchesBegan(touches, with: event)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
super.touchesBegan(touches, with: event)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
57
|
+
guard let webView = webView,
|
|
58
|
+
let overlayView = overlayView else {
|
|
59
|
+
super.touchesMoved(touches, with: event)
|
|
60
|
+
return
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if let touch = touches.first {
|
|
64
|
+
let point = touch.location(in: self)
|
|
65
|
+
let globalPoint = convert(point, to: nil)
|
|
66
|
+
|
|
67
|
+
if labeledFrames.contains(where: { $0.frame.contains(globalPoint) }) {
|
|
68
|
+
overlayView.touchesMoved(touches, with: event)
|
|
69
|
+
} else {
|
|
70
|
+
webView.touchesMoved(touches, with: event)
|
|
71
|
+
overlayView.touchesMoved(touches, with: event)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
super.touchesMoved(touches, with: event)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
79
|
+
guard let webView = webView,
|
|
80
|
+
let overlayView = overlayView else {
|
|
81
|
+
super.touchesEnded(touches, with: event)
|
|
82
|
+
return
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if let touch = touches.first {
|
|
86
|
+
let point = touch.location(in: self)
|
|
87
|
+
let globalPoint = convert(point, to: nil)
|
|
88
|
+
|
|
89
|
+
if labeledFrames.contains(where: { $0.frame.contains(globalPoint) }) {
|
|
90
|
+
overlayView.touchesEnded(touches, with: event)
|
|
91
|
+
} else {
|
|
92
|
+
webView.touchesEnded(touches, with: event)
|
|
93
|
+
overlayView.touchesEnded(touches, with: event)
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
super.touchesEnded(touches, with: event)
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
override func touchesCancelled(_ touches: Set<UITouch>, with event: UIEvent?) {
|
|
101
|
+
guard let webView = webView,
|
|
102
|
+
let overlayView = overlayView else {
|
|
103
|
+
super.touchesCancelled(touches, with: event)
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if let touch = touches.first {
|
|
108
|
+
let point = touch.location(in: self)
|
|
109
|
+
let globalPoint = convert(point, to: nil)
|
|
110
|
+
|
|
111
|
+
if labeledFrames.contains(where: { $0.frame.contains(globalPoint) }) {
|
|
112
|
+
overlayView.touchesCancelled(touches, with: event)
|
|
113
|
+
} else {
|
|
114
|
+
webView.touchesCancelled(touches, with: event)
|
|
115
|
+
overlayView.touchesCancelled(touches, with: event)
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
super.touchesCancelled(touches, with: event)
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
override func point(inside point: CGPoint, with event: UIEvent?) -> Bool {
|
|
123
|
+
return true
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
override func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
|
|
127
|
+
guard let webView = webView,
|
|
128
|
+
let overlayView = overlayView else {
|
|
129
|
+
return super.hitTest(point, with: event)
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Convert point to global coordinates for labeled frame checking
|
|
133
|
+
let globalPoint = convert(point, to: nil)
|
|
134
|
+
|
|
135
|
+
print("TouchInterceptView - Hit test at global point: \(globalPoint)")
|
|
136
|
+
print("Current labeled frames: \(labeledFrames.map { "\($0.label): \($0.frame)" }.joined(separator: ", "))")
|
|
137
|
+
|
|
138
|
+
// Convert point for both views
|
|
139
|
+
let webViewPoint = convert(point, to: webView)
|
|
140
|
+
let overlayPoint = convert(point, to: overlayView)
|
|
141
|
+
|
|
142
|
+
// First check if the point is inside any labeled frame
|
|
143
|
+
for labeledFrame in labeledFrames {
|
|
144
|
+
if labeledFrame.frame.contains(globalPoint) {
|
|
145
|
+
print("Hit labeled frame: \(labeledFrame.label)")
|
|
146
|
+
// If it's in a labeled frame, let the overlay handle it
|
|
147
|
+
if overlayView.point(inside: overlayPoint, with: event),
|
|
148
|
+
let overlayHitView = overlayView.hitTest(overlayPoint, with: event) {
|
|
149
|
+
return overlayHitView
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// If not in a labeled frame, let webview try first
|
|
155
|
+
if webView.point(inside: webViewPoint, with: event),
|
|
156
|
+
let webViewHitView = webView.hitTest(webViewPoint, with: event) {
|
|
157
|
+
return webViewHitView
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
// Finally check if overlay wants to handle the touch
|
|
161
|
+
if overlayView.point(inside: overlayPoint, with: event),
|
|
162
|
+
let overlayHitView = overlayView.hitTest(overlayPoint, with: event) {
|
|
163
|
+
return overlayHitView
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return super.hitTest(point, with: event)
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
func updateLabeledFrames(_ frames: [ViewFramePreferenceData]) {
|
|
170
|
+
print("TouchInterceptView - Updating labeled frames:")
|
|
171
|
+
print("Number of frames: \(frames.count)")
|
|
172
|
+
frames.forEach { frame in
|
|
173
|
+
print("Label: \(frame.label), Frame: \(frame.frame)")
|
|
174
|
+
}
|
|
175
|
+
self.labeledFrames = frames
|
|
176
|
+
}
|
|
177
|
+
}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
//
|
|
2
|
+
// UserRepository.swift
|
|
3
|
+
// Pods
|
|
4
|
+
//
|
|
5
|
+
// Created by Michał Tremblay on 07/02/2025.
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Security
|
|
9
|
+
import StreamVideo
|
|
10
|
+
import Foundation
|
|
11
|
+
|
|
12
|
+
struct UserCredentials: Identifiable, Codable {
|
|
13
|
+
var id: String {
|
|
14
|
+
user.id
|
|
15
|
+
}
|
|
16
|
+
let user: User
|
|
17
|
+
let tokenValue: String
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
protocol UserRepository {
|
|
21
|
+
|
|
22
|
+
func save(user: UserCredentials)
|
|
23
|
+
|
|
24
|
+
func loadCurrentUser() -> UserCredentials?
|
|
25
|
+
|
|
26
|
+
func removeCurrentUser()
|
|
27
|
+
|
|
28
|
+
func save(token: String)
|
|
29
|
+
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
protocol VoipTokenHandler {
|
|
33
|
+
|
|
34
|
+
func save(voipPushToken: String?)
|
|
35
|
+
|
|
36
|
+
func currentVoipPushToken() -> String?
|
|
37
|
+
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// NOTE: This is just for simplicity. User data shouldn't be kept in `UserDefaults`.
|
|
41
|
+
// NOTE: This is just for simplicity. User data shouldn't be kept in `UserDefaults`.
|
|
42
|
+
class SecureUserRepository: UserRepository, VoipTokenHandler {
|
|
43
|
+
|
|
44
|
+
private let defaults = UserDefaults.standard
|
|
45
|
+
private let userKey = "stream.video.user"
|
|
46
|
+
private let tokenKey = "stream.video.token"
|
|
47
|
+
private let chatTokenKey = "stream.chat.token"
|
|
48
|
+
private let voipPushTokenKey = "stream.video.voip.token"
|
|
49
|
+
|
|
50
|
+
static let shared = SecureUserRepository()
|
|
51
|
+
|
|
52
|
+
private init() {}
|
|
53
|
+
|
|
54
|
+
func save(user: UserCredentials) {
|
|
55
|
+
let encoder = JSONEncoder()
|
|
56
|
+
if let encoded = try? encoder.encode(user.user) {
|
|
57
|
+
defaults.set(encoded, forKey: userKey)
|
|
58
|
+
defaults.set(user.tokenValue, forKey: tokenKey)
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
func save(token: String) {
|
|
63
|
+
defaults.set(token, forKey: tokenKey)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
func loadCurrentUser() -> UserCredentials? {
|
|
67
|
+
if let savedUser = defaults.object(forKey: userKey) as? Data {
|
|
68
|
+
let decoder = JSONDecoder()
|
|
69
|
+
do {
|
|
70
|
+
let loadedUser = try decoder.decode(User.self, from: savedUser)
|
|
71
|
+
guard let tokenValue = defaults.value(forKey: tokenKey) as? String else {
|
|
72
|
+
throw ClientError.Unexpected()
|
|
73
|
+
}
|
|
74
|
+
return UserCredentials(user: loadedUser, tokenValue: tokenValue)
|
|
75
|
+
} catch {
|
|
76
|
+
log.error("Error while decoding user: \(String(describing: error))")
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return nil
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
func save(voipPushToken: String?) {
|
|
83
|
+
defaults.set(voipPushToken, forKey: voipPushTokenKey)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
func currentVoipPushToken() -> String? {
|
|
87
|
+
defaults.value(forKey: voipPushTokenKey) as? String
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
func removeCurrentUser() {
|
|
91
|
+
defaults.set(nil, forKey: userKey)
|
|
92
|
+
defaults.set(nil, forKey: tokenKey)
|
|
93
|
+
defaults.set(nil, forKey: voipPushTokenKey)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import WebKit
|
|
3
|
+
|
|
4
|
+
class WebviewNavigationDelegate: NSObject, WKNavigationDelegate {
|
|
5
|
+
private let wrappedDelegate: WKNavigationDelegate?
|
|
6
|
+
private let onSetupOverlay: () -> Void
|
|
7
|
+
|
|
8
|
+
init(wrappedDelegate: WKNavigationDelegate?, onSetupOverlay: @escaping () -> Void) {
|
|
9
|
+
self.wrappedDelegate = wrappedDelegate
|
|
10
|
+
self.onSetupOverlay = onSetupOverlay
|
|
11
|
+
super.init()
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) {
|
|
15
|
+
// Then forward to the original delegate
|
|
16
|
+
wrappedDelegate?.webView?(webView, didFinish: navigation)
|
|
17
|
+
|
|
18
|
+
// Call our custom setup
|
|
19
|
+
onSetupOverlay()
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// Forward all other WKNavigationDelegate methods
|
|
23
|
+
|
|
24
|
+
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
|
|
25
|
+
if let result = wrappedDelegate?.webView?(webView, decidePolicyFor: navigationAction, decisionHandler: decisionHandler) {
|
|
26
|
+
return result
|
|
27
|
+
}
|
|
28
|
+
decisionHandler(.allow)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
func webView(_ webView: WKWebView, decidePolicyFor navigationResponse: WKNavigationResponse, decisionHandler: @escaping (WKNavigationResponsePolicy) -> Void) {
|
|
32
|
+
if let result = wrappedDelegate?.webView?(webView, decidePolicyFor: navigationResponse, decisionHandler: decisionHandler) {
|
|
33
|
+
return result
|
|
34
|
+
}
|
|
35
|
+
decisionHandler(.allow)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
func webView(_ webView: WKWebView, didStartProvisionalNavigation navigation: WKNavigation!) {
|
|
39
|
+
wrappedDelegate?.webView?(webView, didStartProvisionalNavigation: navigation)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) {
|
|
43
|
+
wrappedDelegate?.webView?(webView, didReceiveServerRedirectForProvisionalNavigation: navigation)
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
func webView(_ webView: WKWebView, didFailProvisionalNavigation navigation: WKNavigation!, withError error: Error) {
|
|
47
|
+
wrappedDelegate?.webView?(webView, didFailProvisionalNavigation: navigation, withError: error)
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
func webView(_ webView: WKWebView, didCommit navigation: WKNavigation!) {
|
|
51
|
+
wrappedDelegate?.webView?(webView, didCommit: navigation)
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
func webView(_ webView: WKWebView, didFail navigation: WKNavigation!, withError error: Error) {
|
|
55
|
+
wrappedDelegate?.webView?(webView, didFail: navigation, withError: error)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
func webView(_ webView: WKWebView, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
|
|
59
|
+
if let result = wrappedDelegate?.webView?(webView, didReceive: challenge, completionHandler: completionHandler) {
|
|
60
|
+
return result
|
|
61
|
+
}
|
|
62
|
+
completionHandler(.performDefaultHandling, nil)
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
func webViewWebContentProcessDidTerminate(_ webView: WKWebView) {
|
|
66
|
+
wrappedDelegate?.webViewWebContentProcessDidTerminate?(webView)
|
|
67
|
+
}
|
|
68
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import XCTest
|
|
2
|
+
@testable import StreamCallPlugin
|
|
3
|
+
|
|
4
|
+
class StreamCallTests: XCTestCase {
|
|
5
|
+
func testEcho() {
|
|
6
|
+
// This is an example of a functional test case for a plugin.
|
|
7
|
+
// Use XCTAssert and related functions to verify your tests produce the correct results.
|
|
8
|
+
|
|
9
|
+
let implementation = StreamCall()
|
|
10
|
+
let value = "Hello, World!"
|
|
11
|
+
let result = implementation.echo(value)
|
|
12
|
+
|
|
13
|
+
XCTAssertEqual(value, result)
|
|
14
|
+
}
|
|
15
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capgo/capacitor-stream-call",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Uses the https://getstream.io/ SDK to implement calling in Capacitor",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Sources",
|
|
14
|
+
"ios/Tests",
|
|
15
|
+
"Package.swift",
|
|
16
|
+
"StreamCall.podspec"
|
|
17
|
+
],
|
|
18
|
+
"author": "Martin Donadieu <martin@capgo.app>",
|
|
19
|
+
"license": "MIT",
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/Cap-go/StreamCall.git"
|
|
23
|
+
},
|
|
24
|
+
"bugs": {
|
|
25
|
+
"url": "https://github.com/Cap-go/StreamCall/issues"
|
|
26
|
+
},
|
|
27
|
+
"keywords": [
|
|
28
|
+
"capacitor",
|
|
29
|
+
"plugin",
|
|
30
|
+
"stream",
|
|
31
|
+
"call",
|
|
32
|
+
"video",
|
|
33
|
+
"audio",
|
|
34
|
+
"getstream",
|
|
35
|
+
"stream-video",
|
|
36
|
+
"stream-call",
|
|
37
|
+
"group-call",
|
|
38
|
+
"native",
|
|
39
|
+
"ios",
|
|
40
|
+
"android",
|
|
41
|
+
"web",
|
|
42
|
+
"capacitor-plugin"
|
|
43
|
+
],
|
|
44
|
+
"scripts": {
|
|
45
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
46
|
+
"verify:ios": "xcodebuild -scheme StreamCall -destination generic/platform=iOS",
|
|
47
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
48
|
+
"verify:web": "npm run build",
|
|
49
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
50
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
51
|
+
"eslint": "eslint . --ext ts",
|
|
52
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
53
|
+
"swiftlint": "node-swiftlint",
|
|
54
|
+
"docgen": "docgen --api StreamCallPlugin --output-readme README.md --output-json dist/docs.json",
|
|
55
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
56
|
+
"clean": "rimraf ./dist",
|
|
57
|
+
"watch": "tsc --watch",
|
|
58
|
+
"prepublishOnly": "npm run build"
|
|
59
|
+
},
|
|
60
|
+
"devDependencies": {
|
|
61
|
+
"@capacitor/android": "^7.0.0",
|
|
62
|
+
"@capacitor/core": "^7.0.0",
|
|
63
|
+
"@capacitor/docgen": "^0.3.0",
|
|
64
|
+
"@capacitor/ios": "^7.0.0",
|
|
65
|
+
"@ionic/eslint-config": "^0.4.0",
|
|
66
|
+
"@ionic/prettier-config": "^4.0.0",
|
|
67
|
+
"@ionic/swiftlint-config": "^2.0.0",
|
|
68
|
+
"eslint": "^8.57.0",
|
|
69
|
+
"prettier": "^3.5.0",
|
|
70
|
+
"prettier-plugin-java": "^2.6.7",
|
|
71
|
+
"rimraf": "^6.0.1",
|
|
72
|
+
"rollup": "^4.34.6",
|
|
73
|
+
"swiftlint": "^2.0.0",
|
|
74
|
+
"typescript": "^5.7.3"
|
|
75
|
+
},
|
|
76
|
+
"peerDependencies": {
|
|
77
|
+
"@capacitor/core": ">=7.0.0"
|
|
78
|
+
},
|
|
79
|
+
"prettier": "@ionic/prettier-config",
|
|
80
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
81
|
+
"eslintConfig": {
|
|
82
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
83
|
+
},
|
|
84
|
+
"capacitor": {
|
|
85
|
+
"ios": {
|
|
86
|
+
"src": "ios"
|
|
87
|
+
},
|
|
88
|
+
"android": {
|
|
89
|
+
"src": "android"
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"dependencies": {
|
|
93
|
+
"@stream-io/video-client": "1.16.7",
|
|
94
|
+
"@stream-io/audio-filters-web": "^0.2.2"
|
|
95
|
+
}
|
|
96
|
+
}
|