react-native-nitro-passkeys 0.1.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.
Files changed (88) hide show
  1. package/LICENSE +21 -0
  2. package/NitroPasskeys.podspec +37 -0
  3. package/README.md +314 -0
  4. package/android/CMakeLists.txt +31 -0
  5. package/android/build.gradle +155 -0
  6. package/android/fix-prefab.gradle +51 -0
  7. package/android/gradle.properties +5 -0
  8. package/android/src/main/AndroidManifest.xml +2 -0
  9. package/android/src/main/cpp/cpp-adapter.cpp +9 -0
  10. package/android/src/main/java/com/margelo/nitro/nitropasskeys/HybridNitroPasskeys.kt +65 -0
  11. package/android/src/main/java/com/margelo/nitro/nitropasskeys/NitroPasskeysPackage.kt +20 -0
  12. package/android/src/main/java/com/margelo/nitro/nitropasskeys/PasskeyErrorToken.kt +64 -0
  13. package/android/src/test/java/com/margelo/nitro/nitropasskeys/PasskeyErrorTokenTest.kt +128 -0
  14. package/ios/Base64URL.swift +37 -0
  15. package/ios/Bridge.h +1 -0
  16. package/ios/HybridNitroPasskeys.swift +290 -0
  17. package/ios/PasskeyErrorToken.swift +32 -0
  18. package/ios/PasskeyJSON.swift +195 -0
  19. package/lib/commonjs/PasskeyError.js +39 -0
  20. package/lib/commonjs/PasskeyError.js.map +1 -0
  21. package/lib/commonjs/index.js +52 -0
  22. package/lib/commonjs/index.js.map +1 -0
  23. package/lib/commonjs/package.json +1 -0
  24. package/lib/commonjs/response.js +30 -0
  25. package/lib/commonjs/response.js.map +1 -0
  26. package/lib/commonjs/specs/nitro-passkeys.nitro.js +6 -0
  27. package/lib/commonjs/specs/nitro-passkeys.nitro.js.map +1 -0
  28. package/lib/commonjs/types.js +2 -0
  29. package/lib/commonjs/types.js.map +1 -0
  30. package/lib/commonjs/validate.js +118 -0
  31. package/lib/commonjs/validate.js.map +1 -0
  32. package/lib/module/PasskeyError.js +34 -0
  33. package/lib/module/PasskeyError.js.map +1 -0
  34. package/lib/module/index.js +42 -0
  35. package/lib/module/index.js.map +1 -0
  36. package/lib/module/response.js +25 -0
  37. package/lib/module/response.js.map +1 -0
  38. package/lib/module/specs/nitro-passkeys.nitro.js +4 -0
  39. package/lib/module/specs/nitro-passkeys.nitro.js.map +1 -0
  40. package/lib/module/types.js +2 -0
  41. package/lib/module/types.js.map +1 -0
  42. package/lib/module/validate.js +109 -0
  43. package/lib/module/validate.js.map +1 -0
  44. package/lib/typescript/example/server/index.d.ts +2 -0
  45. package/lib/typescript/example/server/index.d.ts.map +1 -0
  46. package/lib/typescript/src/PasskeyError.d.ts +8 -0
  47. package/lib/typescript/src/PasskeyError.d.ts.map +1 -0
  48. package/lib/typescript/src/index.d.ts +8 -0
  49. package/lib/typescript/src/index.d.ts.map +1 -0
  50. package/lib/typescript/src/response.d.ts +4 -0
  51. package/lib/typescript/src/response.d.ts.map +1 -0
  52. package/lib/typescript/src/specs/nitro-passkeys.nitro.d.ts +12 -0
  53. package/lib/typescript/src/specs/nitro-passkeys.nitro.d.ts.map +1 -0
  54. package/lib/typescript/src/types.d.ts +104 -0
  55. package/lib/typescript/src/types.d.ts.map +1 -0
  56. package/lib/typescript/src/validate.d.ts +14 -0
  57. package/lib/typescript/src/validate.d.ts.map +1 -0
  58. package/nitro.json +24 -0
  59. package/nitrogen/generated/.gitattributes +1 -0
  60. package/nitrogen/generated/android/NitroPasskeys+autolinking.cmake +81 -0
  61. package/nitrogen/generated/android/NitroPasskeys+autolinking.gradle +27 -0
  62. package/nitrogen/generated/android/NitroPasskeysOnLoad.cpp +54 -0
  63. package/nitrogen/generated/android/NitroPasskeysOnLoad.hpp +34 -0
  64. package/nitrogen/generated/android/c++/JHybridNitroPasskeysSpec.cpp +86 -0
  65. package/nitrogen/generated/android/c++/JHybridNitroPasskeysSpec.hpp +64 -0
  66. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitropasskeys/HybridNitroPasskeysSpec.kt +63 -0
  67. package/nitrogen/generated/android/kotlin/com/margelo/nitro/nitropasskeys/NitroPasskeysOnLoad.kt +35 -0
  68. package/nitrogen/generated/ios/NitroPasskeys+autolinking.rb +62 -0
  69. package/nitrogen/generated/ios/NitroPasskeys-Swift-Cxx-Bridge.cpp +49 -0
  70. package/nitrogen/generated/ios/NitroPasskeys-Swift-Cxx-Bridge.hpp +111 -0
  71. package/nitrogen/generated/ios/NitroPasskeys-Swift-Cxx-Umbrella.hpp +45 -0
  72. package/nitrogen/generated/ios/NitroPasskeysAutolinking.mm +33 -0
  73. package/nitrogen/generated/ios/NitroPasskeysAutolinking.swift +26 -0
  74. package/nitrogen/generated/ios/c++/HybridNitroPasskeysSpecSwift.cpp +11 -0
  75. package/nitrogen/generated/ios/c++/HybridNitroPasskeysSpecSwift.hpp +93 -0
  76. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +46 -0
  77. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +46 -0
  78. package/nitrogen/generated/ios/swift/HybridNitroPasskeysSpec.swift +56 -0
  79. package/nitrogen/generated/ios/swift/HybridNitroPasskeysSpec_cxx.swift +169 -0
  80. package/nitrogen/generated/shared/c++/HybridNitroPasskeysSpec.cpp +23 -0
  81. package/nitrogen/generated/shared/c++/HybridNitroPasskeysSpec.hpp +64 -0
  82. package/package.json +106 -0
  83. package/src/PasskeyError.ts +58 -0
  84. package/src/index.ts +66 -0
  85. package/src/response.ts +49 -0
  86. package/src/specs/nitro-passkeys.nitro.ts +12 -0
  87. package/src/types.ts +124 -0
  88. package/src/validate.ts +132 -0
