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