@passlock/client 0.9.10 → 0.9.12

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 (79) hide show
  1. package/dist/authentication/authenticate.d.ts.map +1 -1
  2. package/dist/authentication/authenticate.fixture.d.ts +5 -5
  3. package/dist/authentication/authenticate.fixture.d.ts.map +1 -1
  4. package/dist/authentication/authenticate.fixture.js +9 -9
  5. package/dist/authentication/authenticate.fixture.js.map +1 -1
  6. package/dist/authentication/authenticate.js.map +1 -1
  7. package/dist/authentication/authenticate.test.js +7 -7
  8. package/dist/authentication/authenticate.test.js.map +1 -1
  9. package/dist/connection/connection.d.ts.map +1 -1
  10. package/dist/connection/connection.js.map +1 -1
  11. package/dist/connection/connection.test.js +1 -1
  12. package/dist/connection/connection.test.js.map +1 -1
  13. package/dist/effect.d.ts +5 -5
  14. package/dist/effect.d.ts.map +1 -1
  15. package/dist/effect.js +1 -1
  16. package/dist/effect.js.map +1 -1
  17. package/dist/email/email.d.ts +2 -2
  18. package/dist/email/email.d.ts.map +1 -1
  19. package/dist/email/email.fixture.d.ts +3 -3
  20. package/dist/email/email.fixture.d.ts.map +1 -1
  21. package/dist/email/email.fixture.js +4 -4
  22. package/dist/email/email.fixture.js.map +1 -1
  23. package/dist/email/email.js.map +1 -1
  24. package/dist/email/email.test.js +6 -6
  25. package/dist/email/email.test.js.map +1 -1
  26. package/dist/index.d.ts +5 -6
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +1 -1
  29. package/dist/index.js.map +1 -1
  30. package/dist/registration/register.d.ts.map +1 -1
  31. package/dist/registration/register.fixture.d.ts +5 -5
  32. package/dist/registration/register.fixture.d.ts.map +1 -1
  33. package/dist/registration/register.fixture.js +8 -8
  34. package/dist/registration/register.fixture.js.map +1 -1
  35. package/dist/registration/register.js.map +1 -1
  36. package/dist/registration/register.test.js +7 -7
  37. package/dist/registration/register.test.js.map +1 -1
  38. package/dist/social/social.d.ts.map +1 -1
  39. package/dist/social/social.fixture.d.ts +34 -0
  40. package/dist/social/social.fixture.d.ts.map +1 -0
  41. package/dist/social/social.fixture.js +35 -0
  42. package/dist/social/social.fixture.js.map +1 -0
  43. package/dist/social/social.test.d.ts +2 -0
  44. package/dist/social/social.test.d.ts.map +1 -0
  45. package/dist/social/social.test.js +110 -0
  46. package/dist/social/social.test.js.map +1 -0
  47. package/dist/storage/storage.test.js +1 -1
  48. package/dist/storage/storage.test.js.map +1 -1
  49. package/dist/test/fixtures.d.ts +2 -2
  50. package/dist/test/fixtures.d.ts.map +1 -1
  51. package/dist/test/fixtures.js +2 -2
  52. package/dist/test/fixtures.js.map +1 -1
  53. package/dist/user/user.fixture.d.ts +5 -1
  54. package/dist/user/user.fixture.d.ts.map +1 -1
  55. package/dist/user/user.fixture.js +4 -1
  56. package/dist/user/user.fixture.js.map +1 -1
  57. package/dist/user/user.test.js +20 -1
  58. package/dist/user/user.test.js.map +1 -1
  59. package/package.json +10 -10
  60. package/src/authentication/authenticate.fixture.ts +12 -12
  61. package/src/authentication/authenticate.test.ts +8 -8
  62. package/src/authentication/authenticate.ts +7 -7
  63. package/src/connection/connection.test.ts +2 -2
  64. package/src/connection/connection.ts +3 -3
  65. package/src/effect.ts +26 -26
  66. package/src/email/email.fixture.ts +4 -4
  67. package/src/email/email.test.ts +7 -7
  68. package/src/email/email.ts +2 -2
  69. package/src/index.ts +15 -16
  70. package/src/registration/register.fixture.ts +12 -12
  71. package/src/registration/register.test.ts +8 -8
  72. package/src/registration/register.ts +6 -6
  73. package/src/social/social.fixture.ts +47 -0
  74. package/src/social/social.test.ts +193 -0
  75. package/src/social/social.ts +3 -3
  76. package/src/storage/storage.test.ts +1 -1
  77. package/src/test/fixtures.ts +2 -2
  78. package/src/user/user.fixture.ts +5 -1
  79. package/src/user/user.test.ts +36 -2
