@passlock/server 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (45) hide show
  1. package/dist/effect.d.ts +8 -0
  2. package/dist/effect.d.ts.map +1 -1
  3. package/dist/effect.js +8 -0
  4. package/dist/effect.js.map +1 -1
  5. package/dist/errors.d.ts +65 -0
  6. package/dist/errors.d.ts.map +1 -1
  7. package/dist/errors.js +36 -5
  8. package/dist/errors.js.map +1 -1
  9. package/dist/index.d.ts +63 -21
  10. package/dist/index.d.ts.map +1 -1
  11. package/dist/index.js +60 -18
  12. package/dist/index.js.map +1 -1
  13. package/dist/network.d.ts +3 -3
  14. package/dist/passkey/passkey.d.ts +267 -10
  15. package/dist/passkey/passkey.d.ts.map +1 -1
  16. package/dist/passkey/passkey.js +161 -5
  17. package/dist/passkey/passkey.js.map +1 -1
  18. package/dist/principal/principal.d.ts +45 -1
  19. package/dist/principal/principal.d.ts.map +1 -1
  20. package/dist/principal/principal.js +27 -0
  21. package/dist/principal/principal.js.map +1 -1
  22. package/dist/safe-result.d.ts +33 -0
  23. package/dist/safe-result.d.ts.map +1 -0
  24. package/dist/safe-result.js +35 -0
  25. package/dist/safe-result.js.map +1 -0
  26. package/dist/safe.d.ts +87 -30
  27. package/dist/safe.d.ts.map +1 -1
  28. package/dist/safe.js +90 -30
  29. package/dist/safe.js.map +1 -1
  30. package/dist/schemas/passkey.d.ts +160 -0
  31. package/dist/schemas/passkey.d.ts.map +1 -1
  32. package/dist/schemas/passkey.js +90 -12
  33. package/dist/schemas/passkey.js.map +1 -1
  34. package/dist/schemas/principal.d.ts +50 -0
  35. package/dist/schemas/principal.d.ts.map +1 -1
  36. package/dist/schemas/principal.js +30 -0
  37. package/dist/schemas/principal.js.map +1 -1
  38. package/dist/schemas/signup.d.ts +20 -0
  39. package/dist/schemas/signup.d.ts.map +1 -1
  40. package/dist/schemas/signup.js +10 -0
  41. package/dist/schemas/signup.js.map +1 -1
  42. package/dist/shared.d.ts +18 -0
  43. package/dist/shared.d.ts.map +1 -1
  44. package/dist/shared.js.map +1 -1
  45. package/package.json +6 -6
package/dist/safe.d.ts CHANGED
@@ -1,19 +1,46 @@
1
1
  /**
2
- * Safe functions that return discriminated unions representing
3
- * the successful outcome or expected failures.
2
+ * Safe functions that return result envelopes over the original
3
+ * tagged success and error payloads. The returned value keeps
4
+ * its original `_tag` shape, and is also augmented with a
5
+ * result envelope for `success`- or `failure`-style branching.
4
6
  *
5
7
  * Note: unexpected runtime failures may still throw.
6
8
  *
9
+ * ```ts
10
+ * const result = await exchangeCode({
11
+ * apiKey,
12
+ * code,
13
+ * tenancyId,
14
+ * })
15
+ *
16
+ * if (result.success) {
17
+ * console.log(result.value.id)
18
+ * }
19
+ *
20
+ * if (result.failure) {
21
+ * console.log(result.error.message)
22
+ * }
23
+ *
24
+ * if (isExtendedPrincipal(result)) {
25
+ * console.log(result.id)
26
+ * }
27
+ * ```
28
+ *
7
29
  * @categoryDescription Passkeys
8
- * Functions and related types for managing passkeys
30
+ * Functions and related types for managing passkeys.
31
+ *
32
+ * @categoryDescription Principal
33
+ * Functions and related types for exchanging client codes and verifying
34
+ * Passlock tokens.
9
35
  *
10
36
  * @showCategories
11
37
  *
12
38
  * @module safe
13
39
  */
14
40
  import type { ForbiddenError, InvalidCodeError, NotFoundError, VerificationError } from "./errors.js";
15
- import type { AssignUserOptions, DeletePasskeyOptions, FindAllPasskeys, GetPasskeyOptions, ListPasskeyOptions, Passkey, UpdatedPasskeyUsernames, UpdatePasskeyOptions, UpdatePasskeyUsernamesOptions } from "./passkey/passkey.js";
41
+ import type { AssignUserOptions, DeletedPasskey, DeletedPasskeys, DeletePasskeyOptions, DeleteUserPasskeysOptions, FindAllPasskeys, GetPasskeyOptions, ListPasskeyOptions, Passkey, UpdatedCredentials, UpdatePasskeyOptions, UpdateUsernamesOptions } from "./passkey/passkey.js";
16
42
  import type { ExchangeCodeOptions, VerifyIdTokenOptions } from "./principal/principal.js";
43
+ import { type Result } from "./safe-result.js";
17
44
  import type { ExtendedPrincipal, Principal } from "./schemas/principal.js";
18
45
  /**
19
46
  * Assign a custom User ID to a passkey. Will be reflected in the next
@@ -27,14 +54,14 @@ import type { ExtendedPrincipal, Principal } from "./schemas/principal.js";
27
54
  * @see [credential](https://passlock.dev/rest-api/credential/)
28
55
  *
29
56
  * @param request
30
- * @returns A promise resolving to either a passkey or an API error.
57
+ * @returns A promise resolving to a {@link Result} whose success branch contains
58
+ * a passkey and whose error branch contains an API error.
31
59
  *
32
60
  * @category Passkeys
33
61
  */
