@passlock/client 0.9.21 → 0.9.23

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 (192) hide show
  1. package/README.md +125 -0
  2. package/dist/authentication/authenticate.d.ts +15 -15
  3. package/dist/authentication/authenticate.fixture.d.ts +20 -6
  4. package/dist/authentication/authenticate.fixture.js +7 -5
  5. package/dist/authentication/authenticate.fixture.js.map +1 -1
  6. package/dist/authentication/authenticate.js +19 -8
  7. package/dist/authentication/authenticate.js.map +1 -1
  8. package/dist/capabilities/capabilities.d.ts +8 -4
  9. package/dist/capabilities/capabilities.js +10 -1
  10. package/dist/capabilities/capabilities.js.map +1 -1
  11. package/dist/connection/connection.d.ts +11 -7
  12. package/dist/connection/connection.fixture.d.ts +2 -2
  13. package/dist/connection/connection.fixture.js +2 -1
  14. package/dist/connection/connection.fixture.js.map +1 -1
  15. package/dist/connection/connection.js +12 -3
  16. package/dist/connection/connection.js.map +1 -1
  17. package/dist/effect.d.ts +22 -45
  18. package/dist/effect.js +55 -51
  19. package/dist/effect.js.map +1 -1
  20. package/dist/email/email.d.ts +38 -11
  21. package/dist/email/email.fixture.d.ts +19 -5
  22. package/dist/email/email.fixture.js +4 -3
  23. package/dist/email/email.fixture.js.map +1 -1
  24. package/dist/email/email.js +43 -7
  25. package/dist/email/email.js.map +1 -1
  26. package/dist/event/event.d.ts +3 -1
  27. package/dist/event/event.js +3 -0
  28. package/dist/event/event.js.map +1 -1
  29. package/dist/index.d.ts +105 -27
  30. package/dist/index.js +101 -50
  31. package/dist/index.js.map +1 -1
  32. package/dist/logging/eventLogger.d.ts +13 -1
  33. package/dist/logging/eventLogger.js +13 -0
  34. package/dist/logging/eventLogger.js.map +1 -1
  35. package/dist/registration/register.d.ts +18 -21
  36. package/dist/registration/register.fixture.d.ts +19 -5
  37. package/dist/registration/register.fixture.js +14 -7
  38. package/dist/registration/register.fixture.js.map +1 -1
  39. package/dist/registration/register.js +18 -9
  40. package/dist/registration/register.js.map +1 -1
  41. package/dist/rpc/authentication.d.ts +0 -1
  42. package/dist/rpc/authentication.js +1 -0
  43. package/dist/rpc/authentication.js.map +1 -1
  44. package/dist/rpc/client.d.ts +4 -1
  45. package/dist/rpc/client.js +12 -2
  46. package/dist/rpc/client.js.map +1 -1
  47. package/dist/rpc/config.d.ts +0 -1
  48. package/dist/rpc/connection.d.ts +0 -1
  49. package/dist/rpc/connection.js +1 -0
  50. package/dist/rpc/connection.js.map +1 -1
  51. package/dist/rpc/registration.d.ts +0 -1
  52. package/dist/rpc/registration.js +1 -0
  53. package/dist/rpc/registration.js.map +1 -1
  54. package/dist/rpc/social.d.ts +0 -1
  55. package/dist/rpc/social.js +1 -0
  56. package/dist/rpc/social.js.map +1 -1
  57. package/dist/rpc/user.d.ts +0 -1
  58. package/dist/rpc/user.js +1 -0
  59. package/dist/rpc/user.js.map +1 -1
  60. package/dist/social/social.d.ts +16 -23
  61. package/dist/social/social.fixture.d.ts +21 -9
  62. package/dist/social/social.fixture.js +8 -14
  63. package/dist/social/social.fixture.js.map +1 -1
  64. package/dist/social/social.js +14 -10
  65. package/dist/social/social.js.map +1 -1
  66. package/dist/storage/storage.d.ts +40 -12
  67. package/dist/storage/storage.fixture.d.ts +2 -2
  68. package/dist/storage/storage.fixture.js +2 -2
  69. package/dist/storage/storage.fixture.js.map +1 -1
  70. package/dist/storage/storage.js +48 -15
  71. package/dist/storage/storage.js.map +1 -1
  72. package/dist/test/fixtures.d.ts +1 -2
  73. package/dist/test/fixtures.js +20 -5
  74. package/dist/test/fixtures.js.map +1 -1
  75. package/dist/user/user.d.ts +8 -5
  76. package/dist/user/user.fixture.d.ts +2 -2
  77. package/dist/user/user.fixture.js +9 -5
  78. package/dist/user/user.fixture.js.map +1 -1
  79. package/dist/user/user.js +9 -3
  80. package/dist/user/user.js.map +1 -1
  81. package/dist/version.d.ts +1 -2
  82. package/dist/version.js +1 -1
  83. package/dist/version.js.map +1 -1
  84. package/package.json +39 -33
  85. package/src/authentication/authenticate.fixture.ts +8 -7
  86. package/src/authentication/authenticate.test.ts +59 -17
  87. package/src/authentication/authenticate.ts +34 -32
  88. package/src/capabilities/capabilities.ts +9 -8
  89. package/src/connection/connection.fixture.ts +2 -1
  90. package/src/connection/connection.test.ts +3 -3
  91. package/src/connection/connection.ts +9 -8
  92. package/src/effect.ts +129 -128
  93. package/src/email/email.fixture.ts +4 -3
  94. package/src/email/email.test.ts +4 -4
  95. package/src/email/email.ts +24 -16
  96. package/src/index.ts +225 -169
  97. package/src/logging/eventLogger.test.ts +1 -1
  98. package/src/logging/eventLogger.ts +2 -2
  99. package/src/registration/register.fixture.ts +14 -8
  100. package/src/registration/register.test.ts +13 -9
  101. package/src/registration/register.ts +37 -34
  102. package/src/rpc/authentication.ts +31 -0
  103. package/src/rpc/client.ts +173 -0
  104. package/src/rpc/config.ts +18 -0
  105. package/src/rpc/connection.ts +24 -0
  106. package/src/rpc/registration.ts +31 -0
  107. package/src/rpc/social.ts +36 -0
  108. package/src/rpc/user.ts +42 -0
  109. package/src/social/social.fixture.ts +10 -18
  110. package/src/social/social.test.ts +13 -29
  111. package/src/social/social.ts +20 -47
  112. package/src/storage/storage.fixture.ts +3 -4
  113. package/src/storage/storage.test.ts +28 -19
  114. package/src/storage/storage.ts +36 -36
  115. package/src/test/fixtures.ts +21 -6
  116. package/src/user/user.fixture.ts +17 -7
  117. package/src/user/user.test.ts +2 -5
  118. package/src/user/user.ts +13 -9
  119. package/src/version.ts +1 -0
  120. package/dist/authentication/authenticate.d.ts.map +0 -1
  121. package/dist/authentication/authenticate.fixture.d.ts.map +0 -1
  122. package/dist/authentication/authenticate.test.d.ts +0 -2
  123. package/dist/authentication/authenticate.test.d.ts.map +0 -1
  124. package/dist/authentication/authenticate.test.js +0 -111
  125. package/dist/authentication/authenticate.test.js.map +0 -1
  126. package/dist/capabilities/capabilities.d.ts.map +0 -1
  127. package/dist/config.d.ts +0 -18
  128. package/dist/config.d.ts.map +0 -1
  129. package/dist/config.js +0 -20
  130. package/dist/config.js.map +0 -1
  131. package/dist/connection/connection.d.ts.map +0 -1
  132. package/dist/connection/connection.fixture.d.ts.map +0 -1
  133. package/dist/connection/connection.test.d.ts +0 -2
  134. package/dist/connection/connection.test.d.ts.map +0 -1
  135. package/dist/connection/connection.test.js +0 -36
  136. package/dist/connection/connection.test.js.map +0 -1
  137. package/dist/effect.d.ts.map +0 -1
  138. package/dist/email/email.d.ts.map +0 -1
  139. package/dist/email/email.fixture.d.ts.map +0 -1
  140. package/dist/email/email.test.d.ts +0 -2
  141. package/dist/email/email.test.d.ts.map +0 -1
  142. package/dist/email/email.test.js +0 -99
  143. package/dist/email/email.test.js.map +0 -1
  144. package/dist/event/event.d.ts.map +0 -1
  145. package/dist/event/event.node.test.d.ts +0 -2
  146. package/dist/event/event.node.test.d.ts.map +0 -1
  147. package/dist/event/event.node.test.js +0 -13
  148. package/dist/event/event.node.test.js.map +0 -1
  149. package/dist/event/event.test.d.ts +0 -2
  150. package/dist/event/event.test.d.ts.map +0 -1
  151. package/dist/event/event.test.js +0 -30
  152. package/dist/event/event.test.js.map +0 -1
  153. package/dist/index.d.ts.map +0 -1
  154. package/dist/logging/eventLogger.d.ts.map +0 -1
  155. package/dist/logging/eventLogger.test.d.ts +0 -2
  156. package/dist/logging/eventLogger.test.d.ts.map +0 -1
  157. package/dist/logging/eventLogger.test.js +0 -67
  158. package/dist/logging/eventLogger.test.js.map +0 -1
  159. package/dist/registration/register.d.ts.map +0 -1
  160. package/dist/registration/register.fixture.d.ts.map +0 -1
  161. package/dist/registration/register.test.d.ts +0 -2
  162. package/dist/registration/register.test.d.ts.map +0 -1
  163. package/dist/registration/register.test.js +0 -104
  164. package/dist/registration/register.test.js.map +0 -1
  165. package/dist/rpc/authentication.d.ts.map +0 -1
  166. package/dist/rpc/client.d.ts.map +0 -1
  167. package/dist/rpc/config.d.ts.map +0 -1
  168. package/dist/rpc/connection.d.ts.map +0 -1
  169. package/dist/rpc/registration.d.ts.map +0 -1
  170. package/dist/rpc/social.d.ts.map +0 -1
  171. package/dist/rpc/user.d.ts.map +0 -1
  172. package/dist/social/social.d.ts.map +0 -1
  173. package/dist/social/social.fixture.d.ts.map +0 -1
  174. package/dist/social/social.test.d.ts +0 -2
  175. package/dist/social/social.test.d.ts.map +0 -1
  176. package/dist/social/social.test.js +0 -110
  177. package/dist/social/social.test.js.map +0 -1
  178. package/dist/storage/storage.d.ts.map +0 -1
  179. package/dist/storage/storage.fixture.d.ts.map +0 -1
  180. package/dist/storage/storage.test.d.ts +0 -2
  181. package/dist/storage/storage.test.d.ts.map +0 -1
  182. package/dist/storage/storage.test.js +0 -120
  183. package/dist/storage/storage.test.js.map +0 -1
  184. package/dist/test/fixtures.d.ts.map +0 -1
  185. package/dist/user/user.d.ts.map +0 -1
  186. package/dist/user/user.fixture.d.ts.map +0 -1
  187. package/dist/user/user.test.d.ts +0 -2
  188. package/dist/user/user.test.d.ts.map +0 -1
  189. package/dist/user/user.test.js +0 -56
  190. package/dist/user/user.test.js.map +0 -1
  191. package/dist/version.d.ts.map +0 -1
  192. package/src/config.ts +0 -42
