@capgo/capacitor-persona 8.0.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.
@@ -0,0 +1,216 @@
1
+ import Foundation
2
+ import Capacitor
3
+ import Persona2
4
+
5
+ @objc(PersonaPlugin)
6
+ public class PersonaPlugin: CAPPlugin, CAPBridgedPlugin {
7
+ public let identifier = "PersonaPlugin"
8
+ public let jsName = "Persona"
9
+ public let pluginMethods: [CAPPluginMethod] = [
10
+ CAPPluginMethod(name: "startInquiry", returnType: CAPPluginReturnPromise)
11
+ ]
12
+
13
+ @objc func startInquiry(_ call: CAPPluginCall) {
14
+ DispatchQueue.main.async {
15
+ guard let presenter = self.bridge?.viewController else {
16
+ call.reject("Unable to find a presenting view controller.")
17
+ return
18
+ }
19
+
20
+ do {
21
+ let inquiry = try self.buildInquiry(call: call)
22
+ inquiry.start(from: presenter)
23
+ call.resolve()
24
+ } catch let error as PersonaPluginError {
25
+ call.reject(error.localizedDescription)
26
+ } catch {
27
+ call.reject(error.localizedDescription)
28
+ }
29
+ }
30
+ }
31
+
32
+ private func buildInquiry(call: CAPPluginCall) throws -> Inquiry {
33
+ let inquiryId = call.getString("inquiryId")
34
+ let sessionToken = call.getString("sessionToken")
35
+ let templateId = call.getString("templateId")
36
+ let templateVersion = call.getString("templateVersion")
37
+ let referenceId = call.getString("referenceId")
38
+ let accountId = call.getString("accountId")
39
+ let locale = call.getString("locale")
40
+ let fields = makeInquiryFields(from: call.getObject("fields") ?? [:])
41
+ let environment = try parseEnvironment(call.getString("environment"))
42
+
43
+ if let inquiryId {
44
+ let builder = Inquiry.from(inquiryId: inquiryId, delegate: self)
45
+ if let sessionToken {
46
+ _ = builder.sessionToken(sessionToken)
47
+ }
48
+ if let locale {
49
+ _ = builder.locale(locale)
50
+ }
51
+ return builder.build()
52
+ }
53
+
54
+ if let templateId {
55
+ let builder = Inquiry.from(templateId: templateId, delegate: self)
56
+ if let referenceId {
57
+ _ = builder.referenceId(referenceId)
58
+ }
59
+ if let accountId {
60
+ _ = builder.accountId(accountId)
61
+ }
62
+ if !fields.isEmpty {
63
+ _ = builder.fields(fields)
64
+ }
65
+ if let environment {
66
+ _ = builder.environment(environment)
67
+ }
68
+ if let locale {
69
+ _ = builder.locale(locale)
70
+ }
71
+ return builder.build()
72
+ }
73
+
74
+ if let templateVersion {
75
+ if locale != nil {
76
+ throw PersonaPluginError.templateVersionLocaleUnsupported
77
+ }
78
+
79
+ guard let configuration = InquiryConfiguration.build(
80
+ templateVersion: templateVersion,
81
+ referenceId: referenceId,
82
+ accountId: accountId,
83
+ environment: environment,
84
+ fields: fields.isEmpty ? nil : fields
85
+ ) else {
86
+ throw PersonaPluginError.invalidConfiguration
87
+ }
88
+
89
+ return Inquiry(config: configuration, delegate: self)
90
+ }
91
+
92
+ throw PersonaPluginError.missingIdentifier
93
+ }
94
+
95
+ private func parseEnvironment(_ rawValue: String?) throws -> Environment? {
96
+ guard let rawValue = rawValue?.trimmingCharacters(in: .whitespacesAndNewlines), !rawValue.isEmpty else {
97
+ return nil
98
+ }
99
+ guard let environment = Environment(rawValue: rawValue.lowercased()) else {
100
+ throw PersonaPluginError.invalidEnvironment(rawValue)
101
+ }
102
+ return environment
103
+ }
104
+
105
+ private func makeInquiryFields(from dictionary: [String: Any]) -> [String: InquiryField] {
106
+ var output: [String: InquiryField] = [:]
107
+
108
+ for (key, value) in dictionary {
109
+ switch value {
110
+ case let value as String:
111
+ output[key] = .string(value)
112
+ case let value as Bool:
113
+ output[key] = .bool(value)
114
+ case let value as Int:
115
+ output[key] = .int(value)
116
+ case let value as Float:
117
+ output[key] = .float(value)
118
+ case let value as Double:
119
+ output[key] = .float(Float(value))
120
+ case let value as NSNumber:
121
+ if CFGetTypeID(value) == CFBooleanGetTypeID() {
122
+ output[key] = .bool(value.boolValue)
123
+ } else if value.doubleValue.rounded() == value.doubleValue {
124
+ output[key] = .int(value.intValue)
125
+ } else {
126
+ output[key] = .float(value.floatValue)
127
+ }
128
+ case let value as Date:
129
+ output[key] = .datetime(value)
130
+ case let values as [String]:
131
+ output[key] = .multiChoices(values)
132
+ case let values as [Any]:
133
+ let stringValues = values.compactMap { $0 as? String }
134
+ output[key] = .multiChoices(stringValues)
135
+ default:
136
+ output[key] = .unknown
137
+ }
138
+ }
139
+
140
+ return output
141
+ }
142
+
143
+ private func serializeField(_ field: InquiryField) -> Any {
144
+ switch field {
145
+ case .string(let value):
146
+ return value ?? NSNull()
147
+ case .int(let value):
148
+ return value ?? NSNull()
149
+ case .float(let value):
150
+ return value ?? NSNull()
151
+ case .bool(let value):
152
+ return value ?? NSNull()
153
+ case .date(let value):
154
+ return value?.timeIntervalSince1970 ?? NSNull()
155
+ case .datetime(let value):
156
+ return value?.timeIntervalSince1970 ?? NSNull()
157
+ case .choices(let value):
158
+ return value ?? NSNull()
159
+ case .multiChoices(let value):
160
+ return value ?? []
161
+ case .unknown:
162
+ return NSNull()
163
+ @unknown default:
164
+ return NSNull()
165
+ }
166
+ }
167
+ }
168
+
169
+ extension PersonaPlugin: InquiryDelegate {
170
+ public func inquiryComplete(inquiryId: String, status: String, fields: [String: InquiryField]) {
171
+ let serializedFields = fields.mapValues(serializeField)
172
+ notifyListeners("inquiryComplete", data: [
173
+ "inquiryId": inquiryId,
174
+ "status": status,
175
+ "fields": serializedFields
176
+ ])
177
+ }
178
+
179
+ public func inquiryCanceled(inquiryId: String?, sessionToken: String?) {
180
+ var payload: [String: Any] = [:]
181
+ if let inquiryId {
182
+ payload["inquiryId"] = inquiryId
183
+ }
184
+ if let sessionToken {
185
+ payload["sessionToken"] = sessionToken
186
+ }
187
+
188
+ notifyListeners("inquiryCanceled", data: payload)
189
+ }
190
+
191
+ public func inquiryError(_ error: any Error) {
192
+ notifyListeners("inquiryError", data: [
193
+ "error": error.localizedDescription
194
+ ])
195
+ }
196
+ }
197
+
198
+ private enum PersonaPluginError: LocalizedError {
199
+ case missingIdentifier
200
+ case invalidEnvironment(String)
201
+ case invalidConfiguration
202
+ case templateVersionLocaleUnsupported
203
+
204
+ var errorDescription: String? {
205
+ switch self {
206
+ case .missingIdentifier:
207
+ return "At least one of inquiryId, templateId, or templateVersion must be provided."
208
+ case .invalidEnvironment(let value):
209
+ return "Unsupported Persona environment '\(value)'. Use 'production' or 'sandbox'."
210
+ case .invalidConfiguration:
211
+ return "Unable to build a Persona inquiry configuration with the provided options."
212
+ case .templateVersionLocaleUnsupported:
213
+ return "The locale option is not supported when starting an inquiry with templateVersion on iOS."
214
+ }
215
+ }
216
+ }
@@ -0,0 +1,8 @@
1
+ import XCTest
2
+ @testable import PersonaPlugin
3
+
4
+ final class PersonaPluginTests: XCTestCase {
5
+ func testPlaceholder() {
6
+ XCTAssertTrue(true)
7
+ }
8
+ }
package/package.json ADDED
@@ -0,0 +1,90 @@
1
+ {
2
+ "name": "@capgo/capacitor-persona",
3
+ "version": "8.0.0",
4
+ "description": "Capacitor plugin for launching Persona Inquiry flows on iOS and Android.",
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
+ "CapgoCapacitorPersona.podspec"
17
+ ],
18
+ "author": "Martin Donadieu <martin@capgo.app>",
19
+ "license": "MPL-2.0",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "git+https://github.com/Cap-go/capacitor-persona.git"
23
+ },
24
+ "bugs": {
25
+ "url": "https://github.com/Cap-go/capacitor-persona/issues"
26
+ },
27
+ "homepage": "https://capgo.app/docs/plugins/persona/",
28
+ "keywords": [
29
+ "capacitor",
30
+ "plugin",
31
+ "persona",
32
+ "inquiry",
33
+ "identity-verification"
34
+ ],
35
+ "scripts": {
36
+ "init-plugin": "./scripts/init-plugin.sh",
37
+ "verify": "bun run verify:ios && bun run verify:android && bun run verify:web",
38
+ "verify:ios": "xcodebuild -scheme CapgoCapacitorPersona -destination generic/platform=iOS",
39
+ "verify:android": "cd android && ./gradlew clean build test && cd ..",
40
+ "verify:web": "bun run build",
41
+ "lint": "bun run eslint && bun run prettier -- --check && bun run swiftlint -- lint",
42
+ "fmt": "bun run eslint -- --fix && bun run prettier -- --write && bun run swiftlint -- --fix --format",
43
+ "eslint": "eslint . --ext .ts",
44
+ "prettier": "prettier-pretty-check \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
45
+ "swiftlint": "node-swiftlint",
46
+ "docgen": "docgen --api PersonaPlugin --output-readme README.md --output-json dist/docs.json",
47
+ "build": "bun run clean && bun run docgen && tsc && rollup -c rollup.config.mjs",
48
+ "clean": "rimraf ./dist",
49
+ "watch": "tsc --watch",
50
+ "prepublishOnly": "bun run build",
51
+ "check:wiring": "node scripts/check-capacitor-plugin-wiring.mjs"
52
+ },
53
+ "devDependencies": {
54
+ "@capacitor/android": "^8.0.0",
55
+ "@capacitor/cli": "^8.0.0",
56
+ "@capacitor/core": "^8.0.0",
57
+ "@capacitor/docgen": "^0.3.1",
58
+ "@capacitor/ios": "^8.0.0",
59
+ "@ionic/eslint-config": "^0.4.0",
60
+ "@ionic/prettier-config": "^4.0.0",
61
+ "@ionic/swiftlint-config": "^2.0.0",
62
+ "@types/node": "^24.10.1",
63
+ "eslint": "^8.57.1",
64
+ "eslint-plugin-import": "^2.31.0",
65
+ "husky": "^9.1.7",
66
+ "prettier": "^3.6.2",
67
+ "prettier-pretty-check": "^0.2.0",
68
+ "prettier-plugin-java": "^2.7.7",
69
+ "rimraf": "^6.1.0",
70
+ "rollup": "^4.53.2",
71
+ "swiftlint": "^2.0.0",
72
+ "typescript": "^5.9.3"
73
+ },
74
+ "peerDependencies": {
75
+ "@capacitor/core": ">=8.0.0"
76
+ },
77
+ "prettier": "@ionic/prettier-config",
78
+ "swiftlint": "@ionic/swiftlint-config",
79
+ "eslintConfig": {
80
+ "extends": "@ionic/eslint-config/recommended"
81
+ },
82
+ "capacitor": {
83
+ "ios": {
84
+ "src": "ios"
85
+ },
86
+ "android": {
87
+ "src": "android"
88
+ }
89
+ }
90
+ }