@@ -2,8 +2,8 @@
2
2
  * User & passkey registration effects
3
3
  */
4
4
  import {
5
- type CredentialCreationOptionsJSON,
6
- parseCreationOptionsFromJSON,
5
+ parseCreationOptionsFromJSON,
6
+ type CredentialCreationOptionsJSON,
7
7
  } from '@github/webauthn-json/browser-ponyfill'
8
8
  import type { NotSupported } from '@passlock/shared/dist/error/error.js'
9
9
  import { Duplicate, InternalBrowserError } from '@passlock/shared/dist/error/error.js'
@@ -11,10 +11,10 @@ import type { OptionsErrors, VerificationErrors } from '@passlock/shared/dist/rp
11
11
  import { OptionsReq, VerificationReq } from '@passlock/shared/dist/rpc/registration.js'
12
12
  import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
13
13
  import type {
14
- Principal,
15
- RegistrationCredential,
16
- UserVerification,
17
- VerifyEmail,
14
+ Principal,
15
+ RegistrationCredential,
16
+ UserVerification,
17
+ VerifyEmail,
18
18
  } from '@passlock/shared/dist/schema/schema.js'
19
19
  import { Context, Effect as E, Layer, flow, pipe } from 'effect'
20
20
  import { Capabilities } from '../capabilities/capabilities.js'