34
- export declare const assignUser: (request: AssignUserOptions) => Promise<Passkey | NotFoundError | ForbiddenError>;
62
+ export declare const assignUser: (request: AssignUserOptions) => Promise<Result<Passkey, NotFoundError | ForbiddenError>>;
35
63
  /**
36
- * Can also be used to assign a custom User ID, but also allows you to update
37
- * the username.
64
+ * Update a passkey's custom user ID and/or username metadata.
38
65
  *
39
66
  * **Important:** changing the username has no bearing on authentication, as
40
67
  * it's typically only used in the client-side component of the passkey
@@ -44,27 +71,37 @@ export declare const assignUser: (request: AssignUserOptions) => Promise<Passkey
44
71
  * client-side component to simplify end user support.
45
72
  *
46
73
  * @param request
47
- * @returns A promise resolving to either a passkey or an API error.
74
+ * @returns A promise resolving to a {@link Result} whose success branch contains
75
+ * a passkey and whose error branch contains an API error.
48
76
  *
49
77
  * @category Passkeys
50
78
  */
51
- export declare const updatePasskey: (request: UpdatePasskeyOptions) => Promise<Passkey | NotFoundError | ForbiddenError>;
79
+ export declare const updatePasskey: (request: UpdatePasskeyOptions) => Promise<Result<Passkey, NotFoundError | ForbiddenError>>;
52
80
  /**
53
- * Update the username for all passkeys belonging to a given user.
81
+ * Update the stored username metadata for all passkeys belonging to a given
82
+ * user, and prepare client-side credential updates for those passkeys.
54
83
  *
55
- * **Important:** changing the username has no bearing on authentication, as
56
- * it's typically only used in the client-side component of the passkey
57
- * (so the user knows which account the passkey relates to).
84
+ * **Important:** changing these values has no bearing on authentication. The
85
+ * server-side operation updates the username stored in Passlock. The optional
86
+ * `displayName` is only included in the returned credential updates for
87
+ * follow-up use with `@passlock/client`; it is not persisted in the vault.
58
88
  *
59
89
  * However you might choose to align the username in your vault with the
60
90
  * client-side component to simplify end user support.
61
91
  *
92
+ * **Note:** This can be used alongside `@passlock/client`'s
93
+ * `updatePasskeyUsernames` helper to update those details on the user's device.
94
+ *
62
95
  * @param request
63
- * @returns A promise resolving to either updated passkey usernames or an API error.
96
+ * @returns A promise resolving to a {@link Result}.
97
+ * The success branch contains an {@link UpdatedCredentials} payload, whose
98
+ * `credentials` array can be passed into the client's `updatePasskeyUsernames` function.
99
+ * The error branch contains
100
+ * an API error.
64
101
  *
65
102
  * @category Passkeys
66
103
  */
67
- export declare const updatePasskeyUsernames: (request: UpdatePasskeyUsernamesOptions) => Promise<UpdatedPasskeyUsernames | NotFoundError | ForbiddenError>;
104
+ export declare const updatePasskeyUsernames: (request: UpdateUsernamesOptions) => Promise<Result<UpdatedCredentials, NotFoundError | ForbiddenError>>;
68
105
  /**
69
106
  * Delete a passkey from your vault.
70
107
  *
@@ -85,11 +122,25 @@ export declare const updatePasskeyUsernames: (request: UpdatePasskeyUsernamesOpt
85
122
  * @see [handling missing passkeys](https://passlock.dev/handling-missing-passkeys/)
86
123
  *
87
124
  * @param options
88
- * @returns A promise resolving to either the deleted passkey or an API error.
125
+ * @returns A promise resolving to a {@link Result} whose success branch contains
126
+ * the deleted credential and whose error branch contains an API error.
127
+ *
128
+ * @category Passkeys
129
+ */
130
+ export declare const deletePasskey: (options: DeletePasskeyOptions) => Promise<Result<DeletedPasskey, ForbiddenError | NotFoundError>>;
131
+ /**
132
+ * Delete all passkeys associated with a user.
133
+ *
134
+ * @param request
135
+ * @returns A promise resolving to a {@link Result}.
136
+ * The success branch contains a {@link DeletedPasskeys} payload whose
137
+ * `deleted` array can be passed directly into `@passlock/client`'s
138
+ * `deleteUserPasskeys` helper for follow-up client-side passkey removal.
139
+ * The error branch contains an API error.
89
140
  *
90
141
  * @category Passkeys
91
142
  */
92
- export declare const deletePasskey: (options: DeletePasskeyOptions) => Promise<Passkey | ForbiddenError | NotFoundError>;
143
+ export declare const deleteUserPasskeys: (request: DeleteUserPasskeysOptions) => Promise<Result<DeletedPasskeys, ForbiddenError | NotFoundError>>;
93
144
  /**
94
145
  * Fetch details about a passkey. **Important**: Not to be confused with
95
146
  * the {@link exchangeCode} or {@link verifyIdToken} functions, which
@@ -97,21 +148,23 @@ export declare const deletePasskey: (options: DeletePasskeyOptions) => Promise<P
97
148
  * Use this function for passkey management, not authentication.
98
149
  *
99
150
  * @param options
100
- * @returns A promise resolving to either passkey details or an API error.
151
+ * @returns A promise resolving to a {@link Result} whose success branch contains
152
+ * passkey details and whose error branch contains an API error.
101
153
  *
102
154
  * @category Passkeys
103
155
  */
104
- export declare const getPasskey: (options: GetPasskeyOptions) => Promise<Passkey | ForbiddenError | NotFoundError>;
156
+ export declare const getPasskey: (options: GetPasskeyOptions) => Promise<Result<Passkey, ForbiddenError | NotFoundError>>;
105
157
  /**
106
158
  * List passkeys for the given tenancy. Note: This could return a cursor.
107
159
  * If so, call again, passing the cursor back in.
108
160
  *
109
161
  * @param options
110
- * @returns A promise resolving to a page of passkey summaries or an API error.
162
+ * @returns A promise resolving to a {@link Result} whose success branch contains
163
+ * a page of passkey summaries and whose error branch contains an API error.
111
164
  *
112
165
  * @category Passkeys
113
166
  */