package/src/index.ts CHANGED
@@ -9,38 +9,130 @@ import type {
9
9
  } from '@passlock/shared/dist/error/error.js'
10
10
 
11
11
  import { ErrorCode } from '@passlock/shared/dist/error/error.js'
12
- import { RpcConfig } from '@passlock/shared/dist/rpc/config.js'
13
- import type { Principal } from '@passlock/shared/dist/schema/principal.js'
14
- import { Effect as E, Layer as L, Layer, Option, Runtime, Scope, pipe } from 'effect'
15
- import { AuthenticationService, type AuthenticationRequest } from './authentication/authenticate.js'
16
- import { Capabilities } from './capabilities/capabilities.js'
17
- import { ConnectionService } from './connection/connection.js'
18
- import { allRequirements } from './effect.js'
19
- import { EmailService, type VerifyRequest } from './email/email.js'
20
- import { RegistrationService, type RegistrationRequest } from './registration/register.js'
21
- import { SocialService, type AuthenticateOidcReq, type RegisterOidcReq } from './social/social.js'
22
- import { Storage, StorageService, type AuthType, type StoredToken } from './storage/storage.js'
23
- import { UserService, type Email, type ResendEmail } from './user/user.js'
12
+ import type { VerifyEmail } from '@passlock/shared/dist/schema/email.js'
13
+ import type { UserVerification } from '@passlock/shared/dist/schema/passkey.js'
14
+ import type { Principal, UserPrincipal } from '@passlock/shared/dist/schema/principal.js'
15
+ import { RpcConfig } from './rpc/config.js'
16
+
17
+ import { Effect as E, Layer as L, Layer, Option as O, Runtime, Scope, pipe } from 'effect'
18
+
19
+ import type { AuthenticationService } from './authentication/authenticate.js'
20
+ import type { Capabilities } from './capabilities/capabilities.js'
21
+ import type { ConnectionService } from './connection/connection.js'
22
+
23
+ import { dual } from 'effect/Function'
24
+ import {
25
+ allRequirements,
26
+ authenticateOidc,
27
+ authenticatePasskey,
28
+ clearExpiredTokens,
29
+ getSessionToken,
30
+ isExistingUser,
31
+ isPasskeySupport,
32
+ preConnect,
33
+ registerOidc,
34
+ registerPasskey,
35
+ resendVerificationEmail,
36
+ verifyEmailCode,
37
+ verifyEmailLink,
38
+ } from './effect.js'
39
+ import type { EmailService, VerifyRequest } from './email/email.js'
40
+ import type { RegistrationService } from './registration/register.js'
41
+ import type { Provider, SocialService } from './social/social.js'
42
+ import {
43
+ type AuthType,
44
+ BrowserStorage,
45
+ StorageService,
46
+ type StoredToken,
47
+ } from './storage/storage.js'
48
+ import type { Email, ResendEmail, UserService } from './user/user.js'
49
+ import { PASSLOCK_CLIENT_VERSION } from './version.js'
24
50
 
