@passlock/client 0.9.22 → 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 (151) hide show
  1. package/dist/authentication/authenticate.d.ts +15 -15
  2. package/dist/authentication/authenticate.fixture.d.ts +20 -6
  3. package/dist/authentication/authenticate.fixture.js +7 -5
  4. package/dist/authentication/authenticate.fixture.js.map +1 -1
  5. package/dist/authentication/authenticate.js +19 -8
  6. package/dist/authentication/authenticate.js.map +1 -1
  7. package/dist/capabilities/capabilities.d.ts +8 -4
  8. package/dist/capabilities/capabilities.js +10 -1
  9. package/dist/capabilities/capabilities.js.map +1 -1
  10. package/dist/connection/connection.d.ts +11 -7
  11. package/dist/connection/connection.fixture.d.ts +2 -2
  12. package/dist/connection/connection.fixture.js +2 -1
  13. package/dist/connection/connection.fixture.js.map +1 -1
  14. package/dist/connection/connection.js +12 -3
  15. package/dist/connection/connection.js.map +1 -1
  16. package/dist/effect.d.ts +22 -45
  17. package/dist/effect.js +55 -51
  18. package/dist/effect.js.map +1 -1
  19. package/dist/email/email.d.ts +38 -11
  20. package/dist/email/email.fixture.d.ts +19 -5
  21. package/dist/email/email.fixture.js +4 -3
  22. package/dist/email/email.fixture.js.map +1 -1
  23. package/dist/email/email.js +43 -7
  24. package/dist/email/email.js.map +1 -1
  25. package/dist/event/event.d.ts +3 -1
  26. package/dist/event/event.js +3 -0
  27. package/dist/event/event.js.map +1 -1
  28. package/dist/index.d.ts +105 -27
  29. package/dist/index.js +101 -50
  30. package/dist/index.js.map +1 -1
  31. package/dist/logging/eventLogger.d.ts +13 -1
  32. package/dist/logging/eventLogger.js +13 -0
  33. package/dist/logging/eventLogger.js.map +1 -1
  34. package/dist/registration/register.d.ts +18 -21
  35. package/dist/registration/register.fixture.d.ts +19 -5
  36. package/dist/registration/register.fixture.js +14 -7
  37. package/dist/registration/register.fixture.js.map +1 -1
  38. package/dist/registration/register.js +18 -9
  39. package/dist/registration/register.js.map +1 -1
  40. package/dist/rpc/authentication.d.ts +0 -1
  41. package/dist/rpc/authentication.js +1 -0
  42. package/dist/rpc/authentication.js.map +1 -1
  43. package/dist/rpc/client.d.ts +4 -1
  44. package/dist/rpc/client.js +12 -2
  45. package/dist/rpc/client.js.map +1 -1
  46. package/dist/rpc/config.d.ts +0 -1
  47. package/dist/rpc/connection.d.ts +0 -1
  48. package/dist/rpc/connection.js +1 -0
  49. package/dist/rpc/connection.js.map +1 -1
  50. package/dist/rpc/registration.d.ts +0 -1
  51. package/dist/rpc/registration.js +1 -0
  52. package/dist/rpc/registration.js.map +1 -1
  53. package/dist/rpc/social.d.ts +0 -1
  54. package/dist/rpc/social.js +1 -0
  55. package/dist/rpc/social.js.map +1 -1
  56. package/dist/rpc/user.d.ts +0 -1
  57. package/dist/rpc/user.js +1 -0
  58. package/dist/rpc/user.js.map +1 -1
  59. package/dist/social/social.d.ts +16 -23
  60. package/dist/social/social.fixture.d.ts +21 -9
  61. package/dist/social/social.fixture.js +8 -14
  62. package/dist/social/social.fixture.js.map +1 -1
  63. package/dist/social/social.js +14 -10
  64. package/dist/social/social.js.map +1 -1
  65. package/dist/storage/storage.d.ts +40 -12
  66. package/dist/storage/storage.fixture.d.ts +2 -2
  67. package/dist/storage/storage.fixture.js +2 -2
  68. package/dist/storage/storage.fixture.js.map +1 -1
  69. package/dist/storage/storage.js +48 -15
  70. package/dist/storage/storage.js.map +1 -1
  71. package/dist/test/fixtures.d.ts +1 -2
  72. package/dist/test/fixtures.js +20 -5
  73. package/dist/test/fixtures.js.map +1 -1
  74. package/dist/user/user.d.ts +8 -5
  75. package/dist/user/user.fixture.d.ts +2 -2
  76. package/dist/user/user.fixture.js +9 -5
  77. package/dist/user/user.fixture.js.map +1 -1
  78. package/dist/user/user.js +9 -3
  79. package/dist/user/user.js.map +1 -1
  80. package/dist/version.d.ts +1 -2
  81. package/dist/version.js +1 -1
  82. package/dist/version.js.map +1 -1
  83. package/package.json +30 -26
  84. package/src/authentication/authenticate.fixture.ts +8 -7
  85. package/src/authentication/authenticate.test.ts +59 -17
  86. package/src/authentication/authenticate.ts +34 -32
  87. package/src/capabilities/capabilities.ts +9 -8
  88. package/src/connection/connection.fixture.ts +2 -1
  89. package/src/connection/connection.test.ts +3 -3
  90. package/src/connection/connection.ts +9 -8
  91. package/src/effect.ts +129 -128
  92. package/src/email/email.fixture.ts +4 -3
  93. package/src/email/email.test.ts +4 -4
  94. package/src/email/email.ts +24 -16
  95. package/src/index.ts +225 -169
  96. package/src/logging/eventLogger.test.ts +1 -1
  97. package/src/logging/eventLogger.ts +2 -2
  98. package/src/registration/register.fixture.ts +14 -8
  99. package/src/registration/register.test.ts +13 -9
  100. package/src/registration/register.ts +37 -34
  101. package/src/rpc/authentication.ts +31 -0
  102. package/src/rpc/client.ts +173 -0
  103. package/src/rpc/config.ts +18 -0
  104. package/src/rpc/connection.ts +24 -0
  105. package/src/rpc/registration.ts +31 -0
  106. package/src/rpc/social.ts +36 -0
  107. package/src/rpc/user.ts +42 -0
  108. package/src/social/social.fixture.ts +10 -18
  109. package/src/social/social.test.ts +13 -29
  110. package/src/social/social.ts +20 -47
  111. package/src/storage/storage.fixture.ts +3 -4
  112. package/src/storage/storage.test.ts +28 -19
  113. package/src/storage/storage.ts +36 -36
  114. package/src/test/fixtures.ts +21 -6
  115. package/src/user/user.fixture.ts +17 -7
  116. package/src/user/user.test.ts +2 -5
  117. package/src/user/user.ts +13 -9
  118. package/src/version.ts +1 -0
  119. package/dist/authentication/authenticate.d.ts.map +0 -1
  120. package/dist/authentication/authenticate.fixture.d.ts.map +0 -1
  121. package/dist/capabilities/capabilities.d.ts.map +0 -1
  122. package/dist/config.d.ts +0 -18
  123. package/dist/config.d.ts.map +0 -1
  124. package/dist/config.js +0 -20
  125. package/dist/config.js.map +0 -1
  126. package/dist/connection/connection.d.ts.map +0 -1
  127. package/dist/connection/connection.fixture.d.ts.map +0 -1
  128. package/dist/effect.d.ts.map +0 -1
  129. package/dist/email/email.d.ts.map +0 -1
  130. package/dist/email/email.fixture.d.ts.map +0 -1
  131. package/dist/event/event.d.ts.map +0 -1
  132. package/dist/index.d.ts.map +0 -1
  133. package/dist/logging/eventLogger.d.ts.map +0 -1
  134. package/dist/registration/register.d.ts.map +0 -1
  135. package/dist/registration/register.fixture.d.ts.map +0 -1
  136. package/dist/rpc/authentication.d.ts.map +0 -1
  137. package/dist/rpc/client.d.ts.map +0 -1
  138. package/dist/rpc/config.d.ts.map +0 -1
  139. package/dist/rpc/connection.d.ts.map +0 -1
  140. package/dist/rpc/registration.d.ts.map +0 -1
  141. package/dist/rpc/social.d.ts.map +0 -1
  142. package/dist/rpc/user.d.ts.map +0 -1
  143. package/dist/social/social.d.ts.map +0 -1
  144. package/dist/social/social.fixture.d.ts.map +0 -1
  145. package/dist/storage/storage.d.ts.map +0 -1
  146. package/dist/storage/storage.fixture.d.ts.map +0 -1
  147. package/dist/test/fixtures.d.ts.map +0 -1
  148. package/dist/user/user.d.ts.map +0 -1
  149. package/dist/user/user.fixture.d.ts.map +0 -1
  150. package/dist/version.d.ts.map +0 -1
  151. package/src/config.ts +0 -42