@@ -0,0 +1,195 @@
1
+ import Foundation
2
+ import NitroModules
3
+
4
+ /// The WebAuthn JSON shapes iOS reads and writes. Decoders only declare the fields iOS uses;
5
+ /// unknown keys (`timeout`, `hints`, `extensions`, …) are ignored.
6
+ enum PasskeyJSON {
7
+ // MARK: Options (JS → native)
8
+
9
+ struct CreationOptions: Decodable {
10
+ // swiftlint:disable:next identifier_name
11
+ let rp: RelyingParty
12
+ let user: User
13
+ let challenge: String
14
+ let excludeCredentials: [Descriptor]?
15
+ let authenticatorSelection: Selection?
16
+ let attestation: String?
17
+ }
18
+
19
+ struct RelyingParty: Decodable {
20
+ let id: String?
21
+ }
22
+
23
+ struct User: Decodable {
24
+ let id: String
25
+ let name: String
26
+ let displayName: String?
27
+ }
28
+
29
+ struct Descriptor: Decodable {
30
+ let id: String
31
+ }
32
+
33
+ struct Selection: Decodable {
34
+ let userVerification: String?
35
+ }
36
+
37
+ struct RequestOptions: Decodable {
38
+ let challenge: String
39
+ let rpId: String?
40
+ let allowCredentials: [Descriptor]?
41
+ let userVerification: String?
42
+ }
43
+
44
+ // MARK: Responses (native → JS)
45
+
46
+ struct RegistrationResponseBody: Encodable {
47
+ let clientDataJSON: String
48
+ let attestationObject: String
49
+ let transports: [String]
50
+ }
51
+
52
+ struct RegistrationResponse: Encodable {
53
+ let id: String
54
+ let rawId: String
55
+ let type: String
56
+ let authenticatorAttachment: String
57
+ let clientExtensionResults: [String: String]
58
+ let response: RegistrationResponseBody
59
+
60
+ init(credentialID: Data, clientDataJSON: Data, attestationObject: Data, attachment: String) {
61
+ let encodedID = Base64URL.encode(credentialID)
62
+ id = encodedID
63
+ rawId = encodedID
64
+ type = "public-key"
65
+ authenticatorAttachment = attachment
66
+ clientExtensionResults = [:]
67
+ response = RegistrationResponseBody(
68
+ clientDataJSON: Base64URL.encode(clientDataJSON),
69
+ attestationObject: Base64URL.encode(attestationObject),
70
+ transports: ["internal", "hybrid"]
71
+ )
72
+ }
73
+ }
74
+
75
+ struct AssertionResponseBody: Encodable {
76
+ let clientDataJSON: String
77
+ let authenticatorData: String
78
+ let signature: String
79
+ /// `nil` is omitted from the output by the synthesized `encodeIfPresent`.
80
+ let userHandle: String?
81
+ }
82
+
83
+ struct AssertionResponse: Encodable {
84
+ let id: String
85
+ let rawId: String
86
+ let type: String
87
+ let authenticatorAttachment: String
88
+ let clientExtensionResults: [String: String]
89
+ let response: AssertionResponseBody
90
+
91
+ init(
92
+ credentialID: Data,
93
+ clientDataJSON: Data,
94
+ authenticatorData: Data,
95
+ signature: Data,
96
+ userID: Data?,
97
+ attachment: String
98
+ ) {
99
+ let encodedID = Base64URL.encode(credentialID)
100
+ id = encodedID
101
+ rawId = encodedID
102
+ type = "public-key"
103
+ authenticatorAttachment = attachment
104
+ clientExtensionResults = [:]
105
+ let userHandle = userID.flatMap { $0.isEmpty ? nil : Base64URL.encode($0) }
106
+ response = AssertionResponseBody(
107
+ clientDataJSON: Base64URL.encode(clientDataJSON),
108
+ authenticatorData: Base64URL.encode(authenticatorData),
109
+ signature: Base64URL.encode(signature),
110
+ userHandle: userHandle
111
+ )
112
+ }
113
+ }
114
+
115
+ static func encode<T: Encodable>(_ value: T) throws -> String {
116
+ let encoder = JSONEncoder()
117
+ encoder.outputFormatting = [.withoutEscapingSlashes]
118
+ guard let json = String(bytes: try encoder.encode(value), encoding: .utf8) else {
119
+ let message = PasskeyErrorToken.message(token: "unknown", "Could not encode the response")
120
+ throw RuntimeError.error(withMessage: message)
121
+ }
122
+ return json
123
+ }
124
+ }
125
+
126
+ // MARK: - Validated parameters
127
+
128
+ /// Decoded, validated `create` inputs. Plain values only, so they can cross to the main thread.
129
+ struct RegistrationParameters: Sendable {
130
+ let rpID: String
131
+ let challenge: Data
132
+ let userName: String
133
+ let userID: Data
134
+ let displayName: String?
135
+ let userVerification: String?
136
+ let attestation: String
137
+ let excludedCredentialIDs: [Data]
138
+
139
+ init(json: String) throws {
140
+ let options = try decodeOptions(PasskeyJSON.CreationOptions.self, from: json, label: "creation")
141
+ guard let rpID = options.rp.id, !rpID.isEmpty else {
142
+ throw invalidOptions("rp.id is required")
143
+ }
144
+ self.rpID = rpID
145
+ challenge = try decodeField(options.challenge, "challenge")
146
+ userName = options.user.name
147
+ userID = try decodeField(options.user.id, "user.id")
148
+ displayName = options.user.displayName
149
+ userVerification = options.authenticatorSelection?.userVerification
150
+ attestation = options.attestation ?? "none"
151
+ excludedCredentialIDs = try (options.excludeCredentials ?? []).enumerated().map { index, descriptor in
152
+ try decodeField(descriptor.id, "excludeCredentials[\(index)].id")
153
+ }
154
+ }
155
+ }
156
+
157
+ /// Decoded, validated `get` inputs.
158
+ struct AssertionParameters: Sendable {
159
+ let rpID: String
160
+ let challenge: Data
161
+ let userVerification: String?
162
+ let allowedCredentialIDs: [Data]
163
+
164
+ init(json: String) throws {
165
+ let options = try decodeOptions(PasskeyJSON.RequestOptions.self, from: json, label: "request")
166
+ guard let rpID = options.rpId, !rpID.isEmpty else {
167
+ throw invalidOptions("rpId is required")
168
+ }
169
+ self.rpID = rpID
170
+ challenge = try decodeField(options.challenge, "challenge")
171
+ userVerification = options.userVerification
172
+ allowedCredentialIDs = try (options.allowCredentials ?? []).enumerated().map { index, descriptor in
173
+ try decodeField(descriptor.id, "allowCredentials[\(index)].id")
174
+ }
175
+ }
176
+ }
177
+
178
+ private func invalidOptions(_ text: String) -> Error {
179
+ RuntimeError.error(withMessage: PasskeyErrorToken.message(token: "invalidOptions", text))
180
+ }
181
+
182
+ private func decodeOptions<T: Decodable>(_ type: T.Type, from json: String, label: String) throws -> T {
183
+ do {
184
+ return try JSONDecoder().decode(type, from: Data(json.utf8))
185
+ } catch {
186
+ throw invalidOptions("Invalid \(label) options JSON: \(error.localizedDescription)")
187
+ }
188
+ }
189
+
190
+ private func decodeField(_ value: String, _ name: String) throws -> Data {
191
+ guard let data = Base64URL.decode(value) else {
192
+ throw invalidOptions("\(name) is not valid base64url")
193
+ }
194
+ return data
195
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.PasskeyError = void 0;
7
+ const CODES = new Set(['canceled', 'noCredentials', 'alreadyRegistered', 'domainNotAssociated', 'unsupported', 'invalidOptions', 'unknown']);
8
+ const TOKEN_RE = /\[Passkeys:([A-Za-z0-9-]+)\]\s?/;
9
+ const ASAUTH_RE = /^asauth-\d+$/;
10
+ function codeForToken(token) {
11
+ if (token === undefined) return 'unknown';
12
+ if (token === 'asauth-1001') return 'canceled';
13
+ if (token === 'asauth-1006') return 'alreadyRegistered';
14
+ if (ASAUTH_RE.test(token)) return 'unknown';
15
+ return CODES.has(token) ? token : 'unknown';
16
+ }
17
+ class PasskeyError extends Error {
18
+ constructor(code, message) {
19
+ super(message);
20
+ this.name = 'PasskeyError';
21
+ this.code = code;
22
+ }
23
+
24
+ /** Normalises any thrown value into a `PasskeyError`. Never throws. */
25
+ static from(error) {
26
+ try {
27
+ if (error instanceof PasskeyError) return error;
28
+ const original = error instanceof Error ? error.message : typeof error === 'string' ? error : 'Unknown error';
29
+ const match = TOKEN_RE.exec(original);
30
+ const code = codeForToken(match?.[1]);
31
+ const stripped = match ? original.replace(TOKEN_RE, '') : original;
32
+ return new PasskeyError(code, stripped.length > 0 ? stripped : original);
33
+ } catch {
34
+ return new PasskeyError('unknown', 'Unknown error');
35
+ }
36
+ }
37
+ }
38
+ exports.PasskeyError = PasskeyError;
39
+ //# sourceMappingURL=PasskeyError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["CODES","Set","TOKEN_RE","ASAUTH_RE","codeForToken","token","undefined","test","has","PasskeyError","Error","constructor","code","message","name","from","error","original","match","exec","stripped","replace","length","exports"],"sourceRoot":"../../src","sources":["PasskeyError.ts"],"mappings":";;;;;;AASA,MAAMA,KAA0B,GAAG,IAAIC,GAAG,CAAmB,CAC3D,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,SAAS,CACV,CAAC;AAEF,MAAMC,QAAQ,GAAG,iCAAiC;AAClD,MAAMC,SAAS,GAAG,cAAc;AAEhC,SAASC,YAAYA,CAACC,KAAyB,EAAoB;EACjE,IAAIA,KAAK,KAAKC,SAAS,EAAE,OAAO,SAAS;EACzC,IAAID,KAAK,KAAK,aAAa,EAAE,OAAO,UAAU;EAC9C,IAAIA,KAAK,KAAK,aAAa,EAAE,OAAO,mBAAmB;EACvD,IAAIF,SAAS,CAACI,IAAI,CAACF,KAAK,CAAC,EAAE,OAAO,SAAS;EAC3C,OAAOL,KAAK,CAACQ,GAAG,CAACH,KAAK,CAAC,GAAIA,KAAK,GAAwB,SAAS;AACnE;AAEO,MAAMI,YAAY,SAASC,KAAK,CAAC;EAGtCC,WAAWA,CAACC,IAAsB,EAAEC,OAAe,EAAE;IACnD,KAAK,CAACA,OAAO,CAAC;IACd,IAAI,CAACC,IAAI,GAAG,cAAc;IAC1B,IAAI,CAACF,IAAI,GAAGA,IAAI;EAClB;;EAEA;EACA,OAAOG,IAAIA,CAACC,KAAc,EAAgB;IACxC,IAAI;MACF,IAAIA,KAAK,YAAYP,YAAY,EAAE,OAAOO,KAAK;MAC/C,MAAMC,QAAQ,GACZD,KAAK,YAAYN,KAAK,GAClBM,KAAK,CAACH,OAAO,GACb,OAAOG,KAAK,KAAK,QAAQ,GACvBA,KAAK,GACL,eAAe;MACvB,MAAME,KAAK,GAAGhB,QAAQ,CAACiB,IAAI,CAACF,QAAQ,CAAC;MACrC,MAAML,IAAI,GAAGR,YAAY,CAACc,KAAK,GAAG,CAAC,CAAC,CAAC;MACrC,MAAME,QAAQ,GAAGF,KAAK,GAAGD,QAAQ,CAACI,OAAO,CAACnB,QAAQ,EAAE,EAAE,CAAC,GAAGe,QAAQ;MAClE,OAAO,IAAIR,YAAY,CAACG,IAAI,EAAEQ,QAAQ,CAACE,MAAM,GAAG,CAAC,GAAGF,QAAQ,GAAGH,QAAQ,CAAC;IAC1E,CAAC,CAAC,MAAM;MACN,OAAO,IAAIR,YAAY,CAAC,SAAS,EAAE,eAAe,CAAC;IACrD;EACF;AACF;AAACc,OAAA,CAAAd,YAAA,GAAAA,YAAA","ignoreList":[]}
@@ -0,0 +1,52 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "PasskeyError", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _PasskeyError.PasskeyError;
10
+ }
11
+ });
12
+ exports.createPasskey = createPasskey;
13
+ exports.getPasskey = getPasskey;
14
+ exports.isPasskeySupported = isPasskeySupported;
15
+ var _reactNativeNitroModules = require("react-native-nitro-modules");
16
+ var _PasskeyError = require("./PasskeyError");
17
+ var _response = require("./response");
18
+ var _validate = require("./validate");
19
+ // Deliberately not exported: every caller goes through the helpers and gets typed errors.
20
+ const native = _reactNativeNitroModules.NitroModules.createHybridObject('NitroPasskeys');
21
+ function isPasskeySupported() {
22
+ return native.isSupported;
23
+ }
24
+ async function createPasskey(options) {
25
+ if (!isPasskeySupported()) {
26
+ throw new _PasskeyError.PasskeyError('unsupported', 'Passkeys are not supported on this device');
27
+ }
28
+ const reason = (0, _validate.validateCreationOptions)(options);
29
+ if (reason) throw new _PasskeyError.PasskeyError('invalidOptions', reason);
30
+ let raw;
31
+ try {
32
+ raw = await native.create(JSON.stringify(options));
33
+ } catch (error) {
34
+ throw _PasskeyError.PasskeyError.from(error);
35
+ }
36
+ return (0, _response.parseRegistrationResponse)(raw);
37
+ }
38
+ async function getPasskey(options) {
39
+ if (!isPasskeySupported()) {
40
+ throw new _PasskeyError.PasskeyError('unsupported', 'Passkeys are not supported on this device');
41
+ }
42
+ const reason = (0, _validate.validateRequestOptions)(options);
43
+ if (reason) throw new _PasskeyError.PasskeyError('invalidOptions', reason);
44
+ let raw;
45
+ try {
46
+ raw = await native.get(JSON.stringify(options));
47
+ } catch (error) {
48
+ throw _PasskeyError.PasskeyError.from(error);
49
+ }
50
+ return (0, _response.parseAuthenticationResponse)(raw);
51
+ }
52
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNativeNitroModules","require","_PasskeyError","_response","_validate","native","NitroModules","createHybridObject","isPasskeySupported","isSupported","createPasskey","options","PasskeyError","reason","validateCreationOptions","raw","create","JSON","stringify","error","from","parseRegistrationResponse","getPasskey","validateRequestOptions","get","parseAuthenticationResponse"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;AAAA,IAAAA,wBAAA,GAAAC,OAAA;AAEA,IAAAC,aAAA,GAAAD,OAAA;AACA,IAAAE,SAAA,GAAAF,OAAA;AAWA,IAAAG,SAAA,GAAAH,OAAA;AAEA;AACA,MAAMI,MAAM,GAAGC,qCAAY,CAACC,kBAAkB,CAAgB,eAAe,CAAC;AAEvE,SAASC,kBAAkBA,CAAA,EAAY;EAC5C,OAAOH,MAAM,CAACI,WAAW;AAC3B;AAEO,eAAeC,aAAaA,CACjCC,OAA+C,EACZ;EACnC,IAAI,CAACH,kBAAkB,CAAC,CAAC,EAAE;IACzB,MAAM,IAAII,0BAAY,CACpB,aAAa,EACb,2CACF,CAAC;EACH;EACA,MAAMC,MAAM,GAAG,IAAAC,iCAAuB,EAACH,OAAO,CAAC;EAC/C,IAAIE,MAAM,EAAE,MAAM,IAAID,0BAAY,CAAC,gBAAgB,EAAEC,MAAM,CAAC;EAC5D,IAAIE,GAAW;EACf,IAAI;IACFA,GAAG,GAAG,MAAMV,MAAM,CAACW,MAAM,CAACC,IAAI,CAACC,SAAS,CAACP,OAAO,CAAC,CAAC;EACpD,CAAC,CAAC,OAAOQ,KAAK,EAAE;IACd,MAAMP,0BAAY,CAACQ,IAAI,CAACD,KAAK,CAAC;EAChC;EACA,OAAO,IAAAE,mCAAyB,EAACN,GAAG,CAAC;AACvC;AAEO,eAAeO,UAAUA,CAC9BX,OAA8C,EACT;EACrC,IAAI,CAACH,kBAAkB,CAAC,CAAC,EAAE;IACzB,MAAM,IAAII,0BAAY,CACpB,aAAa,EACb,2CACF,CAAC;EACH;EACA,MAAMC,MAAM,GAAG,IAAAU,gCAAsB,EAACZ,OAAO,CAAC;EAC9C,IAAIE,MAAM,EAAE,MAAM,IAAID,0BAAY,CAAC,gBAAgB,EAAEC,MAAM,CAAC;EAC5D,IAAIE,GAAW;EACf,IAAI;IACFA,GAAG,GAAG,MAAMV,MAAM,CAACmB,GAAG,CAACP,IAAI,CAACC,SAAS,CAACP,OAAO,CAAC,CAAC;EACjD,CAAC,CAAC,OAAOQ,KAAK,EAAE;IACd,MAAMP,0BAAY,CAACQ,IAAI,CAACD,KAAK,CAAC;EAChC;EACA,OAAO,IAAAM,qCAA2B,EAACV,GAAG,CAAC;AACzC","ignoreList":[]}
@@ -0,0 +1 @@
1
+ {"type":"commonjs"}
@@ -0,0 +1,30 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.parseAuthenticationResponse = parseAuthenticationResponse;
7
+ exports.parseRegistrationResponse = parseRegistrationResponse;
8
+ var _PasskeyError = require("./PasskeyError");
9
+ var _validate = require("./validate");
10
+ function parse(raw, label, validate) {
11
+ let value;
12
+ try {
13
+ value = JSON.parse(raw);
14
+ } catch {
15
+ throw new _PasskeyError.PasskeyError('unknown', `Malformed ${label} response: not JSON`);
16
+ }
17
+ const reason = validate(value);
18
+ if (reason) throw new _PasskeyError.PasskeyError('unknown', `Malformed ${label} response: ${reason}`);
19
+ const result = value;
20
+ // The only normalisation: nothing else is added, removed or re-encoded.
21
+ result.clientExtensionResults ??= {};
22
+ return result;
23
+ }
24
+ function parseRegistrationResponse(raw) {
25
+ return parse(raw, 'registration', _validate.validateRegistrationResponse);
26
+ }
27
+ function parseAuthenticationResponse(raw) {
28
+ return parse(raw, 'authentication', _validate.validateAuthenticationResponse);
29
+ }
30
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_PasskeyError","require","_validate","parse","raw","label","validate","value","JSON","PasskeyError","reason","result","clientExtensionResults","parseRegistrationResponse","validateRegistrationResponse","parseAuthenticationResponse","validateAuthenticationResponse"],"sourceRoot":"../../src","sources":["response.ts"],"mappings":";;;;;;;AAAA,IAAAA,aAAA,GAAAC,OAAA;AAKA,IAAAC,SAAA,GAAAD,OAAA;AAKA,SAASE,KAAKA,CACZC,GAAW,EACXC,KAAwC,EACxCC,QAAgD,EAC7C;EACH,IAAIC,KAAc;EAClB,IAAI;IACFA,KAAK,GAAGC,IAAI,CAACL,KAAK,CAACC,GAAG,CAAC;EACzB,CAAC,CAAC,MAAM;IACN,MAAM,IAAIK,0BAAY,CAAC,SAAS,EAAE,aAAaJ,KAAK,qBAAqB,CAAC;EAC5E;EACA,MAAMK,MAAM,GAAGJ,QAAQ,CAACC,KAAK,CAAC;EAC9B,IAAIG,MAAM,EACR,MAAM,IAAID,0BAAY,CAAC,SAAS,EAAE,aAAaJ,KAAK,cAAcK,MAAM,EAAE,CAAC;EAC7E,MAAMC,MAAM,GAAGJ,KAAU;EACzB;EACAI,MAAM,CAACC,sBAAsB,KAAK,CAAC,CAAC;EACpC,OAAOD,MAAM;AACf;AAEO,SAASE,yBAAyBA,CACvCT,GAAW,EACe;EAC1B,OAAOD,KAAK,CACVC,GAAG,EACH,cAAc,EACdU,sCACF,CAAC;AACH;AAEO,SAASC,2BAA2BA,CACzCX,GAAW,EACiB;EAC5B,OAAOD,KAAK,CACVC,GAAG,EACH,gBAAgB,EAChBY,wCACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,6 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ //# sourceMappingURL=nitro-passkeys.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/nitro-passkeys.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.base64URLByteLength = base64URLByteLength;
7
+ exports.isBase64URL = isBase64URL;
8
+ exports.validateAuthenticationResponse = validateAuthenticationResponse;
9
+ exports.validateCreationOptions = validateCreationOptions;
10
+ exports.validateRegistrationResponse = validateRegistrationResponse;
11
+ exports.validateRequestOptions = validateRequestOptions;
12
+ const BASE64URL_RE = /^[A-Za-z0-9_-]+={0,2}$/;
13
+ function unpaddedLength(value) {
14
+ let end = value.length;
15
+ while (end > 0 && value[end - 1] === '=') end--;
16
+ return end;
17
+ }
18
+
19
+ /**
20
+ * True for a non-empty base64url string with optional `=` padding. Rejects `+`, `/`, whitespace,
21
+ * impossible lengths (unpadded length % 4 === 1) and padding that does not complete a 4-char group.
22
+ */
23
+ function isBase64URL(value) {
24
+ if (typeof value !== 'string' || !BASE64URL_RE.test(value)) return false;
25
+ const unpadded = unpaddedLength(value);
26
+ if (unpadded === 0 || unpadded % 4 === 1) return false;
27
+ if (unpadded !== value.length && value.length % 4 !== 0) return false;
28
+ return true;
29
+ }
30
+
31
+ /** Number of bytes a valid base64url string decodes to. */
32
+ function base64URLByteLength(value) {
33
+ return Math.floor(unpaddedLength(value) * 3 / 4);
34
+ }
35
+ function isRecord(value) {
36
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
37
+ }
38
+ function isNonEmptyString(value) {
39
+ return typeof value === 'string' && value.length > 0;
40
+ }
41
+ function validateDescriptors(value, field) {
42
+ if (value === undefined) return undefined;
43
+ if (!Array.isArray(value)) return `${field} must be an array`;
44
+ for (const [index, entry] of value.entries()) {
45
+ if (!isRecord(entry) || !isBase64URL(entry['id'])) {
46
+ return `${field}[${index}].id is not valid base64url`;
47
+ }
48
+ }
49
+ return undefined;
50
+ }
51
+
52
+ /** Returns a reason for the first failing rule, or `undefined` when the options are valid. */
53
+ function validateCreationOptions(options) {
54
+ if (!isRecord(options)) return 'options must be an object';
55
+ const {
56
+ rp,
57
+ user,
58
+ challenge,
59
+ excludeCredentials,
60
+ pubKeyCredParams
61
+ } = options;
62
+ if (!isRecord(rp)) return 'rp must be an object';
63
+ if (!isNonEmptyString(rp['id'])) return 'rp.id is required';
64
+ if (!isNonEmptyString(challenge)) return 'challenge is required';
65
+ if (!isBase64URL(challenge)) return 'challenge is not valid base64url';
66
+ if (!isRecord(user)) return 'user must be an object';
67
+ if (!isNonEmptyString(user['id'])) return 'user.id is required';
68
+ if (!isNonEmptyString(user['name'])) return 'user.name is required';
69
+ if (!isBase64URL(user['id'])) return 'user.id is not valid base64url';
70
+ const userIdBytes = base64URLByteLength(user['id']);
71
+ if (userIdBytes < 1 || userIdBytes > 64) return 'user.id must decode to 1-64 bytes';
72
+ const excludeReason = validateDescriptors(excludeCredentials, 'excludeCredentials');
73
+ if (excludeReason) return excludeReason;
74
+ if (pubKeyCredParams !== undefined) {
75
+ if (!Array.isArray(pubKeyCredParams)) return 'pubKeyCredParams must be an array';
76
+ if (pubKeyCredParams.length > 0 && !pubKeyCredParams.some(param => isRecord(param) && param['alg'] === -7)) {
77
+ return 'pubKeyCredParams must include ES256 (alg -7)';
78
+ }
79
+ }
80
+ return undefined;
81
+ }
82
+
83
+ /** Returns a reason for the first failing rule, or `undefined` when the options are valid. */
84
+ function validateRequestOptions(options) {
85
+ if (!isRecord(options)) return 'options must be an object';
86
+ if (!isNonEmptyString(options['rpId'])) return 'rpId is required';
87
+ if (!isNonEmptyString(options['challenge'])) return 'challenge is required';
88
+ if (!isBase64URL(options['challenge'])) return 'challenge is not valid base64url';
89
+ return validateDescriptors(options['allowCredentials'], 'allowCredentials');
90
+ }
91
+ function validateCommonResponse(value) {
92
+ if (!isRecord(value)) return 'response must be an object';
93
+ if (!isNonEmptyString(value['id'])) return 'id is missing';
94
+ if (!isNonEmptyString(value['rawId'])) return 'rawId is missing';
95
+ if (value['id'] !== value['rawId']) return 'id does not equal rawId';
96
+ if (value['type'] !== 'public-key') return "type must be 'public-key'";
97
+ if (!isRecord(value['response'])) return 'response.response is missing';
98
+ return undefined;
99
+ }
100
+ function missingFields(response, fields) {
101
+ for (const field of fields) {
102
+ if (!isNonEmptyString(response[field])) return `response.${field} is missing`;
103
+ }
104
+ return undefined;
105
+ }
106
+ function validateRegistrationResponse(value) {
107
+ const common = validateCommonResponse(value);
108
+ if (common) return common;
109
+ const response = value.response;
110
+ return missingFields(response, ['clientDataJSON', 'attestationObject']);
111
+ }
112
+ function validateAuthenticationResponse(value) {
113
+ const common = validateCommonResponse(value);
114
+ if (common) return common;
115
+ const response = value.response;
116
+ return missingFields(response, ['clientDataJSON', 'authenticatorData', 'signature']);
117
+ }
118
+ //# sourceMappingURL=validate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["BASE64URL_RE","unpaddedLength","value","end","length","isBase64URL","test","unpadded","base64URLByteLength","Math","floor","isRecord","Array","isArray","isNonEmptyString","validateDescriptors","field","undefined","index","entry","entries","validateCreationOptions","options","rp","user","challenge","excludeCredentials","pubKeyCredParams","userIdBytes","excludeReason","some","param","validateRequestOptions","validateCommonResponse","missingFields","response","fields","validateRegistrationResponse","common","validateAuthenticationResponse"],"sourceRoot":"../../src","sources":["validate.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ const CODES = new Set(['canceled', 'noCredentials', 'alreadyRegistered', 'domainNotAssociated', 'unsupported', 'invalidOptions', 'unknown']);
4
+ const TOKEN_RE = /\[Passkeys:([A-Za-z0-9-]+)\]\s?/;
5
+ const ASAUTH_RE = /^asauth-\d+$/;
6
+ function codeForToken(token) {
7
+ if (token === undefined) return 'unknown';
8
+ if (token === 'asauth-1001') return 'canceled';
9
+ if (token === 'asauth-1006') return 'alreadyRegistered';
10
+ if (ASAUTH_RE.test(token)) return 'unknown';
11
+ return CODES.has(token) ? token : 'unknown';
12
+ }
13
+ export class PasskeyError extends Error {
14
+ constructor(code, message) {
15
+ super(message);
16
+ this.name = 'PasskeyError';
17
+ this.code = code;
18
+ }
19
+
20
+ /** Normalises any thrown value into a `PasskeyError`. Never throws. */
21
+ static from(error) {
22
+ try {
23
+ if (error instanceof PasskeyError) return error;
24
+ const original = error instanceof Error ? error.message : typeof error === 'string' ? error : 'Unknown error';
25
+ const match = TOKEN_RE.exec(original);
26
+ const code = codeForToken(match?.[1]);
27
+ const stripped = match ? original.replace(TOKEN_RE, '') : original;
28
+ return new PasskeyError(code, stripped.length > 0 ? stripped : original);
29
+ } catch {
30
+ return new PasskeyError('unknown', 'Unknown error');
31
+ }
32
+ }
33
+ }
34
+ //# sourceMappingURL=PasskeyError.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["CODES","Set","TOKEN_RE","ASAUTH_RE","codeForToken","token","undefined","test","has","PasskeyError","Error","constructor","code","message","name","from","error","original","match","exec","stripped","replace","length"],"sourceRoot":"../../src","sources":["PasskeyError.ts"],"mappings":";;AASA,MAAMA,KAA0B,GAAG,IAAIC,GAAG,CAAmB,CAC3D,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,qBAAqB,EACrB,aAAa,EACb,gBAAgB,EAChB,SAAS,CACV,CAAC;AAEF,MAAMC,QAAQ,GAAG,iCAAiC;AAClD,MAAMC,SAAS,GAAG,cAAc;AAEhC,SAASC,YAAYA,CAACC,KAAyB,EAAoB;EACjE,IAAIA,KAAK,KAAKC,SAAS,EAAE,OAAO,SAAS;EACzC,IAAID,KAAK,KAAK,aAAa,EAAE,OAAO,UAAU;EAC9C,IAAIA,KAAK,KAAK,aAAa,EAAE,OAAO,mBAAmB;EACvD,IAAIF,SAAS,CAACI,IAAI,CAACF,KAAK,CAAC,EAAE,OAAO,SAAS;EAC3C,OAAOL,KAAK,CAACQ,GAAG,CAACH,KAAK,CAAC,GAAIA,KAAK,GAAwB,SAAS;AACnE;AAEA,OAAO,MAAMI,YAAY,SAASC,KAAK,CAAC;EAGtCC,WAAWA,CAACC,IAAsB,EAAEC,OAAe,EAAE;IACnD,KAAK,CAACA,OAAO,CAAC;IACd,IAAI,CAACC,IAAI,GAAG,cAAc;IAC1B,IAAI,CAACF,IAAI,GAAGA,IAAI;EAClB;;EAEA;EACA,OAAOG,IAAIA,CAACC,KAAc,EAAgB;IACxC,IAAI;MACF,IAAIA,KAAK,YAAYP,YAAY,EAAE,OAAOO,KAAK;MAC/C,MAAMC,QAAQ,GACZD,KAAK,YAAYN,KAAK,GAClBM,KAAK,CAACH,OAAO,GACb,OAAOG,KAAK,KAAK,QAAQ,GACvBA,KAAK,GACL,eAAe;MACvB,MAAME,KAAK,GAAGhB,QAAQ,CAACiB,IAAI,CAACF,QAAQ,CAAC;MACrC,MAAML,IAAI,GAAGR,YAAY,CAACc,KAAK,GAAG,CAAC,CAAC,CAAC;MACrC,MAAME,QAAQ,GAAGF,KAAK,GAAGD,QAAQ,CAACI,OAAO,CAACnB,QAAQ,EAAE,EAAE,CAAC,GAAGe,QAAQ;MAClE,OAAO,IAAIR,YAAY,CAACG,IAAI,EAAEQ,QAAQ,CAACE,MAAM,GAAG,CAAC,GAAGF,QAAQ,GAAGH,QAAQ,CAAC;IAC1E,CAAC,CAAC,MAAM;MACN,OAAO,IAAIR,YAAY,CAAC,SAAS,EAAE,eAAe,CAAC;IACrD;EACF;AACF","ignoreList":[]}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+
3
+ import { NitroModules } from 'react-native-nitro-modules';
4
+ import { PasskeyError } from './PasskeyError';
5
+ import { parseAuthenticationResponse, parseRegistrationResponse } from './response';
6
+ import { validateCreationOptions, validateRequestOptions } from './validate';
7
+
8
+ // Deliberately not exported: every caller goes through the helpers and gets typed errors.
9
+ const native = NitroModules.createHybridObject('NitroPasskeys');
10
+ export function isPasskeySupported() {
11
+ return native.isSupported;
12
+ }
13
+ export async function createPasskey(options) {
14
+ if (!isPasskeySupported()) {
15
+ throw new PasskeyError('unsupported', 'Passkeys are not supported on this device');
16
+ }
17
+ const reason = validateCreationOptions(options);
18
+ if (reason) throw new PasskeyError('invalidOptions', reason);
19
+ let raw;
20
+ try {
21
+ raw = await native.create(JSON.stringify(options));
22
+ } catch (error) {
23
+ throw PasskeyError.from(error);
24
+ }
25
+ return parseRegistrationResponse(raw);
26
+ }
27
+ export async function getPasskey(options) {
28
+ if (!isPasskeySupported()) {
29
+ throw new PasskeyError('unsupported', 'Passkeys are not supported on this device');
30
+ }
31
+ const reason = validateRequestOptions(options);
32
+ if (reason) throw new PasskeyError('invalidOptions', reason);
33
+ let raw;
34
+ try {
35
+ raw = await native.get(JSON.stringify(options));
36
+ } catch (error) {
37
+ throw PasskeyError.from(error);
38
+ }
39
+ return parseAuthenticationResponse(raw);
40
+ }
41
+ export { PasskeyError } from './PasskeyError';
42
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["NitroModules","PasskeyError","parseAuthenticationResponse","parseRegistrationResponse","validateCreationOptions","validateRequestOptions","native","createHybridObject","isPasskeySupported","isSupported","createPasskey","options","reason","raw","create","JSON","stringify","error","from","getPasskey","get"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,4BAA4B;AAEzD,SAASC,YAAY,QAAQ,gBAAgB;AAC7C,SACEC,2BAA2B,EAC3BC,yBAAyB,QACpB,YAAY;AAQnB,SAASC,uBAAuB,EAAEC,sBAAsB,QAAQ,YAAY;;AAE5E;AACA,MAAMC,MAAM,GAAGN,YAAY,CAACO,kBAAkB,CAAgB,eAAe,CAAC;AAE9E,OAAO,SAASC,kBAAkBA,CAAA,EAAY;EAC5C,OAAOF,MAAM,CAACG,WAAW;AAC3B;AAEA,OAAO,eAAeC,aAAaA,CACjCC,OAA+C,EACZ;EACnC,IAAI,CAACH,kBAAkB,CAAC,CAAC,EAAE;IACzB,MAAM,IAAIP,YAAY,CACpB,aAAa,EACb,2CACF,CAAC;EACH;EACA,MAAMW,MAAM,GAAGR,uBAAuB,CAACO,OAAO,CAAC;EAC/C,IAAIC,MAAM,EAAE,MAAM,IAAIX,YAAY,CAAC,gBAAgB,EAAEW,MAAM,CAAC;EAC5D,IAAIC,GAAW;EACf,IAAI;IACFA,GAAG,GAAG,MAAMP,MAAM,CAACQ,MAAM,CAACC,IAAI,CAACC,SAAS,CAACL,OAAO,CAAC,CAAC;EACpD,CAAC,CAAC,OAAOM,KAAK,EAAE;IACd,MAAMhB,YAAY,CAACiB,IAAI,CAACD,KAAK,CAAC;EAChC;EACA,OAAOd,yBAAyB,CAACU,GAAG,CAAC;AACvC;AAEA,OAAO,eAAeM,UAAUA,CAC9BR,OAA8C,EACT;EACrC,IAAI,CAACH,kBAAkB,CAAC,CAAC,EAAE;IACzB,MAAM,IAAIP,YAAY,CACpB,aAAa,EACb,2CACF,CAAC;EACH;EACA,MAAMW,MAAM,GAAGP,sBAAsB,CAACM,OAAO,CAAC;EAC9C,IAAIC,MAAM,EAAE,MAAM,IAAIX,YAAY,CAAC,gBAAgB,EAAEW,MAAM,CAAC;EAC5D,IAAIC,GAAW;EACf,IAAI;IACFA,GAAG,GAAG,MAAMP,MAAM,CAACc,GAAG,CAACL,IAAI,CAACC,SAAS,CAACL,OAAO,CAAC,CAAC;EACjD,CAAC,CAAC,OAAOM,KAAK,EAAE;IACd,MAAMhB,YAAY,CAACiB,IAAI,CAACD,KAAK,CAAC;EAChC;EACA,OAAOf,2BAA2B,CAACW,GAAG,CAAC;AACzC;AAEA,SAASZ,YAAY,QAAQ,gBAAgB","ignoreList":[]}
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ import { PasskeyError } from './PasskeyError';
4
+ import { validateAuthenticationResponse, validateRegistrationResponse } from './validate';
5
+ function parse(raw, label, validate) {
6
+ let value;
7
+ try {
8
+ value = JSON.parse(raw);
9
+ } catch {
10
+ throw new PasskeyError('unknown', `Malformed ${label} response: not JSON`);
11
+ }
12
+ const reason = validate(value);
13
+ if (reason) throw new PasskeyError('unknown', `Malformed ${label} response: ${reason}`);
14
+ const result = value;
15
+ // The only normalisation: nothing else is added, removed or re-encoded.
16
+ result.clientExtensionResults ??= {};
17
+ return result;
18
+ }
19
+ export function parseRegistrationResponse(raw) {
20
+ return parse(raw, 'registration', validateRegistrationResponse);
21
+ }
22
+ export function parseAuthenticationResponse(raw) {
23
+ return parse(raw, 'authentication', validateAuthenticationResponse);
24
+ }
25
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["PasskeyError","validateAuthenticationResponse","validateRegistrationResponse","parse","raw","label","validate","value","JSON","reason","result","clientExtensionResults","parseRegistrationResponse","parseAuthenticationResponse"],"sourceRoot":"../../src","sources":["response.ts"],"mappings":";;AAAA,SAASA,YAAY,QAAQ,gBAAgB;AAK7C,SACEC,8BAA8B,EAC9BC,4BAA4B,QACvB,YAAY;AAEnB,SAASC,KAAKA,CACZC,GAAW,EACXC,KAAwC,EACxCC,QAAgD,EAC7C;EACH,IAAIC,KAAc;EAClB,IAAI;IACFA,KAAK,GAAGC,IAAI,CAACL,KAAK,CAACC,GAAG,CAAC;EACzB,CAAC,CAAC,MAAM;IACN,MAAM,IAAIJ,YAAY,CAAC,SAAS,EAAE,aAAaK,KAAK,qBAAqB,CAAC;EAC5E;EACA,MAAMI,MAAM,GAAGH,QAAQ,CAACC,KAAK,CAAC;EAC9B,IAAIE,MAAM,EACR,MAAM,IAAIT,YAAY,CAAC,SAAS,EAAE,aAAaK,KAAK,cAAcI,MAAM,EAAE,CAAC;EAC7E,MAAMC,MAAM,GAAGH,KAAU;EACzB;EACAG,MAAM,CAACC,sBAAsB,KAAK,CAAC,CAAC;EACpC,OAAOD,MAAM;AACf;AAEA,OAAO,SAASE,yBAAyBA,CACvCR,GAAW,EACe;EAC1B,OAAOD,KAAK,CACVC,GAAG,EACH,cAAc,EACdF,4BACF,CAAC;AACH;AAEA,OAAO,SAASW,2BAA2BA,CACzCT,GAAW,EACiB;EAC5B,OAAOD,KAAK,CACVC,GAAG,EACH,gBAAgB,EAChBH,8BACF,CAAC;AACH","ignoreList":[]}
@@ -0,0 +1,4 @@
1
+ "use strict";
2
+
3
+ export {};
4
+ //# sourceMappingURL=nitro-passkeys.nitro.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../../src","sources":["specs/nitro-passkeys.nitro.ts"],"mappings":"","ignoreList":[]}
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":[],"sourceRoot":"../../src","sources":["types.ts"],"mappings":"","ignoreList":[]}