@passlock/server 2.1.0 → 2.2.1
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/dist/effect.d.ts +8 -0
- package/dist/effect.d.ts.map +1 -1
- package/dist/effect.js +8 -0
- package/dist/effect.js.map +1 -1
- package/dist/errors.d.ts +65 -0
- package/dist/errors.d.ts.map +1 -1
- package/dist/errors.js +36 -5
- package/dist/errors.js.map +1 -1
- package/dist/index.d.ts +54 -18
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +52 -16
- package/dist/index.js.map +1 -1
- package/dist/network.d.ts +3 -3
- package/dist/passkey/passkey.d.ts +242 -10
- package/dist/passkey/passkey.d.ts.map +1 -1
- package/dist/passkey/passkey.js +140 -4
- package/dist/passkey/passkey.js.map +1 -1
- package/dist/principal/principal.d.ts +45 -1
- package/dist/principal/principal.d.ts.map +1 -1
- package/dist/principal/principal.js +27 -0
- package/dist/principal/principal.js.map +1 -1
- package/dist/safe-result.d.ts +33 -0
- package/dist/safe-result.d.ts.map +1 -0
- package/dist/safe-result.js +35 -0
- package/dist/safe-result.js.map +1 -0
- package/dist/safe.d.ts +79 -28
- package/dist/safe.d.ts.map +1 -1
- package/dist/safe.js +82 -28
- package/dist/safe.js.map +1 -1
- package/dist/schemas/passkey.d.ts +148 -0
- package/dist/schemas/passkey.d.ts.map +1 -1
- package/dist/schemas/passkey.js +82 -12
- package/dist/schemas/passkey.js.map +1 -1
- package/dist/schemas/principal.d.ts +50 -0
- package/dist/schemas/principal.d.ts.map +1 -1
- package/dist/schemas/principal.js +30 -0
- package/dist/schemas/principal.js.map +1 -1
- package/dist/schemas/signup.d.ts +20 -0
- package/dist/schemas/signup.d.ts.map +1 -1
- package/dist/schemas/signup.js +10 -0
- package/dist/schemas/signup.js.map +1 -1
- package/dist/shared.d.ts +18 -0
- package/dist/shared.d.ts.map +1 -1
- package/dist/shared.js.map +1 -1
- package/package.json +6 -6
|
@@ -1,12 +1,17 @@
|
|
|
1
|
-
import { Effect, type Layer
|
|
1
|
+
import { Effect, Stream, type Layer } from "effect";
|
|
2
2
|
import { type NetworkFetch } from "../network.js";
|
|
3
3
|
import { ForbiddenError, NotFoundError } from "../schemas/index.js";
|
|
4
4
|
import * as PasskeySchemas from "../schemas/passkey.js";
|
|
5
5
|
import type { AuthenticatedOptions } from "../shared.js";
|
|
6
6
|
/**
|
|
7
|
-
* WebAuthn
|
|
7
|
+
* WebAuthn-specific credential data stored for a passkey in the Passlock vault.
|
|
8
|
+
*
|
|
9
|
+
* The `id` and `userId` fields are the underlying WebAuthn values, encoded as
|
|
10
|
+
* Base64URL strings.
|
|
11
|
+
*
|
|
12
|
+
* @category Passkeys
|
|
8
13
|
*/
|
|
9
|
-
export type
|
|
14
|
+
export type PasskeyCredential = {
|
|
10
15
|
id: string;
|
|
11
16
|
userId: string;
|
|
12
17
|
username: string;
|
|
@@ -31,13 +36,15 @@ export type Credential = {
|
|
|
31
36
|
*
|
|
32
37
|
* We've also included links to icons (SVG) so you can give your users
|
|
33
38
|
* a quick visual indication.
|
|
39
|
+
*
|
|
40
|
+
* @category Passkeys
|
|
34
41
|
*/
|
|
35
42
|
export type Platform = {
|
|
36
43
|
name?: string | undefined;
|
|
37
44
|
icon?: string | undefined;
|
|
38
45
|
};
|
|
39
46
|
/**
|
|
40
|
-
* The server-side
|
|
47
|
+
* The server-side representation of a passkey stored in the Passlock vault.
|
|
41
48
|
*
|
|
42
49
|
* @category Passkeys
|
|
43
50
|
*/
|
|
@@ -52,13 +59,23 @@ export type Passkey = {
|
|
|
52
59
|
*/
|
|
53
60
|
userId?: string | undefined;
|
|
54
61
|
enabled: boolean;
|
|
55
|
-
credential:
|
|
62
|
+
credential: PasskeyCredential;
|
|
56
63
|
platform?: Platform | undefined;
|
|
57
64
|
lastUsed?: number | undefined;
|
|
58
65
|
createdAt: number;
|
|
59
66
|
updatedAt: number;
|
|
60
67
|
};
|
|
68
|
+
/**
|
|
69
|
+
* Type guard for {@link Passkey}.
|
|
70
|
+
*
|
|
71
|
+
* @category Passkeys
|
|
72
|
+
*/
|
|
61
73
|
export declare const isPasskey: (payload: unknown) => payload is Passkey;
|
|
74
|
+
/**
|
|
75
|
+
* Compact passkey payload returned by list operations.
|
|
76
|
+
*
|
|
77
|
+
* @category Passkeys
|
|
78
|
+
*/
|
|
62
79
|
export type PasskeySummary = {
|
|
63
80
|
readonly _tag: "PasskeySummary";
|
|
64
81
|
readonly id: string;
|
|
@@ -71,20 +88,73 @@ export type PasskeySummary = {
|
|
|
71
88
|
readonly lastUsed?: number | undefined;
|
|
72
89
|
readonly createdAt: number;
|
|
73
90
|
};
|
|
91
|
+
/**
|
|
92
|
+
* Type guard for {@link PasskeySummary}.
|
|
93
|
+
*
|
|
94
|
+
* @category Passkeys
|
|
95
|
+
*/
|
|
74
96
|
export declare const isPasskeySummary: (payload: unknown) => payload is PasskeySummary;
|
|
97
|
+
/**
|
|
98
|
+
* Result payload returned when passkeys are updated in bulk for a user.
|
|
99
|
+
*
|
|
100
|
+
* @category Passkeys
|
|
101
|
+
*/
|
|
75
102
|
export type UpdatedPasskeys = {
|
|
76
103
|
_tag: "UpdatedPasskeys";
|
|
77
104
|
updated: ReadonlyArray<Passkey>;
|
|
78
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* Type guard for {@link UpdatedPasskeys}.
|
|
108
|
+
*
|
|
109
|
+
* @category Passkeys
|
|
110
|
+
*/
|
|
79
111
|
export declare const isUpdatedPasskeys: (payload: unknown) => payload is UpdatedPasskeys;
|
|
112
|
+
/**
|
|
113
|
+
* Credential identifiers returned by passkey deletion operations.
|
|
114
|
+
*
|
|
115
|
+
* @category Passkeys
|
|
116
|
+
*/
|
|
117
|
+
export type Credential = {
|
|
118
|
+
credentialId: string;
|
|
119
|
+
userId: string;
|
|
120
|
+
rpId: string;
|
|
121
|
+
};
|
|
122
|
+
/**
|
|
123
|
+
* Result payload returned when all passkeys for a user have been deleted.
|
|
124
|
+
*
|
|
125
|
+
* @category Passkeys
|
|
126
|
+
*/
|
|
127
|
+
export type DeletedPasskeys = {
|
|
128
|
+
_tag: "DeletedPasskeys";
|
|
129
|
+
deleted: ReadonlyArray<Credential>;
|
|
130
|
+
};
|
|
131
|
+
/**
|
|
132
|
+
* Type guard for {@link DeletedPasskeys}.
|
|
133
|
+
*
|
|
134
|
+
* @category Passkeys
|
|
135
|
+
*/
|
|
136
|
+
export declare const isDeletedPasskeys: (payload: unknown) => payload is DeletedPasskeys;
|
|
137
|
+
/**
|
|
138
|
+
* A single page of passkey summaries returned by {@link listPasskeys}.
|
|
139
|
+
*
|
|
140
|
+
* @category Passkeys
|
|
141
|
+
*/
|
|
80
142
|
export type FindAllPasskeys = {
|
|
81
143
|
readonly _tag: "FindAllPasskeys";
|
|
82
144
|
readonly cursor: string | null;
|
|
83
145
|
readonly records: ReadonlyArray<PasskeySummary>;
|
|
84
146
|
};
|
|
85
147
|
export declare const isFindAllPasskeys: (payload: unknown) => payload is FindAllPasskeys;
|
|
86
|
-
|
|
87
|
-
|
|
148
|
+
/**
|
|
149
|
+
* Client-facing credential update payload returned by
|
|
150
|
+
* {@link updatePasskeyUsernames}.
|
|
151
|
+
*
|
|
152
|
+
* Each entry describes one credential to update on the user's device.
|
|
153
|
+
*
|
|
154
|
+
* @category Passkeys
|
|
155
|
+
*/
|
|
156
|
+
export type UpdatedCredentials = {
|
|
157
|
+
_tag: "UpdatedCredentials";
|
|
88
158
|
credentials: ReadonlyArray<{
|
|
89
159
|
rpId: string;
|
|
90
160
|
userId: string;
|
|
@@ -92,41 +162,203 @@ export type UpdatedPasskeyUsernames = {
|
|
|
92
162
|
displayName: string;
|
|
93
163
|
}>;
|
|
94
164
|
};
|
|
95
|
-
|
|
165
|
+
/**
|
|
166
|
+
* Narrow an unknown value to an `UpdatedCredentials`-tagged payload.
|
|
167
|
+
*
|
|
168
|
+
* @category Passkeys
|
|
169
|
+
*/
|
|
170
|
+
export declare const isUpdatedUserDetails: (payload: unknown) => payload is UpdatedCredentials;
|
|
171
|
+
/**
|
|
172
|
+
* Options for fetching a single passkey.
|
|
173
|
+
*
|
|
174
|
+
* @category Passkeys
|
|
175
|
+
*/
|
|
96
176
|
export interface GetPasskeyOptions extends AuthenticatedOptions {
|
|
177
|
+
/**
|
|
178
|
+
* Identifier of the passkey to fetch.
|
|
179
|
+
*/
|
|
97
180
|
passkeyId: string;
|
|
98
181
|
}
|
|
182
|
+
/**
|
|
183
|
+
* Fetch a single passkey from the Passlock vault.
|
|
184
|
+
*
|
|
185
|
+
* @param options Request options including the passkey identifier.
|
|
186
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
187
|
+
* @returns An Effect that succeeds with the requested passkey.
|
|
188
|
+
*
|
|
189
|
+
* @category Passkeys
|
|
190
|
+
*/
|
|
99
191
|
export declare const getPasskey: (options: GetPasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
192
|
+
/**
|
|
193
|
+
* Options for deleting a single passkey.
|
|
194
|
+
*
|
|
195
|
+
* @category Passkeys
|
|
196
|
+
*/
|
|
100
197
|
export interface DeletePasskeyOptions extends AuthenticatedOptions {
|
|
198
|
+
/**
|
|
199
|
+
* Identifier of the passkey to delete.
|
|
200
|
+
*/
|
|
101
201
|
passkeyId: string;
|
|
102
202
|
}
|
|
203
|
+
/**
|
|
204
|
+
* Delete a single passkey from the Passlock vault.
|
|
205
|
+
*
|
|
206
|
+
* This only removes the server-side record. It does not remove the passkey
|
|
207
|
+
* from the user's device.
|
|
208
|
+
*
|
|
209
|
+
* @param options Request options including the passkey identifier.
|
|
210
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
211
|
+
* @returns An Effect that succeeds with the deleted passkey.
|
|
212
|
+
*
|
|
213
|
+
* @category Passkeys
|
|
214
|
+
*/
|
|
103
215
|
export declare const deletePasskey: (options: DeletePasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
104
216
|
/**
|
|
217
|
+
* Options for assigning a custom user ID to a single passkey.
|
|
218
|
+
*
|
|
105
219
|
* @category Passkeys
|
|
106
220
|
*/
|
|
107
221
|
export interface AssignUserOptions extends AuthenticatedOptions {
|
|
222
|
+
/**
|
|
223
|
+
* Identifier of the passkey to update.
|
|
224
|
+
*/
|
|
108
225
|
passkeyId: string;
|
|
109
226
|
/**
|
|
110
227
|
* Custom User ID to align with your own systems
|
|
111
228
|
*/
|
|
112
229
|
userId: string;
|
|
113
230
|
}
|
|
231
|
+
/**
|
|
232
|
+
* Assign a custom user ID to a single passkey.
|
|
233
|
+
*
|
|
234
|
+
* This updates Passlock's mapping for the passkey. It does not change the
|
|
235
|
+
* underlying WebAuthn credential's `userId`.
|
|
236
|
+
*
|
|
237
|
+
* @param options Request options including the passkey identifier and custom user ID.
|
|
238
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
239
|
+
* @returns An Effect that succeeds with the updated passkey.
|
|
240
|
+
*
|
|
241
|
+
* @category Passkeys
|
|
242
|
+
*/
|
|
114
243
|
export declare const assignUser: (options: AssignUserOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
244
|
+
/**
|
|
245
|
+
* Options for updating a single passkey's metadata.
|
|
246
|
+
*
|
|
247
|
+
* @category Passkeys
|
|
248
|
+
*/
|
|
115
249
|
export interface UpdatePasskeyOptions extends AuthenticatedOptions {
|
|
250
|
+
/**
|
|
251
|
+
* Identifier of the passkey to update.
|
|
252
|
+
*/
|
|
116
253
|
passkeyId: string;
|
|
254
|
+
/**
|
|
255
|
+
* Custom user ID to associate with the passkey.
|
|
256
|
+
*/
|
|
117
257
|
userId?: string;
|
|
258
|
+
/**
|
|
259
|
+
* Username metadata stored alongside the passkey.
|
|
260
|
+
*/
|
|
118
261
|
username?: string;
|
|
119
262
|
}
|
|
263
|
+
/**
|
|
264
|
+
* Update a single passkey's custom user ID and/or username metadata.
|
|
265
|
+
*
|
|
266
|
+
* @param options Request options including the passkey identifier and fields to update.
|
|
267
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
268
|
+
* @returns An Effect that succeeds with the updated passkey.
|
|
269
|
+
*
|
|
270
|
+
* @category Passkeys
|
|
271
|
+
*/
|
|
120
272
|
export declare const updatePasskey: (options: UpdatePasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
121
|
-
|
|
273
|
+
/**
|
|
274
|
+
* Options for deleting all passkeys belonging to a user.
|
|
275
|
+
*
|
|
276
|
+
* @category Passkeys
|
|
277
|
+
*/
|
|
278
|
+
export interface DeleteUserPasskeysOptions extends AuthenticatedOptions {
|
|
279
|
+
/**
|
|
280
|
+
* Custom user ID whose passkeys should be deleted.
|
|
281
|
+
*/
|
|
282
|
+
userId: string;
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Delete all passkeys associated with a custom user ID.
|
|
286
|
+
*
|
|
287
|
+
* The resulting `deleted` credentials can be passed to
|
|
288
|
+
* `@passlock/client` to remove the corresponding passkeys from the user's
|
|
289
|
+
* device.
|
|
290
|
+
*
|
|
291
|
+
* @param options Request options including the custom user ID.
|
|
292
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
293
|
+
* @returns An Effect that succeeds with the deleted credential identifiers.
|
|
294
|
+
*
|
|
295
|
+
* @category Passkeys
|
|
296
|
+
*/
|
|
297
|
+
export declare const deleteUserPasskeys: (options: DeleteUserPasskeysOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<DeletedPasskeys, NotFoundError | ForbiddenError>;
|
|
298
|
+
/**
|
|
299
|
+
* Options for updating the username and display name for all passkeys that
|
|
300
|
+
* share a custom user ID.
|
|
301
|
+
*
|
|
302
|
+
* @category Passkeys
|
|
303
|
+
*/
|
|
304
|
+
export interface UpdateUsernamesOptions extends AuthenticatedOptions {
|
|
305
|
+
/**
|
|
306
|
+
* Custom user ID whose passkeys should be updated.
|
|
307
|
+
*/
|
|
122
308
|
userId: string;
|
|
309
|
+
/**
|
|
310
|
+
* Username to write back to each stored passkey.
|
|
311
|
+
*/
|
|
123
312
|
username: string;
|
|
313
|
+
/**
|
|
314
|
+
* Optional display name to return for client-side credential updates.
|
|
315
|
+
*
|
|
316
|
+
* When omitted, the returned credentials use `username` as the display name.
|
|
317
|
+
*/
|
|
124
318
|
displayName?: string;
|
|
125
319
|
}
|
|
126
|
-
|
|
320
|
+
/**
|
|
321
|
+
* Update the username metadata for all passkeys belonging to a custom user ID.
|
|
322
|
+
*
|
|
323
|
+
* The resulting payload is designed to be passed to
|
|
324
|
+
* `@passlock/client` so matching device credentials can be updated.
|
|
325
|
+
*
|
|
326
|
+
* @param options Request options including the custom user ID and username metadata.
|
|
327
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
328
|
+
* @returns An Effect that succeeds with one credential update per updated passkey.
|
|
329
|
+
*
|
|
330
|
+
* @category Passkeys
|
|
331
|
+
*/
|
|
332
|
+
export declare const updatePasskeyUsernames: (options: UpdateUsernamesOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<UpdatedCredentials, NotFoundError | ForbiddenError>;
|
|
333
|
+
/**
|
|
334
|
+
* Stream every passkey summary for a tenancy across all result pages.
|
|
335
|
+
*
|
|
336
|
+
* @param options Request options used for each paginated request.
|
|
337
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
338
|
+
* @returns A stream of passkey summaries.
|
|
339
|
+
*
|
|
340
|
+
* @category Passkeys
|
|
341
|
+
*/
|
|
127
342
|
export declare const listPasskeysStream: (options: AuthenticatedOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Stream.Stream<PasskeySummary, ForbiddenError>;
|
|
343
|
+
/**
|
|
344
|
+
* Options for listing passkeys.
|
|
345
|
+
*
|
|
346
|
+
* @category Passkeys
|
|
347
|
+
*/
|
|
128
348
|
export interface ListPasskeyOptions extends AuthenticatedOptions {
|
|
349
|
+
/**
|
|
350
|
+
* Pagination cursor returned from a previous {@link listPasskeys} call.
|
|
351
|
+
*/
|
|
129
352
|
cursor?: string;
|
|
130
353
|
}
|
|
354
|
+
/**
|
|
355
|
+
* Fetch a single page of passkey summaries for a tenancy.
|
|
356
|
+
*
|
|
357
|
+
* @param options Request options including an optional pagination cursor.
|
|
358
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
359
|
+
* @returns An Effect that succeeds with one page of passkey summaries.
|
|
360
|
+
*
|
|
361
|
+
* @category Passkeys
|
|
362
|
+
*/
|
|
131
363
|
export declare const listPasskeys: (options: ListPasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<FindAllPasskeys, ForbiddenError>;
|
|
132
364
|
//# sourceMappingURL=passkey.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/passkey/passkey.ts"],"names":[],"mappings":"AAAA,OAAO,EAGL,MAAM,EACN,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/passkey/passkey.ts"],"names":[],"mappings":"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"}
|
package/dist/passkey/passkey.js
CHANGED
|
@@ -2,11 +2,37 @@ import { Array, Chunk, Effect, Match, Option, pipe, Schema, Stream, } from "effe
|
|
|
2
2
|
import { fetchNetwork, matchStatus, NetworkFetchLive, } from "../network.js";
|
|
3
3
|
import { FindAllPasskeys as FindAllPasskeysSchema, ForbiddenError, NotFoundError, } from "../schemas/index.js";
|
|
4
4
|
import * as PasskeySchemas from "../schemas/passkey.js";
|
|
5
|
+
/**
|
|
6
|
+
* Type guard for {@link Passkey}.
|
|
7
|
+
*
|
|
8
|
+
* @category Passkeys
|
|
9
|
+
*/
|
|
5
10
|
export const isPasskey = (payload) => Schema.is(PasskeySchemas.Passkey)(payload);
|
|
11
|
+
/**
|
|
12
|
+
* Type guard for {@link PasskeySummary}.
|
|
13
|
+
*
|
|
14
|
+
* @category Passkeys
|
|
15
|
+
*/
|
|
6
16
|
export const isPasskeySummary = (payload) => Schema.is(PasskeySchemas.PasskeySummary)(payload);
|
|
17
|
+
/**
|
|
18
|
+
* Type guard for {@link UpdatedPasskeys}.
|
|
19
|
+
*
|
|
20
|
+
* @category Passkeys
|
|
21
|
+
*/
|
|
7
22
|
export const isUpdatedPasskeys = (payload) => Schema.is(PasskeySchemas.UpdatedPasskeys)(payload);
|
|
23
|
+
/**
|
|
24
|
+
* Type guard for {@link DeletedPasskeys}.
|
|
25
|
+
*
|
|
26
|
+
* @category Passkeys
|
|
27
|
+
*/
|
|
28
|
+
export const isDeletedPasskeys = (payload) => Schema.is(PasskeySchemas.DeletedPasskeys)(payload);
|
|
8
29
|
export const isFindAllPasskeys = (payload) => Schema.is(PasskeySchemas.FindAllPasskeys)(payload);
|
|
9
|
-
|
|
30
|
+
/**
|
|
31
|
+
* Narrow an unknown value to an `UpdatedCredentials`-tagged payload.
|
|
32
|
+
*
|
|
33
|
+
* @category Passkeys
|
|
34
|
+
*/
|
|
35
|
+
export const isUpdatedUserDetails = (payload) => {
|
|
10
36
|
if (typeof payload !== "object")
|
|
11
37
|
return false;
|
|
12
38
|
if (payload === null)
|
|
@@ -15,15 +41,24 @@ export const isUpdatedPasskeyUsernames = (payload) => {
|
|
|
15
41
|
return false;
|
|
16
42
|
if (typeof payload._tag !== "string")
|
|
17
43
|
return false;
|
|
18
|
-
if (payload._tag !== "
|
|
44
|
+
if (payload._tag !== "UpdatedCredentials")
|
|
19
45
|
return false;
|
|
20
46
|
return true;
|
|
21
47
|
};
|
|
22
|
-
/* END
|
|
48
|
+
/* END UpdatedUserDetails */
|
|
23
49
|
const authorizationHeaders = (apiKey) => ({
|
|
24
50
|
authorization: `Bearer ${apiKey}`,
|
|
25
51
|
});
|
|
26
52
|
const decodeResponseJson = (response, schema) => pipe(response.json, Effect.flatMap(Schema.decodeUnknown(schema)));
|
|
53
|
+
/**
|
|
54
|
+
* Fetch a single passkey from the Passlock vault.
|
|
55
|
+
*
|
|
56
|
+
* @param options Request options including the passkey identifier.
|
|
57
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
58
|
+
* @returns An Effect that succeeds with the requested passkey.
|
|
59
|
+
*
|
|
60
|
+
* @category Passkeys
|
|
61
|
+
*/
|
|
27
62
|
export const getPasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
28
63
|
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
29
64
|
const { tenancyId, passkeyId } = options;
|
|
@@ -42,6 +77,18 @@ export const getPasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effec
|
|
|
42
77
|
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
43
78
|
ParseError: (err) => Effect.die(err),
|
|
44
79
|
}), Effect.provide(fetchLayer));
|
|
80
|
+
/**
|
|
81
|
+
* Delete a single passkey from the Passlock vault.
|
|
82
|
+
*
|
|
83
|
+
* This only removes the server-side record. It does not remove the passkey
|
|
84
|
+
* from the user's device.
|
|
85
|
+
*
|
|
86
|
+
* @param options Request options including the passkey identifier.
|
|
87
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
88
|
+
* @returns An Effect that succeeds with the deleted passkey.
|
|
89
|
+
*
|
|
90
|
+
* @category Passkeys
|
|
91
|
+
*/
|
|
45
92
|
export const deletePasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
46
93
|
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
47
94
|
const { tenancyId, passkeyId } = options;
|
|
@@ -61,6 +108,18 @@ export const deletePasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Ef
|
|
|
61
108
|
ParseError: (err) => Effect.die(err),
|
|
62
109
|
}), Effect.provide(fetchLayer));
|
|
63
110
|
// TODO reuse updatePasskey
|
|
111
|
+
/**
|
|
112
|
+
* Assign a custom user ID to a single passkey.
|
|
113
|
+
*
|
|
114
|
+
* This updates Passlock's mapping for the passkey. It does not change the
|
|
115
|
+
* underlying WebAuthn credential's `userId`.
|
|
116
|
+
*
|
|
117
|
+
* @param options Request options including the passkey identifier and custom user ID.
|
|
118
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
119
|
+
* @returns An Effect that succeeds with the updated passkey.
|
|
120
|
+
*
|
|
121
|
+
* @category Passkeys
|
|
122
|
+
*/
|
|
64
123
|
export const assignUser = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
65
124
|
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
66
125
|
const { userId, passkeyId } = options;
|
|
@@ -80,6 +139,15 @@ export const assignUser = (options, fetchLayer = NetworkFetchLive) => pipe(Effec
|
|
|
80
139
|
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
81
140
|
ParseError: (err) => Effect.die(err),
|
|
82
141
|
}), Effect.provide(fetchLayer));
|
|
142
|
+
/**
|
|
143
|
+
* Update a single passkey's custom user ID and/or username metadata.
|
|
144
|
+
*
|
|
145
|
+
* @param options Request options including the passkey identifier and fields to update.
|
|
146
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
147
|
+
* @returns An Effect that succeeds with the updated passkey.
|
|
148
|
+
*
|
|
149
|
+
* @category Passkeys
|
|
150
|
+
*/
|
|
83
151
|
export const updatePasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
84
152
|
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
85
153
|
const { userId, passkeyId, username } = options;
|
|
@@ -118,6 +186,56 @@ const updateUserPasskeys = (options, fetchLayer = NetworkFetchLive) => pipe(Effe
|
|
|
118
186
|
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
119
187
|
ParseError: (err) => Effect.die(err),
|
|
120
188
|
}), Effect.provide(fetchLayer));
|
|
189
|
+
/**
|
|
190
|
+
* Delete all passkeys associated with a custom user ID.
|
|
191
|
+
*
|
|
192
|
+
* The resulting `deleted` credentials can be passed to
|
|
193
|
+
* `@passlock/client` to remove the corresponding passkeys from the user's
|
|
194
|
+
* device.
|
|
195
|
+
*
|
|
196
|
+
* @param options Request options including the custom user ID.
|
|
197
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
198
|
+
* @returns An Effect that succeeds with the deleted credential identifiers.
|
|
199
|
+
*
|
|
200
|
+
* @category Passkeys
|
|
201
|
+
*/
|
|
202
|
+
export const deleteUserPasskeys = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
203
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
204
|
+
const { tenancyId, userId } = options;
|
|
205
|
+
const url = new URL(`/${tenancyId}/users/${userId}/passkeys/`, baseUrl);
|
|
206
|
+
const response = yield* fetchNetwork(url, "delete", { userId }, {
|
|
207
|
+
headers: authorizationHeaders(options.apiKey),
|
|
208
|
+
});
|
|
209
|
+
const encoded = yield* matchStatus(response, {
|
|
210
|
+
"2xx": (res) => decodeResponseJson(res, PasskeySchemas.DeletedPasskeysResponse),
|
|
211
|
+
orElse: (res) => decodeResponseJson(res, Schema.Union(NotFoundError, ForbiddenError)),
|
|
212
|
+
});
|
|
213
|
+
return yield* pipe(Match.value(encoded), Match.tag("DeletedPasskeys", (result) => Effect.succeed({
|
|
214
|
+
_tag: "DeletedPasskeys",
|
|
215
|
+
deleted: result.deleted.map((passkey) => ({
|
|
216
|
+
credentialId: passkey.credential.id,
|
|
217
|
+
userId: passkey.credential.userId,
|
|
218
|
+
rpId: passkey.credential.rpId,
|
|
219
|
+
})),
|
|
220
|
+
})), Match.tag("@error/NotFound", (err) => Effect.fail(err)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.exhaustive);
|
|
221
|
+
}), Effect.catchTags({
|
|
222
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
223
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
224
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
225
|
+
ParseError: (err) => Effect.die(err),
|
|
226
|
+
}), Effect.provide(fetchLayer));
|
|
227
|
+
/**
|
|
228
|
+
* Update the username metadata for all passkeys belonging to a custom user ID.
|
|
229
|
+
*
|
|
230
|
+
* The resulting payload is designed to be passed to
|
|
231
|
+
* `@passlock/client` so matching device credentials can be updated.
|
|
232
|
+
*
|
|
233
|
+
* @param options Request options including the custom user ID and username metadata.
|
|
234
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
235
|
+
* @returns An Effect that succeeds with one credential update per updated passkey.
|
|
236
|
+
*
|
|
237
|
+
* @category Passkeys
|
|
238
|
+
*/
|
|
121
239
|
export const updatePasskeyUsernames = (options, fetchLayer = NetworkFetchLive) => pipe(updateUserPasskeys(options, fetchLayer), Effect.map((result) => result.updated), Effect.map(Array.map((passkey) => {
|
|
122
240
|
return {
|
|
123
241
|
rpId: passkey.credential.rpId,
|
|
@@ -126,14 +244,32 @@ export const updatePasskeyUsernames = (options, fetchLayer = NetworkFetchLive) =
|
|
|
126
244
|
displayName: options.displayName ?? passkey.credential.username,
|
|
127
245
|
};
|
|
128
246
|
})), Effect.map((credentials) => ({
|
|
129
|
-
_tag: "
|
|
247
|
+
_tag: "UpdatedCredentials",
|
|
130
248
|
credentials,
|
|
131
249
|
})));
|
|
132
250
|
/* List Passkeys */
|
|
251
|
+
/**
|
|
252
|
+
* Stream every passkey summary for a tenancy across all result pages.
|
|
253
|
+
*
|
|
254
|
+
* @param options Request options used for each paginated request.
|
|
255
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
256
|
+
* @returns A stream of passkey summaries.
|
|
257
|
+
*
|
|
258
|
+
* @category Passkeys
|
|
259
|
+
*/
|
|
133
260
|
export const listPasskeysStream = (options, fetchLayer = NetworkFetchLive) => pipe(Stream.paginateChunkEffect(null, (cursor) => pipe(listPasskeys(cursor ? { ...options, cursor } : options, fetchLayer), Effect.map((result) => [
|
|
134
261
|
Chunk.fromIterable(result.records),
|
|
135
262
|
Option.fromNullable(result.cursor),
|
|
136
263
|
]))));
|
|
264
|
+
/**
|
|
265
|
+
* Fetch a single page of passkey summaries for a tenancy.
|
|
266
|
+
*
|
|
267
|
+
* @param options Request options including an optional pagination cursor.
|
|
268
|
+
* @param fetchLayer Optional fetch service override for testing or custom runtimes.
|
|
269
|
+
* @returns An Effect that succeeds with one page of passkey summaries.
|
|
270
|
+
*
|
|
271
|
+
* @category Passkeys
|
|
272
|
+
*/
|
|
137
273
|
export const listPasskeys = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
138
274
|
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
139
275
|
const { tenancyId } = options;
|