@@ -1,9 +1,9 @@
1
- import { RpcConfig } from '@passlock/shared/dist/rpc/config.js'
2
- import { ConnectionClient } from '@passlock/shared/dist/rpc/connection.js'
3
- import { Dispatcher } from '@passlock/shared/dist/rpc/dispatcher.js'
4
1
  import { Effect as E, Layer as L, Layer, LogLevel, Logger, pipe } from 'effect'
5
2
  import { describe, expect, test } from 'vitest'
6
3
  import { mock } from 'vitest-mock-extended'
4
+ import { Dispatcher } from '../rpc/client.js'
5
+ import { RpcConfig } from '../rpc/config.js'
6
+ import { ConnectionClient } from '../rpc/connection.js'
7
7
  import * as Fixture from './connection.fixture.js'
8
8
  import { ConnectionService, ConnectionServiceLive } from './connection.js'
9
9
 
@@ -1,18 +1,19 @@
1
1
  /**
2
2
  * Hits the rpc endpoint to warm up a lambda
3
3
  */
4
- import type { RpcConfig } from '@passlock/shared/dist/rpc/config.js'
5
- import { ConnectionClient } from '@passlock/shared/dist/rpc/connection.js'
6
- import { Dispatcher } from '@passlock/shared/dist/rpc/dispatcher.js'
7
4
  import { Context, Effect as E, Layer, flow, pipe } from 'effect'