114
- export declare const listPasskeys: (options: ListPasskeyOptions) => Promise<FindAllPasskeys | ForbiddenError>;
167
+ export declare const listPasskeys: (options: ListPasskeyOptions) => Promise<Result<FindAllPasskeys, ForbiddenError>>;
115
168
  /**
116
169
  * The @passlock/client library generates codes, which you should send to
117
170
  * your backend. Use this function to exchange the code for details about
@@ -121,32 +174,36 @@ export declare const listPasskeys: (options: ListPasskeyOptions) => Promise<Find
121
174
  * @see {@link ExtendedPrincipal}
122
175
  *
123
176
  * @param options
124
- * @returns A promise resolving to an extended principal or an API error.
177
+ * @returns A promise resolving to a {@link Result} whose success branch contains
178
+ * an extended principal and whose error branch contains an API error.
125
179
  *
126
180
  * @category Principal
127
181
  */
128
- export declare const exchangeCode: (options: ExchangeCodeOptions) => Promise<ExtendedPrincipal | ForbiddenError | InvalidCodeError>;
182
+ export declare const exchangeCode: (options: ExchangeCodeOptions) => Promise<Result<ExtendedPrincipal, ForbiddenError | InvalidCodeError>>;
129
183
  /**
130
184
  * Decode and verify an id_token (JWT) locally.
185
+ *
131
186
  * **Note:** This will make a network call to
132
187
  * `https://api.passlock.dev/.well-known/jwks.json` (or your configured `endpoint`)
133
188
  * to fetch the relevant public key. The response will be cached, however
134
- * bear in mind that for something like AWS Lambda it will make the call on every
135
- * cold start so might actually be slower than {@link exchangeCode}
189
+ * bear in mind that for environments such as AWS Lambda it will make the call
190
+ * on each cold start, so it might be slower than {@link exchangeCode}.
136
191
  *
137
192
  * @see {@link Principal}
138
193
  *
139
194
  * @param options
140
- * @returns A promise resolving to a verified principal or verification failure.
195
+ * @returns A promise resolving to a {@link Result} whose success branch contains
196
+ * a verified principal and whose error branch contains a verification error.
141
197
  *
142
198
  * @category Principal
143
199
  */
144
- export declare const verifyIdToken: (options: VerifyIdTokenOptions) => Promise<Principal | VerificationError>;
200
+ export declare const verifyIdToken: (options: VerifyIdTokenOptions) => Promise<Result<Principal, VerificationError>>;
145
201
  export type { BadRequestError, DuplicateEmailError, ForbiddenError, InvalidCodeError, InvalidEmailError, InvalidTenancyError, NotFoundError, PasskeyNotFoundError, UnauthorizedError, VerificationError, } from "./errors.js";
146
202
  export { isBadRequestError, isDuplicateEmailError, isForbiddenError, isInvalidCodeError, isInvalidEmailError, isInvalidTenancyError, isNotFoundError, isPasskeyNotFoundError, isUnauthorizedError, isVerificationError, } from "./errors.js";
147
- export type { AssignUserOptions, Credential, DeletePasskeyOptions, FindAllPasskeys, GetPasskeyOptions, ListPasskeyOptions, Passkey, PasskeySummary, Platform, UpdatedPasskeys, UpdatedPasskeyUsernames, UpdatePasskeyOptions, UpdatePasskeyUsernamesOptions, } from "./passkey/passkey.js";
148
- export { isPasskey, isPasskeySummary, isUpdatedPasskeys, isUpdatedPasskeyUsernames, } from "./passkey/passkey.js";
203
+ export type { AssignUserOptions, Credential, DeletedPasskey, DeletedPasskeys, DeletePasskeyOptions, DeleteUserPasskeysOptions, FindAllPasskeys, GetPasskeyOptions, ListPasskeyOptions, Passkey, PasskeyCredential, PasskeySummary, Platform, UpdatedCredentials as UpdatedUserDetails, UpdatedPasskeys, UpdatePasskeyOptions, UpdateUsernamesOptions as UpdateUserDetailsOptions, } from "./passkey/passkey.js";
204
+ export { isDeletedPasskeys, isPasskey, isPasskeySummary, isUpdatedPasskeys, isUpdatedUserDetails, } from "./passkey/passkey.js";
149
205
  export type { ExchangeCodeOptions, VerifyIdTokenOptions, } from "./principal/principal.js";
206
+ export type { Err, Ok, Result } from "./safe-result.js";
150
207
  export type { CredentialDeviceType, Transports, } from "./schemas/passkey.js";
151
208
  export type { ExtendedPrincipal, Principal } from "./schemas/principal.js";
152
209
  export { isExtendedPrincipal, isPrincipal } from "./schemas/principal.js";