@@ -0,0 +1,47 @@
1
+ import { PreConnectRes } from '@passlock/shared/dist/rpc/connection.js'
2
+ import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
3
+ import { AuthenticateOidcReq, OidcRes, RegisterOidcReq } from '@passlock/shared/dist/rpc/social.js'
4
+ import { Effect as E, Layer as L } from 'effect'
5
+ import * as Fixtures from '../test/fixtures.js'
6
+ import { type OidcRequest } from './social.js'
7
+
8
+ export const session = 'session'
9
+ export const token = 'token'
10
+ export const code = 'code'
11
+ export const authType = 'passkey'
12
+ export const expireAt = Date.now() + 10000
13
+
14
+ export const oidcReq: OidcRequest = {
15
+ provider: 'google',
16
+ idToken: 'google-token'
17
+ }
18
+
19
+ export const rpcRegisterReq = new RegisterOidcReq({ ...oidcReq })
20
+
21
+ export const rpcRegisterRes = new OidcRes({ principal: Fixtures.principal })
22
+
23
+ export const rpcAuthenticateReq = new AuthenticateOidcReq({ ...oidcReq })
24
+
25
+ export const rpcAuthenticateRes = new OidcRes({ principal: Fixtures.principal })
26
+
27
+ export const rpcClientTest = L.succeed(
28
+ RpcClient,
29
+ RpcClient.of({
30
+ preConnect: () => E.succeed(new PreConnectRes({ warmed: true })),
31
+ isExistingUser: () => E.fail(Fixtures.notImplemented),
32
+ verifyEmail: () => E.fail(Fixtures.notImplemented),
33
+ getRegistrationOptions: () => E.fail(Fixtures.notImplemented),
34
+ verifyRegistrationCredential: () => E.fail(Fixtures.notImplemented),
35
+ getAuthenticationOptions: () => E.fail(Fixtures.notImplemented),
36
+ verifyAuthenticationCredential: () => E.fail(Fixtures.notImplemented),
37
+ registerOidc: () => E.fail(Fixtures.notImplemented),
38
+ authenticateOidc: () => E.fail(Fixtures.notImplemented),
39
+ resendVerificationEmail: () => E.fail(Fixtures.notImplemented),
40
+ }),
41
+ )
42
+
43
+ export const principal = Fixtures.principal
44
+
45
+ export const capabilitiesTest = Fixtures.capabilitiesTest
46
+
47
+ export const storageServiceTest = Fixtures.storageServiceTest
@@ -0,0 +1,193 @@
1
+ import { Duplicate, NotFound } from '@passlock/shared/dist/error/error.js'
2
+ import { RpcClient, type RouterOps } from '@passlock/shared/dist/rpc/rpc.js'
3
+ import { Effect as E, Layer as L, Layer, LogLevel, Logger, pipe } from 'effect'
4
+ import { describe, expect, test } from 'vitest'
5
+ import { mock } from 'vitest-mock-extended'
6
+ import * as Fixture from './social.fixture.js'
7
+ import { SocialService, SocialServiceLive } from './social.js'
8
+
9
+ describe('registerOidc should', () => {
10
+ test('return a valid credential', async () => {
11
+ const assertions = E.gen(function* (_) {
12
+ const service = yield* _(SocialService)
13
+ const result = yield* _(service.registerOidc(Fixture.oidcReq))
14
+ expect(result).toEqual(Fixture.principal)
15
+ })
16
+
17
+ const rpcClientTest = L.effect(
18
+ RpcClient,
19
+ E.sync(() => {
20
+ const rpcMock = mock<RouterOps>()
21
+
22
+ rpcMock.registerOidc.mockReturnValue(E.succeed(Fixture.rpcRegisterRes))
23
+
24
+ return rpcMock
25
+ }),
26
+ )
27
+
28
+ const service = pipe(
29
+ SocialServiceLive,
30
+ L.provide(rpcClientTest),
31
+ )
32
+
33
+ const layers = Layer.merge(service, rpcClientTest)
34
+ const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
35
+
36
+ return E.runPromise(effect)
37
+ })
38
+
39
+ test('pass the request to the backend', async () => {
40
+ const assertions = E.gen(function* (_) {
41
+ const service = yield* _(SocialService)
42
+ yield* _(service.registerOidc(Fixture.oidcReq))
43
+
44
+ const rpcClient = yield* _(RpcClient)
45
+ expect(rpcClient.registerOidc).toHaveBeenCalledWith(Fixture.rpcRegisterReq)
46
+ })
47
+
48
+ const rpcClientTest = L.effect(
49
+ RpcClient,
50
+ E.sync(() => {
51
+ const rpcMock = mock<RouterOps>()
52
+
53
+ rpcMock.registerOidc.mockReturnValue(E.succeed(Fixture.rpcRegisterRes))
54
+
55
+ return rpcMock
56
+ }),
57
+ )
58
+
59
+ const service = pipe(
60
+ SocialServiceLive,
61
+ L.provide(rpcClientTest),
62
+ )
63
+
64
+ const layers = Layer.merge(service, rpcClientTest)
65
+ const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
66
+
67
+ return E.runPromise(effect)
68
+ })
69
+
70
+ test('return an error if we try to register an existing user', async () => {
71
+ const assertions = E.gen(function* (_) {
72
+ const service = yield* _(SocialService)
73
+
74
+ const defect = yield* _(service.registerOidc(Fixture.oidcReq), E.flip)
75
+
76
+ expect(defect).toBeInstanceOf(Duplicate)
77
+ })
78
+
79
+ const rpcClientTest = L.effect(
80
+ RpcClient,
81
+ E.sync(() => {
82
+ const rpcMock = mock<RouterOps>()
83
+
84
+ rpcMock.registerOidc.mockReturnValue(E.fail(new Duplicate({ message: "Duplicate user" })))
85
+
86
+ return rpcMock
87
+ }),
88
+ )
89
+
90
+ const service = pipe(
91
+ SocialServiceLive,
92
+ L.provide(rpcClientTest),
93
+ )
94
+
95
+ const layers = Layer.merge(service, rpcClientTest)
96
+ const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
97
+
98
+ return E.runPromise(effect)
99
+ })
100
+ })
101
+
102
+ describe('authenticateIodc should', () => {
103
+ test('return a valid credential', async () => {
104
+ const assertions = E.gen(function* (_) {
105
+ const service = yield* _(SocialService)
106
+ const result = yield* _(service.authenticateOidc(Fixture.oidcReq))
107
+ expect(result).toEqual(Fixture.principal)
108
+ })
109
+
110
+ const rpcClientTest = L.effect(
111
+ RpcClient,
112
+ E.sync(() => {
113
+ const rpcMock = mock<RouterOps>()
114
+
115
+ rpcMock.authenticateOidc.mockReturnValue(E.succeed(Fixture.rpcRegisterRes))
116
+
117
+ return rpcMock
118
+ }),
119
+ )
120
+
121
+ const service = pipe(
122
+ SocialServiceLive,
123
+ L.provide(rpcClientTest),
124
+ )
125
+
126
+ const layers = Layer.merge(service, rpcClientTest)
127
+ const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
128
+
129
+ return E.runPromise(effect)
130
+ })
131
+
132
+ test('pass the request to the backend', async () => {
133
+ const assertions = E.gen(function* (_) {
134
+ const service = yield* _(SocialService)
135
+ yield* _(service.authenticateOidc(Fixture.oidcReq))
136
+
137
+ const rpcClient = yield* _(RpcClient)
138
+ expect(rpcClient.authenticateOidc).toHaveBeenCalledWith(Fixture.rpcAuthenticateReq)
139
+ })
140
+
141
+ const rpcClientTest = L.effect(
142
+ RpcClient,
143
+ E.sync(() => {
144
+ const rpcMock = mock<RouterOps>()
145
+
146
+ rpcMock.authenticateOidc.mockReturnValue(E.succeed(Fixture.rpcAuthenticateRes))
147
+
148
+ return rpcMock
149
+ }),
150
+ )
151
+
152
+ const service = pipe(
153
+ SocialServiceLive,
154
+ L.provide(rpcClientTest),
155
+ )
156
+
157
+ const layers = Layer.merge(service, rpcClientTest)
158
+ const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
159
+
160
+ return E.runPromise(effect)
161
+ })
162
+
163
+ test('return an error if we try to authenticate a non-existing user', async () => {
164
+ const assertions = E.gen(function* (_) {
165
+ const service = yield* _(SocialService)
166
+
167
+ const defect = yield* _(service.authenticateOidc(Fixture.oidcReq), E.flip)
168
+
169
+ expect(defect).toBeInstanceOf(NotFound)
170
+ })
171
+
172
+ const rpcClientTest = L.effect(
173
+ RpcClient,
174
+ E.sync(() => {
175
+ const rpcMock = mock<RouterOps>()
176
+
177
+ rpcMock.authenticateOidc.mockReturnValue(E.fail(new NotFound({ message: "User not found" })))
178
+
179
+ return rpcMock
180
+ }),
181
+ )
182
+
183
+ const service = pipe(
184
+ SocialServiceLive,
185
+ L.provide(rpcClientTest),
186
+ )
187
+
188
+ const layers = Layer.merge(service, rpcClientTest)
189
+ const effect = pipe(E.provide(assertions, layers), Logger.withMinimumLogLevel(LogLevel.None))
190
+
191
+ return E.runPromise(effect)
192
+ })
193
+ })
@@ -2,13 +2,13 @@
2
2
  * Passkey authentication effects