5
+ import { Dispatcher } from '../rpc/client.js'
6
+ import type { RpcConfig } from '../rpc/config.js'
7
+ import { ConnectionClient } from '../rpc/connection.js'
8
8
 
9
9
  /* Service */
10
10
 
11
- export type ConnectionService = {
12
- preConnect: () => E.Effect<void>
13
- }
14
-
15
- export const ConnectionService = Context.GenericTag<ConnectionService>('@services/ConnectService')
11
+ export class ConnectionService extends Context.Tag('@services/ConnectionService')<
12
+ ConnectionService,
13
+ {
14
+ preConnect: () => E.Effect<void>
15
+ }
16
+ >() {}
16
17
 
17
18
  /* Effects */
18
19
 
package/src/effect.ts CHANGED
@@ -1,115 +1,132 @@
1
1
  import { create, get as getCredential } from '@github/webauthn-json/browser-ponyfill'
2
2
 
3
- import { AuthenticationClientLive } from '@passlock/shared/dist/rpc/authentication.js'
4
- import { ConnectionClientLive } from '@passlock/shared/dist/rpc/connection.js'
5
- import { RegistrationClientLive } from '@passlock/shared/dist/rpc/registration.js'
6
- import { SocialClientLive } from '@passlock/shared/dist/rpc/social.js'
7
- import { UserClientLive } from '@passlock/shared/dist/rpc/user.js'
8
-
9
3
  import {
4
+ type BadRequest,
10
5
  Duplicate,
11
6
  InternalBrowserError,
12
- type BadRequest,
13
- type Disabled,
14
- type Forbidden,
15
- type NotFound,
16
- type NotSupported,
17
- type Unauthorized,
18
7
  } from '@passlock/shared/dist/error/error.js'
19
8
 
9
+ import { AuthenticationClientLive } from './rpc/authentication.js'
10
+ import { DispatcherLive } from './rpc/client.js'
11
+ import type { RpcConfig } from './rpc/config.js'
12
+ import { RetrySchedule } from './rpc/config.js'
13
+ import { ConnectionClientLive } from './rpc/connection.js'
14
+ import { RegistrationClientLive } from './rpc/registration.js'
15
+ import { SocialClientLive } from './rpc/social.js'
16
+ import { UserClientLive } from './rpc/user.js'
17
+
20
18
  import type { Principal } from '@passlock/shared/dist/schema/principal.js'
