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