3
3
  */
4
4
  import {
5
- type BadRequest,
6
- type NotSupported
5
+ type BadRequest,
6
+ type NotSupported
7
7
  } from '@passlock/shared/dist/error/error.js'
8
8
  import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
9
9
  import { AuthenticateOidcErrors, AuthenticateOidcReq, RegisterOidcErrors, RegisterOidcReq } from '@passlock/shared/dist/rpc/social.js'
10
10
  import type {
11
- Principal
11
+ Principal
12
12
  } from '@passlock/shared/dist/schema/schema.js'
13
13
  import { Context, Effect as E, Layer, flow } from 'effect'
14
14
 
@@ -1,8 +1,8 @@
1
1
  import { Effect as E, Layer, LogLevel, Logger, identity, pipe } from 'effect'
2
2
  import { describe, expect, test } from 'vitest'
3
3
  import { mock } from 'vitest-mock-extended'
4
- import { Storage, StorageService, clearExpiredToken, clearToken, getToken } from './storage.js'
5
4
  import { principal, testLayers } from './storage.fixture.js'
5
+ import { Storage, StorageService, clearExpiredToken, clearToken, getToken } from './storage.js'
6
6
 
7
7
  // eslint chokes on expect(storage.setItem) etc
8
8
  /* eslint @typescript-eslint/unbound-method: 0 */