25
51
  /* Exports */
26
52
 
27
53
  export type Options = { signal?: AbortSignal }
28
54
  export type { VerifyEmail } from '@passlock/shared/dist/schema/email.js'
29
55
  export type { UserVerification } from '@passlock/shared/dist/schema/passkey.js'
30
- export type { Principal } from '@passlock/shared/dist/schema/principal.js'
56
+ export type { Principal, UserPrincipal } from '@passlock/shared/dist/schema/principal.js'
31
57
 
32
- export type { AuthenticationRequest } from './authentication/authenticate.js'
33
58
  export type { VerifyRequest } from './email/email.js'
34
- export type { RegistrationRequest } from './registration/register.js'
35
59
  export type { AuthType, StoredToken } from './storage/storage.js'
36
60
  export type { Email } from './user/user.js'
37
61
 
38
62
  export type PasslockProps = {
39
- tenancyId: string;
40
- clientId: string;
63
+ tenancyId: string
64
+ clientId: string
41
65
  endpoint?: string
42
66
  }
43
67
 
68
+ export type RegistrationRequest = {
69
+ email: string
70
+ givenName?: string
71
+ familyName?: string
72
+ userVerification?: UserVerification
73
+ verifyEmail?: VerifyEmail
74
+ }
75
+
76
+ const nonEmpty = (text: string): O.Option<string> => {
77
+ const trimmed = text.trim()
78
+ if (trimmed.length > 0) return O.some(trimmed)
79
+ return O.none()
80
+ }
81
+
82
+ const toRpcRegistrationRequest = (request: RegistrationRequest) => {
83
+ return {
84
+ email: request.email,
85
+ givenName: pipe(O.fromNullable(request.givenName), O.flatMap(nonEmpty)),
86
+ familyName: pipe(O.fromNullable(request.familyName), O.flatMap(nonEmpty)),
87
+ userVerification: O.fromNullable(request.userVerification),
88
+ verifyEmail: O.fromNullable(request.verifyEmail),
89
+ }
90
+ }
91
+
92
+ export type AuthenticationRequest = {
93
+ email?: string
94
+ userVerification?: UserVerification
95
+ }
96
+
97
+ const toRpcAuthenticationRequest = (request: AuthenticationRequest) => {
98
+ return {
99
+ email: O.fromNullable(request.email),
100
+ userVerification: O.fromNullable(request.userVerification),
101
+ }
102
+ }
103
+
104
+ export type RegisterOidcReq = {
105
+ provider: Provider
106
+ idToken: string
107
+ givenName?: string
108
+ familyName?: string
109
+ nonce: string
110
+ }
111
+
112
+ const toRpcRegisterOidcReq = (request: RegisterOidcReq) => {
113
+ return {
114
+ provider: request.provider,
115
+ idToken: request.idToken,
116
+ givenName: pipe(O.fromNullable(request.givenName), O.flatMap(nonEmpty)),
117
+ familyName: pipe(O.fromNullable(request.familyName), O.flatMap(nonEmpty)),
118
+ nonce: request.nonce,
119
+ }
120
+ }
121
+
122
+ export type AuthenticateOidcReq = {
123
+ provider: Provider
124
+ idToken: string
125
+ nonce: string
126
+ }
127
+
128
+ const toRpcAuthenticateOidcReq = (request: AuthenticateOidcReq) => {
129
+ return {
130
+ provider: request.provider,
131
+ idToken: request.idToken,
132
+ nonce: request.nonce,
133
+ }
134
+ }
135
+
44
136
  export { ErrorCode } from '@passlock/shared/dist/error/error.js'