21
19
 
22
- import { Context, Effect as E, Layer as L, Layer, Schedule, pipe } from 'effect'
20
+ import { Effect as E, Layer as L, Layer, Schedule, pipe } from 'effect'
23
21
  import type { NoSuchElementException } from 'effect/Cause'
24
22
 
25
23
  import {
26
24
  AuthenticateServiceLive,
25
+ type AuthenticationErrors,
26
+ type AuthenticationRequest,
27
27
  AuthenticationService,
28
28
  GetCredential,
29
- type AuthenticationRequest,
30
29
  } from './authentication/authenticate.js'
31
30
 
32
- import { capabilitiesLive } from './capabilities/capabilities.js'
31
+ import { Capabilities, capabilitiesLive } from './capabilities/capabilities.js'
33
32
  import { ConnectionService, ConnectionServiceLive } from './connection/connection.js'
34
- import { EmailService, EmailServiceLive, URLQueryString, type VerifyRequest } from './email/email.js'
33
+ import {
34
+ EmailService,
35
+ EmailServiceLive,
36
+ URLQueryString,
37
+ type VerifyEmailErrors,
38
+ type VerifyRequest,
39
+ } from './email/email.js'
35
40
 
36
41
  import {
37
42
  CreateCredential,
43
+ type RegistrationErrors,
44
+ type RegistrationRequest,
38
45
  RegistrationService,
39
46
  RegistrationServiceLive,
40
- type RegistrationRequest,
41
47
  } from './registration/register.js'
42
48
 
43
49
  import {
44
- Storage,
50
+ type AuthenticateOidcReq,
51
+ type AuthenticationErrors as OidcAuthenticationErrors,
52
+ type RegistrationErrors as OidcRegistrationErrors,
53
+ type RegisterOidcReq,
54
+ SocialService,
55
+ SocialServiceLive,
56
+ } from './social/social.js'
57
+ import {
58
+ type AuthType,
59
+ BrowserStorage,
45
60
  StorageService,
46
61
  StorageServiceLive,
47
- type AuthType,
48
62
  type StoredToken,
49
63
  } from './storage/storage.js'
50
64
 
51
- import { RetrySchedule, RpcConfig } from '@passlock/shared/dist/rpc/config.js'
52
- import { DispatcherLive } from '@passlock/shared/dist/rpc/dispatcher.js'
53
- import { SocialService, SocialServiceLive, type RegisterOidcReq } from './social/social.js'
54
- import { UserService, UserServiceLive, type Email } from './user/user.js'
65
+ import {
66
+ type Email,
67
+ type ResendEmail,
68
+ type ResendEmailErrors,
69
+ UserService,
70
+ UserServiceLive,
71
+ } from './user/user.js'
55
72
 
56
73
  /* Layers */
57
74
 
58
75
  const createCredentialLive = L.succeed(
59
76
  CreateCredential,
60
- CreateCredential.of((options: CredentialCreationOptions) =>
61
- pipe(
62
- E.tryPromise({
63
- try: () => create(options),
64
- catch: e => {
65
- if (e instanceof Error && e.message.includes('excludeCredentials')) {
66
- return new Duplicate({
67
- message: 'Passkey already registered to this device or cloud account',
68
- })
69
- } else {
70
- return new InternalBrowserError({
71
- message: 'Unable to create credential',
72
- detail: String(e),
73
- })
74
- }
75
- },
76
- }),
77
- E.map(credential => credential.toJSON())
78
- ),
79
- ),
77
+ CreateCredential.of({
78
+ createCredential: options =>
79
+ pipe(
80
+ E.tryPromise({
81
+ try: () => create(options),
82
+ catch: e => {
83
+ if (e instanceof Error && e.message.includes('excludeCredentials')) {
84
+ return new Duplicate({
85
+ message: 'Passkey already registered to this device or cloud account',
86
+ })
87
+ } else {
88
+ return new InternalBrowserError({
89
+ message: 'Unable to create credential',
90
+ detail: String(e),
91
+ })
92
+ }
93
+ },
94
+ }),
95
+ E.map(credential => credential.toJSON()),
96
+ ),
97
+ }),
80
98
  )
