@passlock/client 0.9.22 → 0.9.24

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