45
137
 
46
138
  export class PasslockError extends Error {
@@ -54,11 +146,7 @@ export class PasslockError extends Error {
54
146
  }
55
147
 
56
148
  static readonly isError = (error: unknown): error is PasslockError => {
57
- return (
58
- typeof error === 'object' &&
59
- error !== null &&
60
- error instanceof PasslockError
61
- )
149
+ return typeof error === 'object' && error !== null && error instanceof PasslockError
62
150
  }
63
151
  }
64
152
 
@@ -105,11 +193,13 @@ const transformErrors = <A, R>(
105
193
  },
106
194
 
107
195
  Interrupt: () => {
196
+ console.error("Interrupt")
108
197
  return E.succeed(new PasslockError('Operation aborted', ErrorCode.InternalBrowserError))
109
198
  },
110
199
 
111
200
  Sequential: errors => {
112
201
  console.error(errors)
202
+
113
203
  return E.succeed(
114
204
  new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError),
115
205
  )
@@ -117,6 +207,7 @@ const transformErrors = <A, R>(
117
207
 
118
208
  Parallel: errors => {
119
209
  console.error(errors)
210
+
120
211
  return E.succeed(
121
212
  new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError),
122
213
  )
@@ -135,218 +226,183 @@ type Requirements =
135
226
  | StorageService
136
227
  | Capabilities
137
228
  | SocialService
229
+ | RpcConfig
138
230
 
139
231
  export class PasslockUnsafe {
140
232
  private readonly runtime: Runtime.Runtime<Requirements>
141
233
 
142
- constructor(config: PasslockProps) {
143
- const rpcConfig = Layer.succeed(RpcConfig, RpcConfig.of(config))
144
- const storage = Layer.succeed(Storage, Storage.of(globalThis.localStorage))
145
- const allLayers = pipe(allRequirements, L.provide(rpcConfig), L.provide(storage))
234
+ constructor(props: PasslockProps) {
235
+ const config = Layer.succeed(RpcConfig, RpcConfig.of(props))
236
+ const storage = Layer.succeed(BrowserStorage, BrowserStorage.of(globalThis.localStorage))
237
+ const allLayers = pipe(allRequirements, L.provide(config), L.provide(storage), L.merge(config))
146
238
  const scope = E.runSync(Scope.make())
239
+
147
240
  this.runtime = E.runSync(Layer.toRuntime(allLayers).pipe(Scope.extend(scope)))
241
+
242
+ E.runSync(E.logDebug(`Passlock version: ${PASSLOCK_CLIENT_VERSION}`))
148
243
  }
149
244
 
150
- private readonly runPromise = <A, R extends Requirements>(
151
- effect: E.Effect<A, PasslockErrors, R>,
152
- options: Options | undefined = undefined
153
- ) => {
154
- return pipe(
155
- transformErrors(effect),
156
- E.flatMap(result => (PasslockError.isError(result) ? E.fail(result) : E.succeed(result))),
157
- effect => Runtime.runPromise(this.runtime)(effect, options),
245
+ static isUserPrincipal = (principal: Principal): principal is UserPrincipal => {
246
+ return (
247
+ principal.givenName !== undefined &&
248
+ principal.familyName !== undefined &&
249
+ principal.email !== undefined &&
250
+ principal.emailVerified !== undefined
158
251
  )
159
252
  }
160
253
 
161
- preConnect = (options?: Options): Promise<void> =>
162
- pipe(
163
- ConnectionService,
164
- E.flatMap(service => service.preConnect()),
165
- effect => Runtime.runPromise(this.runtime)(effect, options),
254
+ private readonly runPromise: {
255
+ <A, R extends Requirements>(options: Options | undefined): (effect: E.Effect<A, PasslockErrors, R>) => Promise<A>
256
+ <A, R extends Requirements>(effect: E.Effect<A, PasslockErrors, R>, options: Options | undefined): Promise<A>
257
+ } = dual(
258
+ 2,
259
+ <A, R extends Requirements>(effect: E.Effect<A, PasslockErrors, R>, options: Options | undefined): Promise<A> => pipe(
260
+ transformErrors(effect),
261
+ E.flatMap(result => (PasslockError.isError(result) ? E.fail(result) : E.succeed(result))),
262
+ effect => Runtime.runPromise(this.runtime)(effect, options)
166
263
  )
264
+ )
265
+
266
+ preConnect = (options?: Options): Promise<void> => pipe(preConnect(), this.runPromise(options))
167
267
 
168
268
  isPasskeySupport = (): Promise<boolean> =>
169
- pipe(
170
- Capabilities,
171
- E.flatMap(service => service.isPasskeySupport),
172
- effect => Runtime.runPromise(this.runtime)(effect),
173
- )
269
+ pipe(isPasskeySupport, effect => Runtime.runPromise(this.runtime)(effect))
174
270
 
175
271
  isExistingUser = (email: Email, options?: Options): Promise<boolean> =>
176
- pipe(
177
- UserService,
178
- E.flatMap(service => service.isExistingUser(email)),
179
- effect => this.runPromise(effect, options),
180
- )
272
+ pipe(isExistingUser(email), this.runPromise(options))
181
273
 
182
274
  registerPasskey = (request: RegistrationRequest, options?: Options): Promise<Principal> =>
183
- pipe(
184
- RegistrationService,
185
- E.flatMap(service => service.registerPasskey(request)),
186
- effect => this.runPromise(effect, options),
187
- )
275
+ pipe(registerPasskey(toRpcRegistrationRequest(request)), this.runPromise(options))
188
276
 
189
277
  authenticatePasskey = (request: AuthenticationRequest, options?: Options): Promise<Principal> =>
190
- pipe(
191
- AuthenticationService,
192
- E.flatMap(service => service.authenticatePasskey(request)),
193
- effect => this.runPromise(effect, options),
194
- )
278
+ pipe(authenticatePasskey(toRpcAuthenticationRequest(request)), this.runPromise(options))
195
279
 
196
- registerOidc = (request: RegisterOidcReq, options?: Options) =>
197
- pipe(
198
- SocialService,
199
- E.flatMap(service => service.registerOidc(request)),
200
- effect => this.runPromise(effect, options),
201
- )
202
-
203
- authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
204
- pipe(
205
- SocialService,
206
- E.flatMap(service => service.authenticateOidc(request)),
207
- effect => this.runPromise(effect, options),
208
- )
280
+ registerOidc = (request: RegisterOidcReq, options?: Options) =>
281
+ pipe(registerOidc(toRpcRegisterOidcReq(request)), this.runPromise(options))
282
+
283
+ authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
284
+ pipe(authenticateOidc(toRpcAuthenticateOidcReq(request)), this.runPromise(options))
209
285
 
210
286
  verifyEmailCode = (request: VerifyRequest, options?: Options): Promise<Principal> =>
211
- pipe(
212
- EmailService,
213
- E.flatMap(service => service.verifyEmailCode(request)),
214
- effect => this.runPromise(effect, options),
215
- )
287
+ pipe(verifyEmailCode(request), this.runPromise(options))
216
288
 
217
289
  resendVerificationEmail = (request: ResendEmail, options?: Options): Promise<void> =>
218
- pipe(
219
- UserService,
220
- E.flatMap(service => service.resendVerificationEmail(request)),
221
- effect => this.runPromise(effect, options),
222
- )
290
+ pipe(resendVerificationEmail(request), this.runPromise(options))
223
291
 
224
292
  verifyEmailLink = (options?: Options): Promise<Principal> =>
225
- pipe(
226
- EmailService,
227
- E.flatMap(service => service.verifyEmailLink()),
228
- effect => this.runPromise(effect, options),
229
- )
293
+ pipe(verifyEmailLink, this.runPromise(options))
230
294
 
231
295
  getSessionToken = (authType: AuthType): StoredToken | undefined =>
232
296
  pipe(
233
- StorageService,
234
- E.flatMap(service => service.getToken(authType).pipe(effect => E.option(effect))),
235
- E.map(Option.getOrUndefined),
297
+ getSessionToken(authType),
298
+ E.orElseSucceed(() => undefined),
236
299
  effect => Runtime.runSync(this.runtime)(effect),
237
300
  )
238
301
 
239
- clearExpiredTokens = (): void =>
240
- pipe(
241
- StorageService,
242
- E.flatMap(service => service.clearExpiredTokens),
243
- effect => Runtime.runSync(this.runtime)(effect),
244
- )
302
+ clearExpiredTokens = (): void => {
303
+ pipe(clearExpiredTokens, effect => {
304
+ Runtime.runSync(this.runtime)(effect)
305
+ })
306
+ }
245
307
  }
246
308
 
247
309
  export class Passlock {
248
310
  private readonly runtime: Runtime.Runtime<Requirements>
249
311
 
250
- constructor(config: PasslockProps) {
251
- const rpcConfig = Layer.succeed(RpcConfig, RpcConfig.of(config))
252
- const storage = Layer.succeed(Storage, Storage.of(globalThis.localStorage))
253
- const allLayers = pipe(allRequirements, L.provide(rpcConfig), L.provide(storage))
312
+ constructor(props: PasslockProps) {
313
+ const config = Layer.succeed(RpcConfig, RpcConfig.of(props))
314
+ const storage = Layer.succeed(BrowserStorage, BrowserStorage.of(globalThis.localStorage))
315
+ const allLayers = pipe(allRequirements, L.provide(config), L.provide(storage), L.merge(config))
254
316
  const scope = E.runSync(Scope.make())
317
+
255
318
  this.runtime = E.runSync(Layer.toRuntime(allLayers).pipe(Scope.extend(scope)))
319
+
320
+ E.runSync(E.logDebug(`Passlock version: ${PASSLOCK_CLIENT_VERSION}`))
256
321
  }
257
322
 
258
- private readonly runPromise = <A, R extends Requirements>(
259
- effect: E.Effect<A, PasslockErrors, R>,
260
- options: Options | undefined = undefined
261
- ) => {
262
- return pipe(
323
+ static isUserPrincipal = (principal: Principal): principal is UserPrincipal => {
324
+ return (
325
+ principal.givenName !== undefined &&
326
+ principal.familyName !== undefined &&
327
+ principal.email !== undefined &&
328
+ principal.emailVerified !== undefined
329
+ )
330
+ }
331
+
332
+ private readonly runPromise: {
333
+ <A, R extends Requirements>(options: Options | undefined): (effect: E.Effect<A, PasslockErrors, R>) => Promise<A | PasslockError>
334
+ <A, R extends Requirements>(effect: E.Effect<A, PasslockErrors, R>, options: Options | undefined): Promise<A | PasslockError>
335
+ } = dual(
336
+ 2,
337
+ <A, R extends Requirements>(effect: E.Effect<A, PasslockErrors, R>, options: Options | undefined): Promise<A | PasslockError> => pipe(
263
338
  transformErrors(effect),
264
339
  effect => Runtime.runPromise(this.runtime)(effect, options)
265
340
  )
266
- }
341
+ )
267
342
 
268
- preConnect = (options?: Options): Promise<void | PasslockError> =>
269
- pipe(
270
- ConnectionService,
271
- E.flatMap(service => service.preConnect()),
272
- effect => this.runPromise(effect, options),
343
+ preConnect = async (options?: Options): Promise<boolean | PasslockError> => {
344
+ return pipe(
345
+ preConnect(),
346
+ E.as(true),
347
+ this.runPromise(options)
273
348
  )
349
+ }
274
350
 
275
351
  isPasskeySupport = (): Promise<boolean> =>
276
- pipe(
277
- Capabilities,
278
- E.flatMap(service => service.isPasskeySupport),
279
- effect => Runtime.runPromise(this.runtime)(effect),
280
- )
352
+ pipe(isPasskeySupport, effect => Runtime.runPromise(this.runtime)(effect))
281
353
 
282
354
  isExistingUser = (email: Email, options?: Options): Promise<boolean | PasslockError> =>
283
- pipe(
284
- UserService,
285
- E.flatMap(service => service.isExistingUser(email)),
286
- effect => this.runPromise(effect, options),
287
- )
288
-
289
- registerPasskey = (request: RegistrationRequest, options?: Options): Promise<Principal | PasslockError> =>
290
- pipe(
291
- RegistrationService,
292
- E.flatMap(service => service.registerPasskey(request)),
293
- effect => this.runPromise(effect, options),
294
- )
295
-
296
- authenticatePasskey = (request: AuthenticationRequest = {}, options?: Options): Promise<Principal | PasslockError> =>
297
- pipe(
298
- AuthenticationService,
299
- E.flatMap(service => service.authenticatePasskey(request)),
300
- effect => this.runPromise(effect, options),
355
+ pipe(isExistingUser(email), this.runPromise(options))
356
+
357
+ registerPasskey = (
358
+ request: RegistrationRequest,
359
+ options?: Options,
360
+ ): Promise<Principal | PasslockError> =>
361
+ pipe(registerPasskey(toRpcRegistrationRequest(request)), this.runPromise(options))
362
+
363
+ authenticatePasskey = (
364
+ request: AuthenticationRequest = {},
365
+ options?: Options,
366
+ ): Promise<Principal | PasslockError> => pipe(
367
+ toRpcAuthenticationRequest(request),
368
+ authenticatePasskey,
369
+ this.runPromise(options)
301
370
  )
302
371
 
303
372
  registerOidc = (request: RegisterOidcReq, options?: Options) =>
304
- pipe(
305
- SocialService,
306
- E.flatMap(service => service.registerOidc(request)),
307
- effect => this.runPromise(effect, options),
308
- )
373
+ pipe(registerOidc(toRpcRegisterOidcReq(request)), this.runPromise(options))
309
374
 
310
- authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
311
- pipe(
312
- SocialService,
313
- E.flatMap(service => service.authenticateOidc(request)),
314
- effect => this.runPromise(effect, options),
315
- )
375
+ authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
376
+ pipe(authenticateOidc(request), this.runPromise(options))
316
377
 
317
- verifyEmailCode = (request: VerifyRequest, options?: Options): Promise<Principal | PasslockError> =>
318
- pipe(
319
- EmailService,
320
- E.flatMap(service => service.verifyEmailCode(request)),
321
- effect => this.runPromise(effect, options),
322
- )
378
+ verifyEmailCode = (
379
+ request: VerifyRequest,
380
+ options?: Options,
381
+ ): Promise<Principal | PasslockError> => pipe(verifyEmailCode(request), this.runPromise(options))
323
382
 
324
383
  verifyEmailLink = (options?: Options): Promise<Principal | PasslockError> =>
325
- pipe(
326
- EmailService,
327
- E.flatMap(service => service.verifyEmailLink()),
328
- effect => this.runPromise(effect, options),
329
- )
384
+ pipe(verifyEmailLink, this.runPromise(options))
330
385
 
331
- resendVerificationEmail = (request: ResendEmail, options?: Options): Promise<void | PasslockError> =>
332
- pipe(
333
- UserService,
334
- E.flatMap(service => service.resendVerificationEmail(request)),
335
- effect => this.runPromise(effect, options),
336
- )
386
+ resendVerificationEmail = (
387
+ request: ResendEmail,
388
+ options?: Options,
389
+ ): Promise<boolean | PasslockError> =>
390
+ pipe(resendVerificationEmail(request), E.as(true), this.runPromise(options))
337
391
 
338
- getSessionToken = (authType: AuthType): StoredToken | undefined =>
392
+ getSessionToken = (authType: AuthType): Promise<StoredToken | undefined> =>
339
393
  pipe(
340
- StorageService,
341
- E.flatMap(service => service.getToken(authType).pipe(effect => E.option(effect))),
342
- E.map(maybeToken => Option.getOrUndefined(maybeToken)),
343
- effect => Runtime.runSync(this.runtime)(effect),
394
+ getSessionToken(authType),
395
+ E.orElseSucceed(() => undefined),
396
+ effect => E.runPromise(effect),
344
397
  )
345
398
 
346
- clearExpiredTokens = (): void =>
399
+ clearExpiredTokens = (): void => {
347
400
  pipe(
348
401
  StorageService,
349
402
  E.flatMap(service => service.clearExpiredTokens),
350
- effect => Runtime.runSync(this.runtime)(effect),
403
+ effect => {
404
+ Runtime.runSync(this.runtime)(effect)
405
+ },
351
406
  )
407
+ }
352
408
  }
@@ -79,7 +79,7 @@ describe('log', () => {
79
79
  const withLogLevel = logStatement.pipe(Logger.withMinimumLogLevel(LogLevel.Warning))
80
80
 
81
81
  const effect = E.provide(withLogLevel, eventLoggerLive)
82
-
82
+
83
83
  E.runSync(effect)
84
84
 
85
85
  const expectedEvent = new CustomEvent('PasslogDebugMessage', {
@@ -36,6 +36,6 @@ export const eventLoggerLive = Logger.add(
36
36
  dispatch(message)
37
37
  } else if (Array.isArray(message) && logLevel !== LogLevel.Debug) {
38
38
  message.forEach(dispatch)
39
- }
40
- })
39
+ }
40
+ }),
41
41
  )
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  OptionsReq,
3
3
  OptionsRes,
4
- RegistrationClient,
5
4
  VerificationReq,
6
5
  VerificationRes,
7
6
  } from '@passlock/shared/dist/rpc/registration.js'
8
7
  import type { RegistrationCredential } from '@passlock/shared/dist/schema/passkey.js'
9
- import { Effect as E, Layer as L } from 'effect'
8
+ import { Effect as E, Layer as L, Option as O } from 'effect'
9
+ import { RegistrationClient } from '../rpc/registration.js'
10
10
  import * as Fixtures from '../test/fixtures.js'
11
11
  import { UserService } from '../user/user.js'
12
12
  import { CreateCredential, type RegistrationRequest } from './register.js'
@@ -19,8 +19,10 @@ export const expireAt = Date.now() + 10000
19
19
 
20
20
  export const registrationRequest: RegistrationRequest = {
21
21
  email: 'jdoe@gmail.com',
22
- givenName: 'john',
23
- familyName: 'doe',
22
+ givenName: O.some('john'),
23
+ familyName: O.some('doe'),
24
+ userVerification: O.none(),
25
+ verifyEmail: O.none(),
24
26
  }
25
27
 
26
28
  export const rpcOptionsReq = new OptionsReq(registrationRequest)
@@ -56,20 +58,24 @@ export const credential: RegistrationCredential = {
56
58
  clientExtensionResults: {},
57
59
  }
58
60
 
59
- export const rpcVerificationReq = new VerificationReq({ session, credential })
61
+ export const rpcVerificationReq = new VerificationReq({
62
+ session,
63
+ credential,
64
+ verifyEmail: O.none(),
65
+ })
60
66
 
61
67
  export const rpcVerificationRes = new VerificationRes({ principal: Fixtures.principal })
62
68
 
63
69
  export const createCredentialTest = L.succeed(
64
70
  CreateCredential,
65
- CreateCredential.of(() => E.succeed(credential)),
71
+ CreateCredential.of({ createCredential: () => E.succeed(credential) }),
66
72
  )
67
73
 
68
74
  export const userServiceTest = L.succeed(
69
75
  UserService,
70
76
  UserService.of({
71
77
  isExistingUser: () => E.succeed(false),
72
- resendVerificationEmail: () => E.succeed(true)
78
+ resendVerificationEmail: () => E.succeed(true),
73
79
  }),
74
80
  )
75
81
 
@@ -78,7 +84,7 @@ export const rpcClientTest = L.succeed(
78
84
  RegistrationClient.of({
79
85
  getRegistrationOptions: () => E.succeed(rpcOptionsRes),
80
86
  verifyRegistrationCredential: () => E.succeed(rpcVerificationRes),
81
- })
87
+ }),
82
88
  )
83
89
 
84
90
  export const principal = Fixtures.principal
@@ -1,8 +1,8 @@
1
1
  import { Duplicate, InternalBrowserError } from '@passlock/shared/dist/error/error.js'
2
- import { RegistrationClient } from '@passlock/shared/dist/rpc/registration.js'
3
2
  import { Effect as E, Layer as L, Layer, LogLevel, Logger, pipe } from 'effect'
4
3
  import { describe, expect, test, vi } from 'vitest'
5
4
  import { mock } from 'vitest-mock-extended'
5
+ import { RegistrationClient } from '../rpc/registration.js'
6
6
  import * as Fixture from './register.fixture.js'
7
7
  import { CreateCredential, RegistrationService, RegistrationServiceLive } from './register.js'
8
8
 
@@ -70,7 +70,9 @@ describe('register should', () => {
70
70
  yield* _(service.registerPasskey(Fixture.registrationRequest))
71
71
 
72
72
  const rpcClient = yield* _(RegistrationClient)
73
- expect(rpcClient.verifyRegistrationCredential).toHaveBeenCalledWith(Fixture.rpcVerificationReq)
73
+ expect(rpcClient.verifyRegistrationCredential).toHaveBeenCalledWith(
74
+ Fixture.rpcVerificationReq,
75
+ )
74
76
  })
75
77
 
76
78
  const rpcClientTest = L.effect(
@@ -114,7 +116,9 @@ describe('register should', () => {
114
116
  E.sync(() => {
115
117
  const rpcMock = mock<RegistrationClient['Type']>()
116
118
 
117
- rpcMock.getRegistrationOptions.mockReturnValue(E.fail(new Duplicate({ message: 'User already exists' })))
119
+ rpcMock.getRegistrationOptions.mockReturnValue(
120
+ E.fail(new Duplicate({ message: 'User already exists' })),
121
+ )
118
122
 
119
123
  return rpcMock
120
124
  }),
@@ -147,11 +151,11 @@ describe('register should', () => {
147
151
  const createTest = L.effect(
148
152
  CreateCredential,
149
153
  E.sync(() => {
150
- const createTest = vi.fn()
154
+ const createCredential = vi.fn()
151
155
 
152
- createTest.mockReturnValue(E.fail(new Duplicate({ message: 'boom!' })))
156
+ createCredential.mockReturnValue(E.fail(new Duplicate({ message: 'boom!' })))
153
157
 
154
- return createTest
158
+ return { createCredential }
155
159
  }),
156
160
  )
157
161
 
@@ -185,11 +189,11 @@ describe('register should', () => {
185
189
  const createTest = L.effect(
186
190
  CreateCredential,
187
191
  E.sync(() => {
188
- const createTest = vi.fn()
192
+ const createCredential = vi.fn()
189
193
 
190
- createTest.mockReturnValue(E.fail(new InternalBrowserError({ message: 'boom!' })))
194
+ createCredential.mockReturnValue(E.fail(new InternalBrowserError({ message: 'boom!' })))
191
195
 
192
- return createTest
196
+ return { createCredential }
193
197
  }),
194
198
  )
195
199