@@ -1,9 +1,9 @@
1
+ import { BadRequest } from '@passlock/shared/dist/error/error.js'
2
+ import { PreConnectRes } from '@passlock/shared/dist/rpc/connection.js'
1
3
  import type { Principal } from '@passlock/shared/dist/schema/schema.js'
2
4
  import { Effect as E, Layer as L } from 'effect'
3
5
  import { Capabilities } from '../capabilities/capabilities.js'
4
6
  import { StorageService, type StoredToken } from '../storage/storage.js'
5
- import { BadRequest } from '@passlock/shared/dist/error/error.js'
6
- import { PreConnectRes } from '@passlock/shared/dist/rpc/connection.js'
7
7
 
8
8
  export const session = 'session'
9
9
  export const token = 'token'
@@ -1,12 +1,16 @@
1
1
  import { RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
2
- import { IsExistingUserReq, IsExistingUserRes, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
2
+ import { IsExistingUserReq, IsExistingUserRes, ResendEmailReq, ResendEmailRes, VerifyEmailRes } from '@passlock/shared/dist/rpc/user.js'
3
3
  import { Effect as E, Layer as L } from 'effect'
4
4
  import * as Fixtures from '../test/fixtures.js'
5
+ import type { ResendEmail } from './user.js'
5
6
 
6
7
  export const email = 'jdoe@gmail.com'
7
8
  export const isRegisteredReq = new IsExistingUserReq({ email })
8
9
  export const isRegisteredRes = new IsExistingUserRes({ existingUser: false })
9
10
  export const verifyEmailRes = new VerifyEmailRes({ principal: Fixtures.principal })
11
+ export const resendEmailReq: ResendEmail = { userId: '123', method: 'code' }
12
+ export const rpcResendEmailReq = new ResendEmailReq({ userId: '123', verifyEmail: { method: 'code' }})
13
+ export const rpcResendEmailRes = new ResendEmailRes({ })
10
14
 
11
15
  export const rpcClientTest = L.succeed(
12
16
  RpcClient,
@@ -1,9 +1,9 @@
1
- import { type RouterOps, RpcClient } from '@passlock/shared/dist/rpc/rpc.js'
1
+ import { RpcClient, type RouterOps } from '@passlock/shared/dist/rpc/rpc.js'
2
2
  import { Effect as E, Layer as L, Layer, LogLevel, Logger, pipe } from 'effect'
3
3
  import { describe, expect, test } from 'vitest'
4
4
  import { mock } from 'vitest-mock-extended'
5
- import { UserService, UserServiceLive } from './user.js'
6
5
  import * as Fixture from './user.fixture.js'
6
+ import { UserService, UserServiceLive } from './user.js'
7
7
 
8
8
  describe('isExistingUser should', () => {
9
9
  test('return true when the user already has a passkey', async () => {
@@ -50,3 +50,37 @@ describe('isExistingUser should', () => {
50
50
  return E.runPromise(effect)
51
51
  })
52
52
  })
53
+
54
+ describe('resendVerificationEmail should', () => {
55
+ test('forward the request to the backend', async () => {
56
+ const assertions = E.gen(function* (_) {
57
+ const service = yield* _(UserService)
58
+ yield* _(service.resendVerificationEmail(Fixture.resendEmailReq))
59
+
60
+ const rpcClient = yield* _(RpcClient)
61
+ expect(rpcClient.resendVerificationEmail).toBeCalledWith(Fixture.rpcResendEmailReq)
62
+ })
63
+
64
+ const rpcClientTest = Layer.effect(
65
+ RpcClient,
66
+ E.sync(() => {
67
+ const rpcMock = mock<RouterOps>()
68
+
69
+ rpcMock.resendVerificationEmail.mockReturnValue(E.succeed(Fixture.rpcResendEmailRes))
70
+
71
+ return rpcMock
72
+ }),
73
+ )
74
+
75
+ const service = pipe(UserServiceLive, L.provide(rpcClientTest))
76
+
77
+ const layers = L.merge(service, rpcClientTest)
78
+
79
+ const effect = pipe(
80
+ E.provide(assertions, layers),
81
+ Logger.withMinimumLogLevel(LogLevel.None)
82
+ )
83
+
84
+ return E.runPromise(effect)
85
+ })
86
+ })