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