@passlock/client 0.9.32 → 2.0.0-beta.2
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 +14 -86
- package/README.template.md +16 -88
- package/dist/index.d.ts +4 -206
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -158
- package/dist/index.js.map +1 -1
- package/dist/logger/index.d.ts +24 -0
- package/dist/logger/index.d.ts.map +1 -0
- package/dist/logger/index.js +47 -0
- package/dist/logger/index.js.map +1 -0
- package/dist/network.d.ts +39 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +83 -0
- package/dist/network.js.map +1 -0
- package/dist/passkey/authentication/index.d.ts +21 -0
- package/dist/passkey/authentication/index.d.ts.map +1 -0
- package/dist/passkey/authentication/index.js +22 -0
- package/dist/passkey/authentication/index.js.map +1 -0
- package/dist/passkey/authentication/micro.d.ts +71 -0
- package/dist/passkey/authentication/micro.d.ts.map +1 -0
- package/dist/passkey/authentication/micro.js +107 -0
- package/dist/passkey/authentication/micro.js.map +1 -0
- package/dist/passkey/index.d.ts +7 -0
- package/dist/passkey/index.d.ts.map +1 -0
- package/dist/passkey/index.js +5 -0
- package/dist/passkey/index.js.map +1 -0
- package/dist/passkey/registration/index.d.ts +19 -0
- package/dist/passkey/registration/index.d.ts.map +1 -0
- package/dist/passkey/registration/index.js +20 -0
- package/dist/passkey/registration/index.js.map +1 -0
- package/dist/passkey/registration/micro.d.ts +101 -0
- package/dist/passkey/registration/micro.d.ts.map +1 -0
- package/dist/passkey/registration/micro.js +126 -0
- package/dist/passkey/registration/micro.js.map +1 -0
- package/dist/passkey/shared.d.ts +24 -0
- package/dist/passkey/shared.d.ts.map +1 -0
- package/dist/passkey/shared.js +10 -0
- package/dist/passkey/shared.js.map +1 -0
- package/dist/passkey/support.d.ts +3 -0
- package/dist/passkey/support.d.ts.map +1 -0
- package/dist/passkey/support.js +4 -0
- package/dist/passkey/support.js.map +1 -0
- package/dist/passkey/types.d.ts +26 -0
- package/dist/passkey/types.d.ts.map +1 -0
- package/dist/passkey/types.js +2 -0
- package/dist/passkey/types.js.map +1 -0
- package/dist/promise.d.ts +15 -0
- package/dist/promise.d.ts.map +1 -0
- package/dist/promise.js +46 -0
- package/dist/promise.js.map +1 -0
- package/dist/shared.d.ts +15 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +2 -0
- package/dist/shared.js.map +1 -0
- package/dist/tenancy.d.ts +8 -0
- package/dist/tenancy.d.ts.map +1 -0
- package/dist/tenancy.js +4 -0
- package/dist/tenancy.js.map +1 -0
- package/package.json +52 -58
- package/LICENSE +0 -21
- package/dist/authentication/authenticate.d.ts +0 -23
- package/dist/authentication/authenticate.fixture.d.ts +0 -52
- package/dist/authentication/authenticate.fixture.js +0 -50
- package/dist/authentication/authenticate.fixture.js.map +0 -1
- package/dist/authentication/authenticate.js +0 -72
- package/dist/authentication/authenticate.js.map +0 -1
- package/dist/capabilities/capabilities.d.ts +0 -19
- package/dist/capabilities/capabilities.js +0 -37
- package/dist/capabilities/capabilities.js.map +0 -1
- package/dist/connection/connection.d.ts +0 -15
- package/dist/connection/connection.fixture.d.ts +0 -10
- package/dist/connection/connection.fixture.js +0 -13
- package/dist/connection/connection.fixture.js.map +0 -1
- package/dist/connection/connection.js +0 -23
- package/dist/connection/connection.js.map +0 -1
- package/dist/effect.d.ts +0 -26
- package/dist/effect.js +0 -78
- package/dist/effect.js.map +0 -1
- package/dist/email/email.d.ts +0 -70
- package/dist/email/email.fixture.d.ts +0 -46
- package/dist/email/email.fixture.js +0 -25
- package/dist/email/email.fixture.js.map +0 -1
- package/dist/email/email.js +0 -83
- package/dist/email/email.js.map +0 -1
- package/dist/event/event.d.ts +0 -8
- package/dist/event/event.js +0 -23
- package/dist/event/event.js.map +0 -1
- package/dist/logging/eventLogger.d.ts +0 -17
- package/dist/logging/eventLogger.js +0 -38
- package/dist/logging/eventLogger.js.map +0 -1
- package/dist/registration/register.d.ts +0 -25
- package/dist/registration/register.fixture.d.ts +0 -53
- package/dist/registration/register.fixture.js +0 -66
- package/dist/registration/register.fixture.js.map +0 -1
- package/dist/registration/register.js +0 -77
- package/dist/registration/register.js.map +0 -1
- package/dist/rpc/client.d.ts +0 -30
- package/dist/rpc/client.js +0 -101
- package/dist/rpc/client.js.map +0 -1
- package/dist/rpc/config.d.ts +0 -15
- package/dist/rpc/config.js +0 -6
- package/dist/rpc/config.js.map +0 -1
- package/dist/rpc/connection.d.ts +0 -8
- package/dist/rpc/connection.js +0 -16
- package/dist/rpc/connection.js.map +0 -1
- package/dist/rpc/passkey/authentication.d.ts +0 -8
- package/dist/rpc/passkey/authentication.js +0 -17
- package/dist/rpc/passkey/authentication.js.map +0 -1
- package/dist/rpc/passkey/registration.d.ts +0 -8
- package/dist/rpc/passkey/registration.js +0 -17
- package/dist/rpc/passkey/registration.js.map +0 -1
- package/dist/rpc/social.d.ts +0 -10
- package/dist/rpc/social.js +0 -19
- package/dist/rpc/social.js.map +0 -1
- package/dist/rpc/user.d.ts +0 -8
- package/dist/rpc/user.js +0 -20
- package/dist/rpc/user.js.map +0 -1
- package/dist/social/social.d.ts +0 -23
- package/dist/social/social.fixture.d.ts +0 -46
- package/dist/social/social.fixture.js +0 -31
- package/dist/social/social.fixture.js.map +0 -1
- package/dist/social/social.js +0 -38
- package/dist/social/social.js.map +0 -1
- package/dist/storage/storage.d.ts +0 -56
- package/dist/storage/storage.fixture.d.ts +0 -4
- package/dist/storage/storage.fixture.js +0 -10
- package/dist/storage/storage.fixture.js.map +0 -1
- package/dist/storage/storage.js +0 -111
- package/dist/storage/storage.js.map +0 -1
- package/dist/test/fixtures.d.ts +0 -15
- package/dist/test/fixtures.js +0 -56
- package/dist/test/fixtures.js.map +0 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
- package/dist/user/user.d.ts +0 -25
- package/dist/user/user.fixture.d.ts +0 -12
- package/dist/user/user.fixture.js +0 -20
- package/dist/user/user.fixture.js.map +0 -1
- package/dist/user/user.js +0 -37
- package/dist/user/user.js.map +0 -1
- package/dist/version.d.ts +0 -1
- package/dist/version.js +0 -2
- package/dist/version.js.map +0 -1
- package/src/authentication/authenticate.fixture.ts +0 -73
- package/src/authentication/authenticate.test.ts +0 -249
- package/src/authentication/authenticate.ts +0 -143
- package/src/capabilities/capabilities.ts +0 -83
- package/src/connection/connection.fixture.ts +0 -20
- package/src/connection/connection.test.ts +0 -60
- package/src/connection/connection.ts +0 -51
- package/src/effect.ts +0 -280
- package/src/email/email.fixture.ts +0 -44
- package/src/email/email.test.ts +0 -186
- package/src/email/email.ts +0 -148
- package/src/event/event.node.test.ts +0 -21
- package/src/event/event.test.ts +0 -37
- package/src/event/event.ts +0 -25
- package/src/index.ts +0 -407
- package/src/logging/eventLogger.test.ts +0 -104
- package/src/logging/eventLogger.ts +0 -41
- package/src/registration/register.fixture.ts +0 -96
- package/src/registration/register.test.ts +0 -216
- package/src/registration/register.ts +0 -156
- package/src/rpc/client.ts +0 -174
- package/src/rpc/config.ts +0 -18
- package/src/rpc/connection.ts +0 -32
- package/src/rpc/passkey/authentication.ts +0 -52
- package/src/rpc/passkey/registration.ts +0 -52
- package/src/rpc/social.ts +0 -55
- package/src/rpc/user.ts +0 -68
- package/src/social/social.fixture.ts +0 -44
- package/src/social/social.test.ts +0 -179
- package/src/social/social.ts +0 -79
- package/src/storage/storage.fixture.ts +0 -16
- package/src/storage/storage.test.ts +0 -206
- package/src/storage/storage.ts +0 -168
- package/src/test/fixtures.ts +0 -70
- package/src/user/user.fixture.ts +0 -33
- package/src/user/user.test.ts +0 -84
- package/src/user/user.ts +0 -71
- package/src/version.ts +0 -1
package/src/email/email.ts
DELETED
|
@@ -1,148 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Email verification effects
|
|
3
|
-
*/
|
|
4
|
-
import { Context, Effect as E, Layer, Option as O, flow, identity, pipe } from 'effect'
|
|
5
|
-
|
|
6
|
-
import { BadRequest } from '@passlock/shared/dist/error/error.js'
|
|
7
|
-
import type { VerifyEmailErrors as RpcErrors } from '@passlock/shared/dist/rpc/user.js'
|
|
8
|
-
import { VerifyEmailRequest } from '@passlock/shared/dist/rpc/user.js'
|
|
9
|
-
import type { Principal } from '@passlock/shared/dist/schema/principal.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'
|
|
14
|
-
|
|
15
|
-
/* Requests */
|
|
16
|
-
|
|
17
|
-
export type VerifyRequest = {
|
|
18
|
-
code: string
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/* Errors */
|
|
22
|
-
|
|
23
|
-
export type VerifyEmailErrors = RpcErrors | AuthenticationErrors
|
|
24
|
-
|
|
25
|
-
/* Dependencies */
|
|
26
|
-
|
|
27
|
-
export class URLQueryString extends Context.Tag('@utils/URLQueryString')<
|
|
28
|
-
URLQueryString,
|
|
29
|
-
E.Effect<string>
|
|
30
|
-
>() {}
|
|
31
|
-
|
|
32
|
-
/* Service */
|
|
33
|
-
|
|
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
|
-
>() {}
|
|
41
|
-
|
|
42
|
-
/* Utils */
|
|
43
|
-
|
|
44
|
-
export type Dependencies = StorageService | AuthenticationService | UserClient
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Check for existing token in sessionStorage,
|
|
48
|
-
* otherwise force passkey re-authentication
|
|
49
|
-
* @returns
|
|
50
|
-
*/
|
|
51
|
-
const getToken = () => {
|
|
52
|
-
return E.gen(function* (_) {
|
|
53
|
-
// Check for existing token
|
|
54
|
-
const storageService = yield* _(StorageService)
|
|
55
|
-
const existingTokenE = storageService.getToken('passkey')
|
|
56
|
-
const authenticationService = yield* _(AuthenticationService)
|
|
57
|
-
|
|
58
|
-
const tokenE = E.matchEffect(existingTokenE, {
|
|
59
|
-
onSuccess: token => E.succeed(token),
|
|
60
|
-
onFailure: () =>
|
|
61
|
-
// No token, need to authenticate the user
|
|
62
|
-
pipe(
|
|
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
|
-
),
|
|
75
|
-
),
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
const token = yield* _(tokenE)
|
|
79
|
-
yield* _(storageService.clearToken('passkey'))
|
|
80
|
-
|
|
81
|
-
return token
|
|
82
|
-
})
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Look for ?code=<code> in the url
|
|
87
|
-
* @returns
|
|
88
|
-
*/
|
|
89
|
-
export const extractCodeFromHref = () => {
|
|
90
|
-
return pipe(
|
|
91
|
-
URLQueryString,
|
|
92
|
-
E.flatMap(identity),
|
|
93
|
-
E.map(search => new URLSearchParams(search)),
|
|
94
|
-
E.flatMap(params => O.fromNullable(params.get('code'))),
|
|
95
|
-
)
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
/* Effects */
|
|
99
|
-
|
|
100
|
-
/**
|
|
101
|
-
* Verify the mailbox using the given code
|
|
102
|
-
* @param request
|
|
103
|
-
* @returns
|
|
104
|
-
*/
|
|
105
|
-
export const verifyEmail = (
|
|
106
|
-
request: VerifyRequest,
|
|
107
|
-
): E.Effect<Principal, VerifyEmailErrors, Dependencies> => {
|
|
108
|
-
return E.gen(function* (_) {
|
|
109
|
-
// Re-authenticate the user if required
|
|
110
|
-
const { token } = yield* _(getToken())
|
|
111
|
-
|
|
112
|
-
yield* _(E.logDebug('Making request'))
|
|
113
|
-
const client = yield* _(UserClient)
|
|
114
|
-
const { principal } = yield* _(
|
|
115
|
-
client.verifyEmail(new VerifyEmailRequest({ token, code: request.code })),
|
|
116
|
-
)
|
|
117
|
-
|
|
118
|
-
return principal
|
|
119
|
-
})
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
/**
|
|
123
|
-
* Look for a code in the current url and verify it
|
|
124
|
-
* @returns
|
|
125
|
-
*/
|
|
126
|
-
export const verifyEmailLink = () =>
|
|
127
|
-
pipe(
|
|
128
|
-
extractCodeFromHref(),
|
|
129
|
-
E.mapError(() => new BadRequest({ message: 'Expected ?code=xxx in window.location' })),
|
|
130
|
-
E.flatMap(code => verifyEmail({ code })),
|
|
131
|
-
)
|
|
132
|
-
|
|
133
|
-
/* Live */
|
|
134
|
-
|
|
135
|
-
/* v8 ignore start */
|
|
136
|
-
export const EmailServiceLive = Layer.effect(
|
|
137
|
-
EmailService,
|
|
138
|
-
E.gen(function* (_) {
|
|
139
|
-
const context = yield* _(
|
|
140
|
-
E.context<UserClient | AuthenticationService | StorageService | URLQueryString>(),
|
|
141
|
-
)
|
|
142
|
-
return EmailService.of({
|
|
143
|
-
verifyEmailCode: flow(verifyEmail, E.provide(context)),
|
|
144
|
-
verifyEmailLink: flow(verifyEmailLink, E.provide(context)),
|
|
145
|
-
})
|
|
146
|
-
}),
|
|
147
|
-
)
|
|
148
|
-
/* v8 ignore stop */
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { Effect, pipe } from 'effect'
|
|
2
|
-
import { describe, expect, test } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { fireEvent } from './event.js'
|
|
5
|
-
|
|
6
|
-
// @vitest-environment node
|
|
7
|
-
|
|
8
|
-
describe('isPasslockEvent', () => {
|
|
9
|
-
test("return a Passlock error if custom events aren't supported", async () => {
|
|
10
|
-
const program = pipe(
|
|
11
|
-
fireEvent('hello world'),
|
|
12
|
-
Effect.flip,
|
|
13
|
-
Effect.tap(e => {
|
|
14
|
-
expect(e._tag).toBe('InternalBrowserError')
|
|
15
|
-
expect(e.message).toBe('Unable to fire custom event')
|
|
16
|
-
}),
|
|
17
|
-
)
|
|
18
|
-
|
|
19
|
-
await Effect.runPromise(program)
|
|
20
|
-
})
|
|
21
|
-
})
|
package/src/event/event.test.ts
DELETED
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { Effect } from 'effect'
|
|
2
|
-
import { afterEach, describe, expect, test, vi } from 'vitest'
|
|
3
|
-
|
|
4
|
-
import { DebugMessage, fireEvent, isPasslockEvent } from './event.js'
|
|
5
|
-
|
|
6
|
-
describe('fireEvent', () => {
|
|
7
|
-
afterEach(() => {
|
|
8
|
-
vi.restoreAllMocks()
|
|
9
|
-
})
|
|
10
|
-
|
|
11
|
-
test('fire a custom log event', () => {
|
|
12
|
-
const effect = fireEvent('hello world')
|
|
13
|
-
const eventSpy = vi.spyOn(globalThis, 'dispatchEvent')
|
|
14
|
-
Effect.runSync(effect)
|
|
15
|
-
|
|
16
|
-
const expectedEvent = new CustomEvent(DebugMessage, {
|
|
17
|
-
detail: 'hello world',
|
|
18
|
-
})
|
|
19
|
-
|
|
20
|
-
expect(eventSpy).toHaveBeenCalledWith(expectedEvent)
|
|
21
|
-
})
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
describe('isPasslockEvent', () => {
|
|
25
|
-
test('return true for our custom event', () => {
|
|
26
|
-
const passlockEvent = new CustomEvent(DebugMessage, {
|
|
27
|
-
detail: 'hello world',
|
|
28
|
-
})
|
|
29
|
-
|
|
30
|
-
expect(isPasslockEvent(passlockEvent)).toBe(true)
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('return false for other events', () => {
|
|
34
|
-
const otherEvent = new MouseEvent('click')
|
|
35
|
-
expect(isPasslockEvent(otherEvent)).toBe(false)
|
|
36
|
-
})
|
|
37
|
-
})
|
package/src/event/event.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Fire DOM events
|
|
3
|
-
*/
|
|
4
|
-
import { Effect } from 'effect'
|
|
5
|
-
|
|
6
|
-
import { InternalBrowserError } from '@passlock/shared/dist/error/error.js'
|
|
7
|
-
|
|
8
|
-
export const DebugMessage = 'PasslogDebugMessage'
|
|
9
|
-
|
|
10
|
-
export const fireEvent = (message: string) => {
|
|
11
|
-
return Effect.try({
|
|
12
|
-
try: () => {
|
|
13
|
-
const evt = new CustomEvent(DebugMessage, { detail: message })
|
|
14
|
-
globalThis.dispatchEvent(evt)
|
|
15
|
-
},
|
|
16
|
-
catch: () => {
|
|
17
|
-
return new InternalBrowserError({ message: 'Unable to fire custom event' })
|
|
18
|
-
},
|
|
19
|
-
})
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function isPasslockEvent(event: Event): event is CustomEvent {
|
|
23
|
-
if (event.type !== DebugMessage) return false
|
|
24
|
-
return 'detail' in event
|
|
25
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,407 +0,0 @@
|
|
|
1
|
-
import { Effect as E, Layer as L, Layer, Option as O, Runtime, Scope, pipe } from 'effect'
|
|
2
|
-
import { dual } from 'effect/Function'
|
|
3
|
-
|
|
4
|
-
import type {
|
|
5
|
-
BadRequest,
|
|
6
|
-
Disabled,
|
|
7
|
-
Duplicate,
|
|
8
|
-
Forbidden,
|
|
9
|
-
NotFound,
|
|
10
|
-
NotSupported,
|
|
11
|
-
Unauthorized,
|
|
12
|
-
} from '@passlock/shared/dist/error/error.js'
|
|
13
|
-
import { ErrorCode } from '@passlock/shared/dist/error/error.js'
|
|
14
|
-
import type { VerifyEmail } from '@passlock/shared/dist/schema/email.js'
|
|
15
|
-
import type { UserVerification } from '@passlock/shared/dist/schema/passkey.js'
|
|
16
|
-
import {
|
|
17
|
-
type Principal,
|
|
18
|
-
type UserPrincipal,
|
|
19
|
-
isPrincipal,
|
|
20
|
-
isUserPrincipal,
|
|
21
|
-
} from '@passlock/shared/dist/schema/principal.js'
|
|
22
|
-
|
|
23
|
-
import type { AuthenticationService } from './authentication/authenticate.js'
|
|
24
|
-
import type { Capabilities } from './capabilities/capabilities.js'
|
|
25
|
-
import type { ConnectionService } from './connection/connection.js'
|
|
26
|
-
import {
|
|
27
|
-
allRequirements,
|
|
28
|
-
authenticateOidc,
|
|
29
|
-
authenticatePasskey,
|
|
30
|
-
clearExpiredTokens,
|
|
31
|
-
getSessionToken,
|
|
32
|
-
isExistingUser,
|
|
33
|
-
isPasskeySupport,
|
|
34
|
-
preConnect,
|
|
35
|
-
registerOidc,
|
|
36
|
-
registerPasskey,
|
|
37
|
-
resendVerificationEmail,
|
|
38
|
-
verifyEmailCode,
|
|
39
|
-
verifyEmailLink,
|
|
40
|
-
} from './effect.js'
|
|
41
|
-
import type { EmailService, VerifyRequest } from './email/email.js'
|
|
42
|
-
import type { RegistrationService } from './registration/register.js'
|
|
43
|
-
import { RpcConfig } from './rpc/config.js'
|
|
44
|
-
import type { Provider, SocialService } from './social/social.js'
|
|
45
|
-
import {
|
|
46
|
-
type AuthType,
|
|
47
|
-
BrowserStorage,
|
|
48
|
-
StorageService,
|
|
49
|
-
type StoredToken,
|
|
50
|
-
} from './storage/storage.js'
|
|
51
|
-
import type { Email, ResendEmail, UserService } from './user/user.js'
|
|
52
|
-
import { PASSLOCK_CLIENT_VERSION } from './version.js'
|
|
53
|
-
|
|
54
|
-
/* Exports */
|
|
55
|
-
|
|
56
|
-
export type Options = { signal?: AbortSignal }
|
|
57
|
-
export type { VerifyEmail } from '@passlock/shared/dist/schema/email.js'
|
|
58
|
-
export type { UserVerification } from '@passlock/shared/dist/schema/passkey.js'
|
|
59
|
-
export type { Principal, UserPrincipal } from '@passlock/shared/dist/schema/principal.js'
|
|
60
|
-
|
|
61
|
-
export type { VerifyRequest } from './email/email.js'
|
|
62
|
-
export type { AuthType, StoredToken } from './storage/storage.js'
|
|
63
|
-
export type { Email } from './user/user.js'
|
|
64
|
-
|
|
65
|
-
export type PasslockProps = {
|
|
66
|
-
tenancyId: string
|
|
67
|
-
clientId: string
|
|
68
|
-
endpoint?: string
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
export type RegistrationRequest = {
|
|
72
|
-
email: string
|
|
73
|
-
givenName?: string
|
|
74
|
-
familyName?: string
|
|
75
|
-
userVerification?: UserVerification
|
|
76
|
-
verifyEmail?: VerifyEmail
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const nonEmpty = (text: string): O.Option<string> => {
|
|
80
|
-
const trimmed = text.trim()
|
|
81
|
-
if (trimmed.length > 0) return O.some(trimmed)
|
|
82
|
-
return O.none()
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
const toRpcRegistrationRequest = (request: RegistrationRequest) => {
|
|
86
|
-
return {
|
|
87
|
-
email: request.email,
|
|
88
|
-
givenName: pipe(O.fromNullable(request.givenName), O.flatMap(nonEmpty)),
|
|
89
|
-
familyName: pipe(O.fromNullable(request.familyName), O.flatMap(nonEmpty)),
|
|
90
|
-
userVerification: O.fromNullable(request.userVerification),
|
|
91
|
-
verifyEmail: O.fromNullable(request.verifyEmail),
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
export type AuthenticationRequest = {
|
|
96
|
-
email?: string
|
|
97
|
-
userVerification?: UserVerification
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const toRpcAuthenticationRequest = (request: AuthenticationRequest) => {
|
|
101
|
-
return {
|
|
102
|
-
email: O.fromNullable(request.email),
|
|
103
|
-
userVerification: O.fromNullable(request.userVerification),
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
export type RegisterOidcReq = {
|
|
108
|
-
provider: Provider
|
|
109
|
-
idToken: string
|
|
110
|
-
givenName?: string
|
|
111
|
-
familyName?: string
|
|
112
|
-
nonce: string
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
const toRpcRegisterOidcReq = (request: RegisterOidcReq) => {
|
|
116
|
-
return {
|
|
117
|
-
provider: request.provider,
|
|
118
|
-
idToken: request.idToken,
|
|
119
|
-
givenName: pipe(O.fromNullable(request.givenName), O.flatMap(nonEmpty)),
|
|
120
|
-
familyName: pipe(O.fromNullable(request.familyName), O.flatMap(nonEmpty)),
|
|
121
|
-
nonce: request.nonce,
|
|
122
|
-
}
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
export type AuthenticateOidcReq = {
|
|
126
|
-
provider: Provider
|
|
127
|
-
idToken: string
|
|
128
|
-
nonce: string
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
const toRpcAuthenticateOidcReq = (request: AuthenticateOidcReq) => {
|
|
132
|
-
return {
|
|
133
|
-
provider: request.provider,
|
|
134
|
-
idToken: request.idToken,
|
|
135
|
-
nonce: request.nonce,
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
export { ErrorCode } from '@passlock/shared/dist/error/error.js'
|
|
140
|
-
|
|
141
|
-
export class PasslockError extends Error {
|
|
142
|
-
readonly code: ErrorCode
|
|
143
|
-
readonly detail: string | undefined
|
|
144
|
-
|
|
145
|
-
constructor(message: string, code: ErrorCode, detail?: string) {
|
|
146
|
-
super(message)
|
|
147
|
-
this.code = code
|
|
148
|
-
this.detail = detail
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
static readonly isError = (error: unknown): error is PasslockError => {
|
|
152
|
-
return typeof error === 'object' && error !== null && error instanceof PasslockError
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
/* // Exports */
|
|
157
|
-
|
|
158
|
-
type PasslockErrors =
|
|
159
|
-
| BadRequest
|
|
160
|
-
| NotSupported
|
|
161
|
-
| Duplicate
|
|
162
|
-
| Unauthorized
|
|
163
|
-
| Forbidden
|
|
164
|
-
| Disabled
|
|
165
|
-
| NotFound
|
|
166
|
-
|
|
167
|
-
const hasMessage = (defect: unknown): defect is { message: string } => {
|
|
168
|
-
return (
|
|
169
|
-
typeof defect === 'object' &&
|
|
170
|
-
defect !== null &&
|
|
171
|
-
'message' in defect &&
|
|
172
|
-
typeof defect['message'] === 'string'
|
|
173
|
-
)
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
const transformErrors = <A, R>(
|
|
177
|
-
effect: E.Effect<A, PasslockErrors, R>,
|
|
178
|
-
): E.Effect<A | PasslockError, never, R> => {
|
|
179
|
-
const withErrorHandling = E.catchTags(effect, {
|
|
180
|
-
NotSupported: e => E.succeed(new PasslockError(e.message, ErrorCode.NotSupported)),
|
|
181
|
-
BadRequest: e => E.succeed(new PasslockError(e.message, ErrorCode.BadRequest, e.detail)),
|
|
182
|
-
Duplicate: e => E.succeed(new PasslockError(e.message, ErrorCode.Duplicate, e.detail)),
|
|
183
|
-
Unauthorized: e => E.succeed(new PasslockError(e.message, ErrorCode.Unauthorized, e.detail)),
|
|
184
|
-
Forbidden: e => E.succeed(new PasslockError(e.message, ErrorCode.Forbidden, e.detail)),
|
|
185
|
-
Disabled: e => E.succeed(new PasslockError(e.message, ErrorCode.Disabled, e.detail)),
|
|
186
|
-
NotFound: e => E.succeed(new PasslockError(e.message, ErrorCode.NotFound, e.detail)),
|
|
187
|
-
})
|
|
188
|
-
|
|
189
|
-
const sandboxed = E.sandbox(withErrorHandling)
|
|
190
|
-
|
|
191
|
-
const withSandboxing = E.catchTags(sandboxed, {
|
|
192
|
-
Die: ({ defect }) => {
|
|
193
|
-
return hasMessage(defect)
|
|
194
|
-
? E.succeed(new PasslockError(defect.message, ErrorCode.InternalServerError))
|
|
195
|
-
: E.succeed(new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError))
|
|
196
|
-
},
|
|
197
|
-
|
|
198
|
-
Interrupt: () => {
|
|
199
|
-
console.error('Interrupt')
|
|
200
|
-
return E.succeed(new PasslockError('Operation aborted', ErrorCode.InternalBrowserError))
|
|
201
|
-
},
|
|
202
|
-
|
|
203
|
-
Sequential: errors => {
|
|
204
|
-
console.error(errors)
|
|
205
|
-
|
|
206
|
-
return E.succeed(
|
|
207
|
-
new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError),
|
|
208
|
-
)
|
|
209
|
-
},
|
|
210
|
-
|
|
211
|
-
Parallel: errors => {
|
|
212
|
-
console.error(errors)
|
|
213
|
-
|
|
214
|
-
return E.succeed(
|
|
215
|
-
new PasslockError('Sorry, something went wrong', ErrorCode.InternalServerError),
|
|
216
|
-
)
|
|
217
|
-
},
|
|
218
|
-
})
|
|
219
|
-
|
|
220
|
-
return E.unsandbox(withSandboxing)
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
type Requirements =
|
|
224
|
-
| UserService
|
|
225
|
-
| RegistrationService
|
|
226
|
-
| AuthenticationService
|
|
227
|
-
| ConnectionService
|
|
228
|
-
| EmailService
|
|
229
|
-
| StorageService
|
|
230
|
-
| Capabilities
|
|
231
|
-
| SocialService
|
|
232
|
-
| RpcConfig
|
|
233
|
-
|
|
234
|
-
export class PasslockUnsafe {
|
|
235
|
-
private readonly runtime: Runtime.Runtime<Requirements>
|
|
236
|
-
|
|
237
|
-
constructor(props: PasslockProps) {
|
|
238
|
-
const config = Layer.succeed(RpcConfig, RpcConfig.of(props))
|
|
239
|
-
const storage = Layer.succeed(BrowserStorage, BrowserStorage.of(globalThis.localStorage))
|
|
240
|
-
const allLayers = pipe(allRequirements, L.provide(config), L.provide(storage), L.merge(config))
|
|
241
|
-
const scope = E.runSync(Scope.make())
|
|
242
|
-
|
|
243
|
-
this.runtime = E.runSync(Layer.toRuntime(allLayers).pipe(Scope.extend(scope)))
|
|
244
|
-
|
|
245
|
-
E.runSync(E.logDebug(`Passlock version: ${PASSLOCK_CLIENT_VERSION}`))
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
static isPrincipal = (value: unknown): value is Principal => isPrincipal(value)
|
|
249
|
-
static isUserPrincipal = (value: unknown): value is UserPrincipal => isUserPrincipal(value)
|
|
250
|
-
|
|
251
|
-
private readonly runPromise: {
|
|
252
|
-
<A, R extends Requirements>(
|
|
253
|
-
options: Options | undefined,
|
|
254
|
-
): (effect: E.Effect<A, PasslockErrors, R>) => Promise<A>
|
|
255
|
-
<A, R extends Requirements>(
|
|
256
|
-
effect: E.Effect<A, PasslockErrors, R>,
|
|
257
|
-
options: Options | undefined,
|
|
258
|
-
): Promise<A>
|
|
259
|
-
} = dual(
|
|
260
|
-
2,
|
|
261
|
-
<A, R extends Requirements>(
|
|
262
|
-
effect: E.Effect<A, PasslockErrors, R>,
|
|
263
|
-
options: Options | undefined,
|
|
264
|
-
): Promise<A> =>
|
|
265
|
-
pipe(
|
|
266
|
-
transformErrors(effect),
|
|
267
|
-
E.flatMap(result => (PasslockError.isError(result) ? E.fail(result) : E.succeed(result))),
|
|
268
|
-
effect => Runtime.runPromise(this.runtime)(effect, options),
|
|
269
|
-
),
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
preConnect = (options?: Options): Promise<void> => pipe(preConnect(), this.runPromise(options))
|
|
273
|
-
|
|
274
|
-
isPasskeySupport = (): Promise<boolean> =>
|
|
275
|
-
pipe(isPasskeySupport, effect => Runtime.runPromise(this.runtime)(effect))
|
|
276
|
-
|
|
277
|
-
isExistingUser = (email: Email, options?: Options): Promise<boolean> =>
|
|
278
|
-
pipe(isExistingUser(email), this.runPromise(options))
|
|
279
|
-
|
|
280
|
-
registerPasskey = (request: RegistrationRequest, options?: Options): Promise<Principal> =>
|
|
281
|
-
pipe(registerPasskey(toRpcRegistrationRequest(request)), this.runPromise(options))
|
|
282
|
-
|
|
283
|
-
authenticatePasskey = (request: AuthenticationRequest, options?: Options): Promise<Principal> =>
|
|
284
|
-
pipe(authenticatePasskey(toRpcAuthenticationRequest(request)), this.runPromise(options))
|
|
285
|
-
|
|
286
|
-
registerOidc = (request: RegisterOidcReq, options?: Options) =>
|
|
287
|
-
pipe(registerOidc(toRpcRegisterOidcReq(request)), this.runPromise(options))
|
|
288
|
-
|
|
289
|
-
authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
|
|
290
|
-
pipe(authenticateOidc(toRpcAuthenticateOidcReq(request)), this.runPromise(options))
|
|
291
|
-
|
|
292
|
-
verifyEmailCode = (request: VerifyRequest, options?: Options): Promise<Principal> =>
|
|
293
|
-
pipe(verifyEmailCode(request), this.runPromise(options))
|
|
294
|
-
|
|
295
|
-
resendVerificationEmail = (request: ResendEmail, options?: Options): Promise<void> =>
|
|
296
|
-
pipe(resendVerificationEmail(request), this.runPromise(options))
|
|
297
|
-
|
|
298
|
-
verifyEmailLink = (options?: Options): Promise<Principal> =>
|
|
299
|
-
pipe(verifyEmailLink, this.runPromise(options))
|
|
300
|
-
|
|
301
|
-
getSessionToken = (authType: AuthType): StoredToken | undefined =>
|
|
302
|
-
pipe(
|
|
303
|
-
getSessionToken(authType),
|
|
304
|
-
E.orElseSucceed(() => undefined),
|
|
305
|
-
effect => Runtime.runSync(this.runtime)(effect),
|
|
306
|
-
)
|
|
307
|
-
|
|
308
|
-
clearExpiredTokens = (): void => {
|
|
309
|
-
pipe(clearExpiredTokens, effect => {
|
|
310
|
-
Runtime.runSync(this.runtime)(effect)
|
|
311
|
-
})
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
|
|
315
|
-
export class Passlock {
|
|
316
|
-
private readonly runtime: Runtime.Runtime<Requirements>
|
|
317
|
-
|
|
318
|
-
constructor(props: PasslockProps) {
|
|
319
|
-
const config = Layer.succeed(RpcConfig, RpcConfig.of(props))
|
|
320
|
-
const storage = Layer.succeed(BrowserStorage, BrowserStorage.of(globalThis.localStorage))
|
|
321
|
-
const allLayers = pipe(allRequirements, L.provide(config), L.provide(storage), L.merge(config))
|
|
322
|
-
const scope = E.runSync(Scope.make())
|
|
323
|
-
|
|
324
|
-
this.runtime = E.runSync(Layer.toRuntime(allLayers).pipe(Scope.extend(scope)))
|
|
325
|
-
|
|
326
|
-
E.runSync(E.logDebug(`Passlock version: ${PASSLOCK_CLIENT_VERSION}`))
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
static isPrincipal = (value: unknown): value is Principal => isPrincipal(value)
|
|
330
|
-
static isUserPrincipal = (value: unknown): value is UserPrincipal => isUserPrincipal(value)
|
|
331
|
-
|
|
332
|
-
private readonly runPromise: {
|
|
333
|
-
<A, R extends Requirements>(
|
|
334
|
-
options: Options | undefined,
|
|
335
|
-
): (effect: E.Effect<A, PasslockErrors, R>) => Promise<A | PasslockError>
|
|
336
|
-
<A, R extends Requirements>(
|
|
337
|
-
effect: E.Effect<A, PasslockErrors, R>,
|
|
338
|
-
options: Options | undefined,
|
|
339
|
-
): Promise<A | PasslockError>
|
|
340
|
-
} = dual(
|
|
341
|
-
2,
|
|
342
|
-
<A, R extends Requirements>(
|
|
343
|
-
effect: E.Effect<A, PasslockErrors, R>,
|
|
344
|
-
options: Options | undefined,
|
|
345
|
-
): Promise<A | PasslockError> =>
|
|
346
|
-
pipe(transformErrors(effect), effect => Runtime.runPromise(this.runtime)(effect, options)),
|
|
347
|
-
)
|
|
348
|
-
|
|
349
|
-
preConnect = async (options?: Options): Promise<boolean | PasslockError> => {
|
|
350
|
-
return pipe(preConnect(), E.as(true), this.runPromise(options))
|
|
351
|
-
}
|
|
352
|
-
|
|
353
|
-
isPasskeySupport = (): Promise<boolean> =>
|
|
354
|
-
pipe(isPasskeySupport, effect => Runtime.runPromise(this.runtime)(effect))
|
|
355
|
-
|
|
356
|
-
isExistingUser = (email: Email, options?: Options): Promise<boolean | PasslockError> =>
|
|
357
|
-
pipe(isExistingUser(email), this.runPromise(options))
|
|
358
|
-
|
|
359
|
-
registerPasskey = (
|
|
360
|
-
request: RegistrationRequest,
|
|
361
|
-
options?: Options,
|
|
362
|
-
): Promise<Principal | PasslockError> =>
|
|
363
|
-
pipe(registerPasskey(toRpcRegistrationRequest(request)), this.runPromise(options))
|
|
364
|
-
|
|
365
|
-
authenticatePasskey = (
|
|
366
|
-
request: AuthenticationRequest = {},
|
|
367
|
-
options?: Options,
|
|
368
|
-
): Promise<Principal | PasslockError> =>
|
|
369
|
-
pipe(toRpcAuthenticationRequest(request), authenticatePasskey, this.runPromise(options))
|
|
370
|
-
|
|
371
|
-
registerOidc = (request: RegisterOidcReq, options?: Options) =>
|
|
372
|
-
pipe(registerOidc(toRpcRegisterOidcReq(request)), this.runPromise(options))
|
|
373
|
-
|
|
374
|
-
authenticateOidc = (request: AuthenticateOidcReq, options?: Options) =>
|
|
375
|
-
pipe(authenticateOidc(request), this.runPromise(options))
|
|
376
|
-
|
|
377
|
-
verifyEmailCode = (
|
|
378
|
-
request: VerifyRequest,
|
|
379
|
-
options?: Options,
|
|
380
|
-
): Promise<Principal | PasslockError> => pipe(verifyEmailCode(request), this.runPromise(options))
|
|
381
|
-
|
|
382
|
-
verifyEmailLink = (options?: Options): Promise<Principal | PasslockError> =>
|
|
383
|
-
pipe(verifyEmailLink, this.runPromise(options))
|
|
384
|
-
|
|
385
|
-
resendVerificationEmail = (
|
|
386
|
-
request: ResendEmail,
|
|
387
|
-
options?: Options,
|
|
388
|
-
): Promise<boolean | PasslockError> =>
|
|
389
|
-
pipe(resendVerificationEmail(request), E.as(true), this.runPromise(options))
|
|
390
|
-
|
|
391
|
-
getSessionToken = (authType: AuthType): Promise<StoredToken | undefined> =>
|
|
392
|
-
pipe(
|
|
393
|
-
getSessionToken(authType),
|
|
394
|
-
E.orElseSucceed(() => undefined),
|
|
395
|
-
effect => E.runPromise(effect),
|
|
396
|
-
)
|
|
397
|
-
|
|
398
|
-
clearExpiredTokens = (): void => {
|
|
399
|
-
pipe(
|
|
400
|
-
StorageService,
|
|
401
|
-
E.flatMap(service => service.clearExpiredTokens),
|
|
402
|
-
effect => {
|
|
403
|
-
Runtime.runSync(this.runtime)(effect)
|
|
404
|
-
},
|
|
405
|
-
)
|
|
406
|
-
}
|
|
407
|
-
}
|