81
99
 
82
100
  const getCredentialLive = L.succeed(
83
101
  GetCredential,
84
- GetCredential.of((options: CredentialRequestOptions) =>
85
- pipe(
86
- E.tryPromise({
87
- try: () => getCredential(options),
88
- catch: e =>
89
- new InternalBrowserError({
90
- message: 'Unable to get authentication credential',
91
- detail: String(e),
92
- }),
93
- }),
94
- E.map(credential => credential.toJSON()),
95
- ),
96
- ),
102
+ GetCredential.of({
103
+ getCredential: (options: CredentialRequestOptions) =>
104
+ pipe(
105
+ E.tryPromise({
106
+ try: () => getCredential(options),
107
+ catch: e =>
108
+ new InternalBrowserError({
109
+ message: 'Unable to get authentication credential',
110
+ detail: String(e),
111
+ }),
112
+ }),
113
+ E.map(credential => credential.toJSON()),
114
+ ),
115
+ }),
97
116
  )
98
117
 
99
118
  const schedule = Schedule.intersect(Schedule.recurs(3), Schedule.exponential('100 millis'))
100
119
 
101
120
  const retryScheduleLive = L.succeed(RetrySchedule, RetrySchedule.of({ schedule }))
102
121
 
103
- /* RPC Clients */
122
+ /* Services */
104
123
  const dispatcherLive = pipe(DispatcherLive, L.provide(retryScheduleLive))
105
124
  const connectClientLive = pipe(ConnectionClientLive, L.provide(dispatcherLive))
106
125
  const registerClientLive = pipe(RegistrationClientLive, L.provide(dispatcherLive))
107
126
  const authenticateClientLive = pipe(AuthenticationClientLive, L.provide(dispatcherLive))
108
127
  const socialClientLive = pipe(SocialClientLive, L.provide(dispatcherLive))
109
128
  const userClientLive = pipe(UserClientLive, L.provide(dispatcherLive))
110
-
111
129
  const storageServiceLive = StorageServiceLive
112
-
113
130
  const userServiceLive = pipe(UserServiceLive, L.provide(userClientLive))
114
131
 