@@ -1 +1 @@
1
- {"version":3,"file":"safe.d.ts","sourceRoot":"","sources":["../src/safe.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"safe.d.ts","sourceRoot":"","sources":["../src/safe.ts"],"names":[],"mappings":"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"}
package/dist/safe.js CHANGED
@@ -1,19 +1,50 @@
1
1
  /**
2
- * Safe functions that return discriminated unions representing
3
- * the successful outcome or expected failures.
2
+ * Safe functions that return result envelopes over the original
3
+ * tagged success and error payloads. The returned value keeps
4
+ * its original `_tag` shape, and is also augmented with a
5
+ * result envelope for `success`- or `failure`-style branching.
4
6
  *
5
7
  * Note: unexpected runtime failures may still throw.
6
8
  *
9
+ * ```ts
10
+ * const result = await exchangeCode({
11
+ * apiKey,
12
+ * code,
13
+ * tenancyId,
14
+ * })
15
+ *
16
+ * if (result.success) {
17
+ * console.log(result.value.id)
18
+ * }
19
+ *
20
+ * if (result.failure) {
21
+ * console.log(result.error.message)
22
+ * }
23
+ *
24
+ * if (isExtendedPrincipal(result)) {
25
+ * console.log(result.id)
26
+ * }
27
+ * ```
28
+ *
7
29
  * @categoryDescription Passkeys
8
- * Functions and related types for managing passkeys
30
+ * Functions and related types for managing passkeys.
31
+ *
32
+ * @categoryDescription Principal
33
+ * Functions and related types for exchanging client codes and verifying
34
+ * Passlock tokens.
9
35
  *
10
36
  * @showCategories
11
37
  *
12
38
  * @module safe
13
39
  */
14
- import { Effect, identity, pipe } from "effect";
15
- import { assignUser as assignUserE, deletePasskey as deletePasskeyE, getPasskey as getPasskeyE, listPasskeys as listPasskeysE, updatePasskey as updatePasskeyE, updatePasskeyUsernames as updatePasskeyUsernamesE, } from "./passkey/passkey.js";
40
+ import { Effect, pipe } from "effect";
41
+ import { assignUser as assignUserE, deletePasskey as deletePasskeyE, deleteUserPasskeys as deleteUserPasskeysE, getPasskey as getPasskeyE, listPasskeys as listPasskeysE, updatePasskey as updatePasskeyE, updatePasskeyUsernames as updatePasskeyUsernamesE, } from "./passkey/passkey.js";
16
42
  import { exchangeCode as exchangeCodeE, verifyIdToken as verifyIdTokenE, } from "./principal/principal.js";
43
+ import { toErrResult, toOkResult } from "./safe-result.js";
44
+ const runSafe = (effect) => pipe(effect, Effect.match({
45
+ onFailure: (error) => toErrResult(error),
46
+ onSuccess: (value) => toOkResult(value),
47
+ }), Effect.runPromise);
17
48
  /**
18
49
  * Assign a custom User ID to a passkey. Will be reflected in the next
19
50
  * {@link Principal} or {@link ExtendedPrincipal} generated.
@@ -26,14 +57,14 @@ import { exchangeCode as exchangeCodeE, verifyIdToken as verifyIdTokenE, } from
26
57
  * @see [credential](https://passlock.dev/rest-api/credential/)
27
58
  *
28
59
  * @param request
29
- * @returns A promise resolving to either a passkey or an API error.
60
+ * @returns A promise resolving to a {@link Result} whose success branch contains
61
+ * a passkey and whose error branch contains an API error.
30
62
  *
31
63
  * @category Passkeys
32
64
  */
33
- export const assignUser = (request) => pipe(assignUserE(request), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
65
+ export const assignUser = (request) => runSafe(assignUserE(request));
34
66
  /**
35
- * Can also be used to assign a custom User ID, but also allows you to update
36
- * the username.
67
+ * Update a passkey's custom user ID and/or username metadata.
37
68
  *
38
69
  * **Important:** changing the username has no bearing on authentication, as
39
70
  * it's typically only used in the client-side component of the passkey
@@ -43,27 +74,37 @@ export const assignUser = (request) => pipe(assignUserE(request), Effect.match({
43
74
  * client-side component to simplify end user support.
44
75
  *
45
76
  * @param request
46
- * @returns A promise resolving to either a passkey or an API error.
77
+ * @returns A promise resolving to a {@link Result} whose success branch contains
78
+ * a passkey and whose error branch contains an API error.
47
79
  *
48
80
  * @category Passkeys
49
81
  */
50
- export const updatePasskey = (request) => pipe(updatePasskeyE(request), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
82
+ export const updatePasskey = (request) => runSafe(updatePasskeyE(request));
51
83
  /**
52
- * Update the username for all passkeys belonging to a given user.
84
+ * Update the stored username metadata for all passkeys belonging to a given
85
+ * user, and prepare client-side credential updates for those passkeys.
53
86
  *
54
- * **Important:** changing the username has no bearing on authentication, as
55
- * it's typically only used in the client-side component of the passkey
56
- * (so the user knows which account the passkey relates to).
87
+ * **Important:** changing these values has no bearing on authentication. The
88
+ * server-side operation updates the username stored in Passlock. The optional
89
+ * `displayName` is only included in the returned credential updates for
90
+ * follow-up use with `@passlock/client`; it is not persisted in the vault.
57
91
  *
58
92
  * However you might choose to align the username in your vault with the
59
93
  * client-side component to simplify end user support.
60
94
  *
95
+ * **Note:** This can be used alongside `@passlock/client`'s
96
+ * `updatePasskeyUsernames` helper to update those details on the user's device.
97
+ *
61
98
  * @param request
62
- * @returns A promise resolving to either updated passkey usernames or an API error.
99
+ * @returns A promise resolving to a {@link Result}.
100
+ * The success branch contains an {@link UpdatedCredentials} payload, whose
101
+ * `credentials` array can be passed into the client's `updatePasskeyUsernames` function.
102
+ * The error branch contains
103
+ * an API error.
63
104
  *
64
105
  * @category Passkeys
65
106
  */
66
- export const updatePasskeyUsernames = (request) => pipe(updatePasskeyUsernamesE(request), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
107
+ export const updatePasskeyUsernames = (request) => runSafe(updatePasskeyUsernamesE(request));
67
108
  /**
68
109
  * Delete a passkey from your vault.
69
110
  *
@@ -84,11 +125,25 @@ export const updatePasskeyUsernames = (request) => pipe(updatePasskeyUsernamesE(
84
125
  * @see [handling missing passkeys](https://passlock.dev/handling-missing-passkeys/)
85
126
  *
86
127
  * @param options
87
- * @returns A promise resolving to either the deleted passkey or an API error.
128
+ * @returns A promise resolving to a {@link Result} whose success branch contains
129
+ * the deleted credential and whose error branch contains an API error.
130
+ *
131
+ * @category Passkeys
132
+ */
133
+ export const deletePasskey = (options) => runSafe(deletePasskeyE(options));
134
+ /**
135
+ * Delete all passkeys associated with a user.
136
+ *
137
+ * @param request
138
+ * @returns A promise resolving to a {@link Result}.
139
+ * The success branch contains a {@link DeletedPasskeys} payload whose
140
+ * `deleted` array can be passed directly into `@passlock/client`'s
141
+ * `deleteUserPasskeys` helper for follow-up client-side passkey removal.
142
+ * The error branch contains an API error.
88
143
  *
89
144
  * @category Passkeys
90
145
  */
91
- export const deletePasskey = (options) => pipe(deletePasskeyE(options), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
146
+ export const deleteUserPasskeys = (request) => runSafe(deleteUserPasskeysE(request));
92
147
  /**
93
148
  * Fetch details about a passkey. **Important**: Not to be confused with
94
149
  * the {@link exchangeCode} or {@link verifyIdToken} functions, which
@@ -96,21 +151,23 @@ export const deletePasskey = (options) => pipe(deletePasskeyE(options), Effect.m
96
151
  * Use this function for passkey management, not authentication.
97
152
  *
98
153
  * @param options
99
- * @returns A promise resolving to either passkey details or an API error.
154
+ * @returns A promise resolving to a {@link Result} whose success branch contains
155
+ * passkey details and whose error branch contains an API error.
100
156
  *
101
157
  * @category Passkeys
102
158
  */
103
- export const getPasskey = (options) => pipe(getPasskeyE(options), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
159
+ export const getPasskey = (options) => runSafe(getPasskeyE(options));
104
160
  /**
105
161
  * List passkeys for the given tenancy. Note: This could return a cursor.
106
162
  * If so, call again, passing the cursor back in.
107
163
  *
108
164
  * @param options
109
- * @returns A promise resolving to a page of passkey summaries or an API error.
165
+ * @returns A promise resolving to a {@link Result} whose success branch contains
166
+ * a page of passkey summaries and whose error branch contains an API error.
110
167
  *
111
168
  * @category Passkeys
112
169
  */
113
- export const listPasskeys = (options) => pipe(listPasskeysE(options), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
170
+ export const listPasskeys = (options) => runSafe(listPasskeysE(options));
114
171
  /**
115
172
  * The @passlock/client library generates codes, which you should send to
116
173
  * your backend. Use this function to exchange the code for details about
@@ -120,28 +177,31 @@ export const listPasskeys = (options) => pipe(listPasskeysE(options), Effect.mat
120
177
  * @see {@link ExtendedPrincipal}
121
178
  *
122
179
  * @param options
123
- * @returns A promise resolving to an extended principal or an API error.
180
+ * @returns A promise resolving to a {@link Result} whose success branch contains
181
+ * an extended principal and whose error branch contains an API error.
124
182
  *
125
183
  * @category Principal
126
184
  */
127
- export const exchangeCode = (options) => pipe(exchangeCodeE(options), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
185
+ export const exchangeCode = (options) => runSafe(exchangeCodeE(options));
128
186
  /**
129
187
  * Decode and verify an id_token (JWT) locally.
188
+ *
130
189
  * **Note:** This will make a network call to
131
190
  * `https://api.passlock.dev/.well-known/jwks.json` (or your configured `endpoint`)
132
191
  * to fetch the relevant public key. The response will be cached, however
133
- * bear in mind that for something like AWS Lambda it will make the call on every
134
- * cold start so might actually be slower than {@link exchangeCode}
192
+ * bear in mind that for environments such as AWS Lambda it will make the call
193
+ * on each cold start, so it might be slower than {@link exchangeCode}.
135
194
  *
136
195
  * @see {@link Principal}
137
196
  *
138
197
  * @param options
139
- * @returns A promise resolving to a verified principal or verification failure.
198
+ * @returns A promise resolving to a {@link Result} whose success branch contains
199
+ * a verified principal and whose error branch contains a verification error.
140
200
  *
141
201
  * @category Principal
142
202
  */
143
- export const verifyIdToken = (options) => pipe(verifyIdTokenE(options), Effect.match({ onFailure: identity, onSuccess: identity }), Effect.runPromise);
203
+ export const verifyIdToken = (options) => runSafe(verifyIdTokenE(options));
144
204
  export { isBadRequestError, isDuplicateEmailError, isForbiddenError, isInvalidCodeError, isInvalidEmailError, isInvalidTenancyError, isNotFoundError, isPasskeyNotFoundError, isUnauthorizedError, isVerificationError, } from "./errors.js";
145
- export { isPasskey, isPasskeySummary, isUpdatedPasskeys, isUpdatedPasskeyUsernames, } from "./passkey/passkey.js";
205
+ export { isDeletedPasskeys, isPasskey, isPasskeySummary, isUpdatedPasskeys, isUpdatedUserDetails, } from "./passkey/passkey.js";
146
206
  export { isExtendedPrincipal, isPrincipal } from "./schemas/principal.js";
147
207
  //# sourceMappingURL=safe.js.map
package/dist/safe.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"safe.js","sourceRoot":"","sources":["../src/safe.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Safe functions that return discriminated unions representing\n * the successful outcome or expected failures.\n *\n * Note: unexpected runtime failures may still throw.\n *\n * @categoryDescription Passkeys\n * Functions and related types for managing passkeys\n *\n * @showCategories\n *\n * @module safe\n */\n\nimport { Effect, identity, pipe } from \"effect\"\nimport type {\n ForbiddenError,\n InvalidCodeError,\n NotFoundError,\n VerificationError,\n} from \"./errors.js\"\nimport type {\n AssignUserOptions,\n DeletePasskeyOptions,\n FindAllPasskeys,\n GetPasskeyOptions,\n ListPasskeyOptions,\n Passkey,\n UpdatedPasskeyUsernames,\n UpdatePasskeyOptions,\n UpdatePasskeyUsernamesOptions,\n} from \"./passkey/passkey.js\"\nimport {\n assignUser as assignUserE,\n deletePasskey as deletePasskeyE,\n getPasskey as getPasskeyE,\n listPasskeys as listPasskeysE,\n updatePasskey as updatePasskeyE,\n updatePasskeyUsernames as updatePasskeyUsernamesE,\n} from \"./passkey/passkey.js\"\nimport type {\n ExchangeCodeOptions,\n VerifyIdTokenOptions,\n} from \"./principal/principal.js\"\nimport {\n exchangeCode as exchangeCodeE,\n verifyIdToken as verifyIdTokenE,\n} from \"./principal/principal.js\"\nimport type { ExtendedPrincipal, Principal } from \"./schemas/principal.js\"\n\n/**\n * Assign a custom User ID to a passkey. Will be reflected in the next\n * {@link Principal} or {@link ExtendedPrincipal} generated.\n *\n * **Note:** This does not change the underlying WebAuthn credential's `userId`.\n * Instead we apply a layer of indirection.\n *\n * @see {@link Principal}\n * @see {@link ExtendedPrincipal}\n * @see [credential](https://passlock.dev/rest-api/credential/)\n *\n * @param request\n * @returns A promise resolving to either a passkey or an API error.\n *\n * @category Passkeys\n */\nexport const assignUser = (\n request: AssignUserOptions\n): Promise<Passkey | NotFoundError | ForbiddenError> =>\n pipe(\n assignUserE(request),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * Can also be used to assign a custom User ID, but also allows you to update\n * the username.\n *\n * **Important:** changing the username has no bearing on authentication, as\n * it's typically only used in the client-side component of the passkey\n * (so the user knows which account the passkey relates to).\n *\n * However you might choose to align the username in your vault with the\n * client-side component to simplify end user support.\n *\n * @param request\n * @returns A promise resolving to either a passkey or an API error.\n *\n * @category Passkeys\n */\nexport const updatePasskey = (\n request: UpdatePasskeyOptions\n): Promise<Passkey | NotFoundError | ForbiddenError> =>\n pipe(\n updatePasskeyE(request),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * Update the username for all passkeys belonging to a given user.\n *\n * **Important:** changing the username has no bearing on authentication, as\n * it's typically only used in the client-side component of the passkey\n * (so the user knows which account the passkey relates to).\n *\n * However you might choose to align the username in your vault with the\n * client-side component to simplify end user support.\n *\n * @param request\n * @returns A promise resolving to either updated passkey usernames or an API error.\n *\n * @category Passkeys\n */\nexport const updatePasskeyUsernames = (\n request: UpdatePasskeyUsernamesOptions\n): Promise<UpdatedPasskeyUsernames | NotFoundError | ForbiddenError> =>\n pipe(\n updatePasskeyUsernamesE(request),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * Delete a passkey from your vault.\n *\n * **Note:** The user will still retain the passkey on their device so\n * you will need to either:\n *\n * a) Use the @passlock/client functions to delete the passkey from the user's device.\n * b) Remind the user to delete the passkey\n *\n * See [deleting passkeys](https://passlock.dev/passkeys/passkey-removal/) in the documentation.\n *\n * In addition, during authentication you should handle a missing passkey scenario.\n * This happens when a user tries to authenticate with a passkey that is missing from\n * your vault. The @passlock/client library can help with this. See\n * [handling missing passkeys](https://passlock.dev/handling-missing-passkeys/)\n *\n * @see [deleting passkeys](https://passlock.dev/passkeys/passkey-removal/)\n * @see [handling missing passkeys](https://passlock.dev/handling-missing-passkeys/)\n *\n * @param options\n * @returns A promise resolving to either the deleted passkey or an API error.\n *\n * @category Passkeys\n */\nexport const deletePasskey = (\n options: DeletePasskeyOptions\n): Promise<Passkey | ForbiddenError | NotFoundError> =>\n pipe(\n deletePasskeyE(options),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * Fetch details about a passkey. **Important**: Not to be confused with\n * the {@link exchangeCode} or {@link verifyIdToken} functions, which\n * return details about specific authentication or registration operations.\n * Use this function for passkey management, not authentication.\n *\n * @param options\n * @returns A promise resolving to either passkey details or an API error.\n *\n * @category Passkeys\n */\nexport const getPasskey = (\n options: GetPasskeyOptions\n): Promise<Passkey | ForbiddenError | NotFoundError> =>\n pipe(\n getPasskeyE(options),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * List passkeys for the given tenancy. Note: This could return a cursor.\n * If so, call again, passing the cursor back in.\n *\n * @param options\n * @returns A promise resolving to a page of passkey summaries or an API error.\n *\n * @category Passkeys\n */\nexport const listPasskeys = (\n options: ListPasskeyOptions\n): Promise<FindAllPasskeys | ForbiddenError> =>\n pipe(\n listPasskeysE(options),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * The @passlock/client library generates codes, which you should send to\n * your backend. Use this function to exchange the code for details about\n * the registration or authentication operation. **Note:** a code is valid\n * for 5 minutes.\n *\n * @see {@link ExtendedPrincipal}\n *\n * @param options\n * @returns A promise resolving to an extended principal or an API error.\n *\n * @category Principal\n */\nexport const exchangeCode = (\n options: ExchangeCodeOptions\n): Promise<ExtendedPrincipal | ForbiddenError | InvalidCodeError> =>\n pipe(\n exchangeCodeE(options),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/**\n * Decode and verify an id_token (JWT) locally.\n * **Note:** This will make a network call to\n * `https://api.passlock.dev/.well-known/jwks.json` (or your configured `endpoint`)\n * to fetch the relevant public key. The response will be cached, however\n * bear in mind that for something like AWS Lambda it will make the call on every\n * cold start so might actually be slower than {@link exchangeCode}\n *\n * @see {@link Principal}\n *\n * @param options\n * @returns A promise resolving to a verified principal or verification failure.\n *\n * @category Principal\n */\nexport const verifyIdToken = (\n options: VerifyIdTokenOptions\n): Promise<Principal | VerificationError> =>\n pipe(\n verifyIdTokenE(options),\n Effect.match({ onFailure: identity, onSuccess: identity }),\n Effect.runPromise\n )\n\n/* Re-exports */\n\nexport type {\n BadRequestError,\n DuplicateEmailError,\n ForbiddenError,\n InvalidCodeError,\n InvalidEmailError,\n InvalidTenancyError,\n NotFoundError,\n PasskeyNotFoundError,\n UnauthorizedError,\n VerificationError,\n} from \"./errors.js\"\nexport {\n isBadRequestError,\n isDuplicateEmailError,\n isForbiddenError,\n isInvalidCodeError,\n isInvalidEmailError,\n isInvalidTenancyError,\n isNotFoundError,\n isPasskeyNotFoundError,\n isUnauthorizedError,\n isVerificationError,\n} from \"./errors.js\"\nexport type {\n AssignUserOptions,\n Credential,\n DeletePasskeyOptions,\n FindAllPasskeys,\n GetPasskeyOptions,\n ListPasskeyOptions,\n Passkey,\n PasskeySummary,\n Platform,\n UpdatedPasskeys,\n UpdatedPasskeyUsernames,\n UpdatePasskeyOptions,\n UpdatePasskeyUsernamesOptions,\n} from \"./passkey/passkey.js\"\nexport {\n isPasskey,\n isPasskeySummary,\n isUpdatedPasskeys,\n isUpdatedPasskeyUsernames,\n} from \"./passkey/passkey.js\"\nexport type {\n ExchangeCodeOptions,\n VerifyIdTokenOptions,\n} from \"./principal/principal.js\"\nexport type {\n CredentialDeviceType,\n Transports,\n} from \"./schemas/passkey.js\"\nexport type { ExtendedPrincipal, Principal } from \"./schemas/principal.js\"\nexport { isExtendedPrincipal, isPrincipal } from \"./schemas/principal.js\"\nexport type {\n AuthenticatedOptions,\n PasslockOptions,\n} from \"./shared.js\"\n"]}
1
+ {"version":3,"file":"safe.js","sourceRoot":"","sources":["../src/safe.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Safe functions that return result envelopes over the original\n * tagged success and error payloads. The returned value keeps\n * its original `_tag` shape, and is also augmented with a\n * result envelope for `success`- or `failure`-style branching.\n *\n * Note: unexpected runtime failures may still throw.\n *\n * ```ts\n * const result = await exchangeCode({\n * apiKey,\n * code,\n * tenancyId,\n * })\n *\n * if (result.success) {\n * console.log(result.value.id)\n * }\n *\n * if (result.failure) {\n * console.log(result.error.message)\n * }\n *\n * if (isExtendedPrincipal(result)) {\n * console.log(result.id)\n * }\n * ```\n *\n * @categoryDescription Passkeys\n * Functions and related types for managing passkeys.\n *\n * @categoryDescription Principal\n * Functions and related types for exchanging client codes and verifying\n * Passlock tokens.\n *\n * @showCategories\n *\n * @module safe\n */\n\nimport { Effect, pipe } from \"effect\"\nimport type {\n ForbiddenError,\n InvalidCodeError,\n NotFoundError,\n VerificationError,\n} from \"./errors.js\"\nimport type {\n AssignUserOptions,\n DeletedPasskey,\n DeletedPasskeys,\n DeletePasskeyOptions,\n DeleteUserPasskeysOptions,\n FindAllPasskeys,\n GetPasskeyOptions,\n ListPasskeyOptions,\n Passkey,\n UpdatedCredentials,\n UpdatePasskeyOptions,\n UpdateUsernamesOptions,\n} from \"./passkey/passkey.js\"\nimport {\n assignUser as assignUserE,\n deletePasskey as deletePasskeyE,\n deleteUserPasskeys as deleteUserPasskeysE,\n getPasskey as getPasskeyE,\n listPasskeys as listPasskeysE,\n updatePasskey as updatePasskeyE,\n updatePasskeyUsernames as updatePasskeyUsernamesE,\n} from \"./passkey/passkey.js\"\nimport type {\n ExchangeCodeOptions,\n VerifyIdTokenOptions,\n} from \"./principal/principal.js\"\nimport {\n exchangeCode as exchangeCodeE,\n verifyIdToken as verifyIdTokenE,\n} from \"./principal/principal.js\"\nimport { type Result, toErrResult, toOkResult } from \"./safe-result.js\"\nimport type { ExtendedPrincipal, Principal } from \"./schemas/principal.js\"\n\nconst runSafe = <A extends object, E extends object>(\n effect: Effect.Effect<A, E>\n): Promise<Result<A, E>> =>\n pipe(\n effect,\n Effect.match({\n onFailure: (error): Result<A, E> => toErrResult(error) as Result<A, E>,\n onSuccess: (value): Result<A, E> => toOkResult(value) as Result<A, E>,\n }),\n Effect.runPromise\n )\n\n/**\n * Assign a custom User ID to a passkey. Will be reflected in the next\n * {@link Principal} or {@link ExtendedPrincipal} generated.\n *\n * **Note:** This does not change the underlying WebAuthn credential's `userId`.\n * Instead we apply a layer of indirection.\n *\n * @see {@link Principal}\n * @see {@link ExtendedPrincipal}\n * @see [credential](https://passlock.dev/rest-api/credential/)\n *\n * @param request\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * a passkey and whose error branch contains an API error.\n *\n * @category Passkeys\n */\nexport const assignUser = (\n request: AssignUserOptions\n): Promise<Result<Passkey, NotFoundError | ForbiddenError>> =>\n runSafe(assignUserE(request))\n\n/**\n * Update a passkey's custom user ID and/or username metadata.\n *\n * **Important:** changing the username has no bearing on authentication, as\n * it's typically only used in the client-side component of the passkey\n * (so the user knows which account the passkey relates to).\n *\n * However you might choose to align the username in your vault with the\n * client-side component to simplify end user support.\n *\n * @param request\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * a passkey and whose error branch contains an API error.\n *\n * @category Passkeys\n */\nexport const updatePasskey = (\n request: UpdatePasskeyOptions\n): Promise<Result<Passkey, NotFoundError | ForbiddenError>> =>\n runSafe(updatePasskeyE(request))\n\n/**\n * Update the stored username metadata for all passkeys belonging to a given\n * user, and prepare client-side credential updates for those passkeys.\n *\n * **Important:** changing these values has no bearing on authentication. The\n * server-side operation updates the username stored in Passlock. The optional\n * `displayName` is only included in the returned credential updates for\n * follow-up use with `@passlock/client`; it is not persisted in the vault.\n *\n * However you might choose to align the username in your vault with the\n * client-side component to simplify end user support.\n *\n * **Note:** This can be used alongside `@passlock/client`'s\n * `updatePasskeyUsernames` helper to update those details on the user's device.\n *\n * @param request\n * @returns A promise resolving to a {@link Result}.\n * The success branch contains an {@link UpdatedCredentials} payload, whose\n * `credentials` array can be passed into the client's `updatePasskeyUsernames` function.\n * The error branch contains\n * an API error.\n *\n * @category Passkeys\n */\nexport const updatePasskeyUsernames = (\n request: UpdateUsernamesOptions\n): Promise<Result<UpdatedCredentials, NotFoundError | ForbiddenError>> =>\n runSafe(updatePasskeyUsernamesE(request))\n\n/**\n * Delete a passkey from your vault.\n *\n * **Note:** The user will still retain the passkey on their device so\n * you will need to either:\n *\n * a) Use the @passlock/client functions to delete the passkey from the user's device.\n * b) Remind the user to delete the passkey\n *\n * See [deleting passkeys](https://passlock.dev/passkeys/passkey-removal/) in the documentation.\n *\n * In addition, during authentication you should handle a missing passkey scenario.\n * This happens when a user tries to authenticate with a passkey that is missing from\n * your vault. The @passlock/client library can help with this. See\n * [handling missing passkeys](https://passlock.dev/handling-missing-passkeys/)\n *\n * @see [deleting passkeys](https://passlock.dev/passkeys/passkey-removal/)\n * @see [handling missing passkeys](https://passlock.dev/handling-missing-passkeys/)\n *\n * @param options\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * the deleted credential and whose error branch contains an API error.\n *\n * @category Passkeys\n */\nexport const deletePasskey = (\n options: DeletePasskeyOptions\n): Promise<Result<DeletedPasskey, ForbiddenError | NotFoundError>> =>\n runSafe(deletePasskeyE(options))\n\n/**\n * Delete all passkeys associated with a user.\n *\n * @param request\n * @returns A promise resolving to a {@link Result}.\n * The success branch contains a {@link DeletedPasskeys} payload whose\n * `deleted` array can be passed directly into `@passlock/client`'s\n * `deleteUserPasskeys` helper for follow-up client-side passkey removal.\n * The error branch contains an API error.\n *\n * @category Passkeys\n */\nexport const deleteUserPasskeys = (\n request: DeleteUserPasskeysOptions\n): Promise<Result<DeletedPasskeys, ForbiddenError | NotFoundError>> =>\n runSafe(deleteUserPasskeysE(request))\n\n/**\n * Fetch details about a passkey. **Important**: Not to be confused with\n * the {@link exchangeCode} or {@link verifyIdToken} functions, which\n * return details about specific authentication or registration operations.\n * Use this function for passkey management, not authentication.\n *\n * @param options\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * passkey details and whose error branch contains an API error.\n *\n * @category Passkeys\n */\nexport const getPasskey = (\n options: GetPasskeyOptions\n): Promise<Result<Passkey, ForbiddenError | NotFoundError>> =>\n runSafe(getPasskeyE(options))\n\n/**\n * List passkeys for the given tenancy. Note: This could return a cursor.\n * If so, call again, passing the cursor back in.\n *\n * @param options\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * a page of passkey summaries and whose error branch contains an API error.\n *\n * @category Passkeys\n */\nexport const listPasskeys = (\n options: ListPasskeyOptions\n): Promise<Result<FindAllPasskeys, ForbiddenError>> =>\n runSafe(listPasskeysE(options))\n\n/**\n * The @passlock/client library generates codes, which you should send to\n * your backend. Use this function to exchange the code for details about\n * the registration or authentication operation. **Note:** a code is valid\n * for 5 minutes.\n *\n * @see {@link ExtendedPrincipal}\n *\n * @param options\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * an extended principal and whose error branch contains an API error.\n *\n * @category Principal\n */\nexport const exchangeCode = (\n options: ExchangeCodeOptions\n): Promise<Result<ExtendedPrincipal, ForbiddenError | InvalidCodeError>> =>\n runSafe(exchangeCodeE(options))\n\n/**\n * Decode and verify an id_token (JWT) locally.\n *\n * **Note:** This will make a network call to\n * `https://api.passlock.dev/.well-known/jwks.json` (or your configured `endpoint`)\n * to fetch the relevant public key. The response will be cached, however\n * bear in mind that for environments such as AWS Lambda it will make the call\n * on each cold start, so it might be slower than {@link exchangeCode}.\n *\n * @see {@link Principal}\n *\n * @param options\n * @returns A promise resolving to a {@link Result} whose success branch contains\n * a verified principal and whose error branch contains a verification error.\n *\n * @category Principal\n */\nexport const verifyIdToken = (\n options: VerifyIdTokenOptions\n): Promise<Result<Principal, VerificationError>> =>\n runSafe(verifyIdTokenE(options))\n\n/* Re-exports */\n\nexport type {\n BadRequestError,\n DuplicateEmailError,\n ForbiddenError,\n InvalidCodeError,\n InvalidEmailError,\n InvalidTenancyError,\n NotFoundError,\n PasskeyNotFoundError,\n UnauthorizedError,\n VerificationError,\n} from \"./errors.js\"\nexport {\n isBadRequestError,\n isDuplicateEmailError,\n isForbiddenError,\n isInvalidCodeError,\n isInvalidEmailError,\n isInvalidTenancyError,\n isNotFoundError,\n isPasskeyNotFoundError,\n isUnauthorizedError,\n isVerificationError,\n} from \"./errors.js\"\nexport type {\n AssignUserOptions,\n Credential,\n DeletedPasskey,\n DeletedPasskeys,\n DeletePasskeyOptions,\n DeleteUserPasskeysOptions,\n FindAllPasskeys,\n GetPasskeyOptions,\n ListPasskeyOptions,\n Passkey,\n PasskeyCredential,\n PasskeySummary,\n Platform,\n UpdatedCredentials as UpdatedUserDetails,\n UpdatedPasskeys,\n UpdatePasskeyOptions,\n UpdateUsernamesOptions as UpdateUserDetailsOptions,\n} from \"./passkey/passkey.js\"\nexport {\n isDeletedPasskeys,\n isPasskey,\n isPasskeySummary,\n isUpdatedPasskeys,\n isUpdatedUserDetails,\n} from \"./passkey/passkey.js\"\nexport type {\n ExchangeCodeOptions,\n VerifyIdTokenOptions,\n} from \"./principal/principal.js\"\nexport type { Err, Ok, Result } from \"./safe-result.js\"\nexport type {\n CredentialDeviceType,\n Transports,\n} from \"./schemas/passkey.js\"\nexport type { ExtendedPrincipal, Principal } from \"./schemas/principal.js\"\nexport { isExtendedPrincipal, isPrincipal } from \"./schemas/principal.js\"\nexport type {\n AuthenticatedOptions,\n PasslockOptions,\n} from \"./shared.js\"\n"]}