115
132
  const registrationServiceLive = pipe(
@@ -149,10 +166,7 @@ const emailServiceLive = pipe(
149
166
  L.provide(storageServiceLive),
150
167
  )
151
168
 
152
- const socialServiceLive = pipe(
153
- SocialServiceLive,
154
- L.provide(socialClientLive),
155
- )
169
+ const socialServiceLive = pipe(SocialServiceLive, L.provide(socialClientLive))
156
170
 
157
171
  export const allRequirements = Layer.mergeAll(
158
172
  capabilitiesLive,
@@ -165,98 +179,75 @@ export const allRequirements = Layer.mergeAll(
165
179
  socialServiceLive,
166
180
  )
167
181
 
168
- export class Config extends Context.Tag('Config')<
169
- Config,
170
- {
171
- tenancyId: string
172
- clientId: string
173
- endpoint?: string
174
- }
175
- >() {}
176
-
177
- const storageLive = Layer.effect(
178
- Storage,
179
- E.sync(() => Storage.of(globalThis.localStorage)),
182
+ const browserStorageLive = Layer.effect(
183
+ BrowserStorage,
184
+ E.sync(() => BrowserStorage.of(globalThis.localStorage)),
180
185
  )
181
186
 
182
- const exchangeConfig = <A, E>(effect: E.Effect<A, E, RpcConfig | Storage>) => {
183
- return pipe(
184
- Config,
185
- E.flatMap(config => E.provideService(effect, RpcConfig, RpcConfig.of(config))),
186
- effect => E.provide(effect, storageLive),
187
- )
188
- }
189
-
190
- export const preConnect = (): E.Effect<void, never, Config> =>
187
+ export const preConnect = (): E.Effect<void, never, RpcConfig> =>
191
188
  pipe(
192
189
  ConnectionService,
193
190
  E.flatMap(service => service.preConnect()),
194
191
  E.provide(connectionServiceLive),
195
- exchangeConfig,
196
192
  )
197
193
 
198
- export const isRegistered = (email: Email): E.Effect<boolean, BadRequest, Config> =>
194
+ export const isPasskeySupport: E.Effect<boolean> = pipe(
195
+ Capabilities,
196
+ E.flatMap(service => service.isPasskeySupport),
197
+ E.provide(capabilitiesLive),
198
+ )
199
+
200
+ export const isExistingUser = (request: Email): E.Effect<boolean, BadRequest, RpcConfig> =>
199
201
  pipe(
200
202
  UserService,
201
- E.flatMap(service => service.isExistingUser(email)),
203
+ E.flatMap(service => service.isExistingUser(request)),
202
204
  E.provide(userServiceLive),
203
- exchangeConfig,
204
205
  )
205
206
 
206
- export type RegistrationErrors = NotSupported | BadRequest | Duplicate | Unauthorized | Forbidden
207
-
208
207
  export const registerPasskey = (
209
208
  request: RegistrationRequest,
210
- ): E.Effect<Principal, RegistrationErrors, Config> =>
209
+ ): E.Effect<Principal, RegistrationErrors, RpcConfig> =>
211
210
  pipe(
212
211
  RegistrationService,
213
212
  E.flatMap(service => service.registerPasskey(request)),
214
213
  E.provide(registrationServiceLive),
215
- exchangeConfig,
214
+ E.provide(browserStorageLive),
216
215
  )
217
216
 
218
- export type AuthenticationErrors =
219
- | NotSupported
220
- | BadRequest
221
- | NotFound
222
- | Disabled
223
- | Unauthorized
224
- | Forbidden
225
-
226
217
  export const authenticatePasskey = (
227
218
  request: AuthenticationRequest,
228
- ): E.Effect<Principal, AuthenticationErrors, Config> =>
229
- pipe(
219
+ ): E.Effect<Principal, AuthenticationErrors, RpcConfig> => pipe(
230
220
  AuthenticationService,
231
221
  E.flatMap(service => service.authenticatePasskey(request)),
232
222
  E.provide(authenticationServiceLive),
233
- exchangeConfig,
223
+ E.provide(browserStorageLive),
234
224
  )
235
225
 
236
- export type VerifyEmailErrors =
237
- | NotSupported
238
- | BadRequest
239
- | NotFound
240
- | Disabled
241
- | Unauthorized
242
- | Forbidden
243
-
244
226
  export const verifyEmailCode = (
245
227
  request: VerifyRequest,
246
- ): E.Effect<Principal, VerifyEmailErrors, Config> =>
228
+ ): E.Effect<Principal, VerifyEmailErrors, RpcConfig> =>
247
229
  pipe(
248
230
  EmailService,
249
231
  E.flatMap(service => service.verifyEmailCode(request)),
250
232
  E.provide(emailServiceLive),
251
- exchangeConfig,
233
+ E.provide(browserStorageLive),
252
234
  )
253
235
 
254
- export const verifyEmailLink = (): E.Effect<Principal, VerifyEmailErrors, Config> =>
236
+ export const verifyEmailLink: E.Effect<Principal, VerifyEmailErrors, RpcConfig> = pipe(
237
+ EmailService,
238
+ E.flatMap(service => service.verifyEmailLink()),
239
+ E.provide(emailServiceLive),
240
+ E.provide(browserStorageLive),
241
+ )
242
+
243
+ export const resendVerificationEmail = (
244
+ request: ResendEmail,
245
+ ): E.Effect<void, ResendEmailErrors, RpcConfig> =>
255
246
  pipe(
256
- EmailService,
257
- E.flatMap(service => service.verifyEmailLink()),
258
- E.provide(emailServiceLive),
259
- exchangeConfig,
247
+ UserService,
248
+ E.flatMap(service => service.resendVerificationEmail(request)),
249
+ E.provide(userServiceLive),
250
+ E.provide(browserStorageLive),
260
251
  )
261
252
 
262
253
  export const getSessionToken = (
@@ -266,20 +257,30 @@ export const getSessionToken = (
266
257
  StorageService,
267
258
  E.flatMap(service => service.getToken(authType)),
268
259
  E.provide(storageServiceLive),
269
- E.provide(storageLive),
260
+ E.provide(browserStorageLive),
270
261
  )
271
262
 
272
- export const clearExpiredTokens = (): E.Effect<void> =>
263
+ export const clearExpiredTokens: E.Effect<void> = pipe(
264
+ StorageService,
265
+ E.flatMap(service => service.clearExpiredTokens),
266
+ E.provide(storageServiceLive),
267
+ E.provide(browserStorageLive),
268
+ )
269
+
270
+ export const registerOidc = (
271
+ request: RegisterOidcReq,
272
+ ): E.Effect<Principal, OidcRegistrationErrors, RpcConfig> =>
273
273
  pipe(
274
- StorageService,
275
- E.flatMap(service => service.clearExpiredTokens),
276
- E.provide(storageServiceLive),
277
- E.provide(storageLive),
274
+ SocialService,
275
+ E.flatMap(service => service.registerOidc(request)),
276
+ E.provide(socialServiceLive),
278
277
  )
279
278
 
280
- export const authenticateOIDC = (request: RegisterOidcReq) =>
279
+ export const authenticateOidc = (
280
+ request: AuthenticateOidcReq,
281
+ ): E.Effect<Principal, OidcAuthenticationErrors, RpcConfig> =>
281
282
  pipe(
282
283
  SocialService,
283
- E.flatMap(service => service.registerOidc(request)),
284
- E.provide(socialServiceLive)
285
- )
284
+ E.flatMap(service => service.authenticateOidc(request)),
285
+ E.provide(socialServiceLive),
286
+ )
@@ -1,6 +1,7 @@
1
- import { UserClient, VerifyEmailReq, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
2
- import { Effect as E, Layer as L } from 'effect'
1
+ import { VerifyEmailReq, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
2
+ import { Effect as E, Layer as L, Option as O } from 'effect'
3
3
  import { AuthenticationService } from '../authentication/authenticate.js'
4
+ import { UserClient } from '../rpc/user.js'
4
5
  import * as Fixtures from '../test/fixtures.js'
5
6
  import { URLQueryString } from './email.js'
6
7
 
@@ -28,7 +29,7 @@ export const rpcVerifyEmailRes = new VerifyEmailRes({ principal: Fixtures.princi
28
29
  export const rpcClientTest = L.succeed(
29
30
  UserClient,
30
31
  UserClient.of({
31
- isExistingUser: () => E.succeed({ existingUser: true }),
32
+ isExistingUser: () => E.succeed({ existingUser: true, detail: O.none() }),
32
33
  verifyEmail: () => E.succeed(rpcVerifyEmailRes),
33
34
  resendVerificationEmail: () => E.fail(Fixtures.notImplemented),
34
35
  }),
@@ -1,9 +1,9 @@
1
- import { UserClient } from '@passlock/shared/dist/rpc/user.js'
2
1
  import { Effect as E, Layer as L, LogLevel, Logger, pipe } from 'effect'
3
2
  import { NoSuchElementException } from 'effect/Cause'
4
3
  import { describe, expect, test } from 'vitest'
5
4
  import { mock } from 'vitest-mock-extended'
6
5
  import { AuthenticationService } from '../authentication/authenticate.js'
6
+ import { UserClient } from '../rpc/user.js'
7
7
  import { StorageService } from '../storage/storage.js'
8
8
  import * as Fixture from './email.fixture.js'
9
9
  import { EmailService, EmailServiceLive } from './email.js'
@@ -42,7 +42,7 @@ describe('verifyEmailCode should', () => {
42
42
  const storageServiceTest = L.effect(
43
43
  StorageService,
44
44
  E.sync(() => {
45
- const storageServiceMock = mock<StorageService>()
45
+ const storageServiceMock = mock<StorageService['Type']>()
46
46
 
47
47
  storageServiceMock.getToken.mockReturnValue(E.succeed(Fixture.storedToken))
48
48
  storageServiceMock.clearToken.mockReturnValue(E.void)
@@ -77,7 +77,7 @@ describe('verifyEmailCode should', () => {
77
77
  const storageServiceTest = L.effect(
78
78
  StorageService,
79
79
  E.sync(() => {
80
- const storageServiceMock = mock<StorageService>()
80
+ const storageServiceMock = mock<StorageService['Type']>()
81
81
 
82
82
  storageServiceMock.getToken.mockReturnValue(E.fail(new NoSuchElementException()))
83
83
  storageServiceMock.clearToken.mockReturnValue(E.void)
@@ -89,7 +89,7 @@ describe('verifyEmailCode should', () => {
89
89
  const authServiceTest = L.effect(
90
90
  AuthenticationService,
91
91
  E.sync(() => {
92
- const authServiceMock = mock<AuthenticationService>()
92
+ const authServiceMock = mock<AuthenticationService['Type']>()
93
93
 
94
94
  authServiceMock.authenticatePasskey.mockReturnValue(E.succeed(Fixture.principal))
95
95
 
@@ -3,11 +3,12 @@
3
3
  */
4
4
  import { BadRequest } from '@passlock/shared/dist/error/error.js'
5
5
  import type { VerifyEmailErrors as RpcErrors } from '@passlock/shared/dist/rpc/user.js'
6
- import { UserClient, VerifyEmailReq } from '@passlock/shared/dist/rpc/user.js'
6
+ import { VerifyEmailReq } from '@passlock/shared/dist/rpc/user.js'
7
7
  import type { Principal } from '@passlock/shared/dist/schema/principal.js'
8
8
  import { Context, Effect as E, Layer, Option as O, flow, identity, pipe } from 'effect'
9
- import { AuthenticationService, type AuthenticationErrors } from '../authentication/authenticate.js'
10
- import { StorageService } from '../storage/storage.js'
9
+ import { type AuthenticationErrors, AuthenticationService } from '../authentication/authenticate.js'
10
+ import { UserClient } from '../rpc/user.js'
11
+ import { StorageService, type StoredToken } from '../storage/storage.js'
11
12
 
12
13
  /* Requests */
13
14
 
@@ -21,19 +22,20 @@ export type VerifyEmailErrors = RpcErrors | AuthenticationErrors
21
22
 
22
23
  /* Dependencies */
23
24
 
24
- export class URLQueryString extends Context.Tag('URLQueryString')<
25
+ export class URLQueryString extends Context.Tag('@utils/URLQueryString')<
25
26
  URLQueryString,
26
27
  E.Effect<string>
27
28
  >() {}
28
29
 
29
30
  /* Service */
30
31
 
31
- export type EmailService = {
32
- verifyEmailCode: (request: VerifyRequest) => E.Effect<Principal, VerifyEmailErrors>
33
- verifyEmailLink: () => E.Effect<Principal, VerifyEmailErrors>
34
- }
35
-
36
- export const EmailService = Context.GenericTag<EmailService>('@services/EmailService')
32
+ export class EmailService extends Context.Tag('@services/EmailService')<
33
+ EmailService,
34
+ {
35
+ verifyEmailCode: (request: VerifyRequest) => E.Effect<Principal, VerifyEmailErrors>
36
+ verifyEmailLink: () => E.Effect<Principal, VerifyEmailErrors>
37
+ }
38
+ >() {}
37
39
 
38
40
  /* Utils */
39
41
 
@@ -56,12 +58,18 @@ const getToken = () => {
56
58
  onFailure: () =>
57
59
  // No token, need to authenticate the user
58
60
  pipe(
59
- authenticationService.authenticatePasskey({ userVerification: 'preferred' }),
60
- E.map(principal => ({
61
- token: principal.token,
62
- authType: principal.authStatement.authType,
63
- expiresAt: principal.expireAt.getTime(),
64
- })),
61
+ authenticationService.authenticatePasskey({
62
+ userVerification: O.some('preferred'),
63
+ email: O.none(),
64
+ }),
65
+ E.map(
66
+ principal =>
67
+ ({
68
+ token: principal.jti,
69
+ authType: principal.authType,
70
+ expiry: principal.exp.getTime(),
71
+ }) as StoredToken,
72
+ ),
65
73
  ),
66
74
  })
67
75