@passlock/server 2.1.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.
- package/README.md +45 -0
- package/README.template.md +45 -0
- package/dist/effect.d.ts +7 -0
- package/dist/effect.d.ts.map +1 -0
- package/dist/effect.js +4 -0
- package/dist/effect.js.map +1 -0
- package/dist/errors.d.ts +71 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +30 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +115 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +109 -0
- package/dist/index.js.map +1 -0
- package/dist/network.d.ts +134 -0
- package/dist/network.d.ts.map +1 -0
- package/dist/network.js +172 -0
- package/dist/network.js.map +1 -0
- package/dist/passkey/passkey.d.ts +132 -0
- package/dist/passkey/passkey.d.ts.map +1 -0
- package/dist/passkey/passkey.js +158 -0
- package/dist/passkey/passkey.js.map +1 -0
- package/dist/principal/principal.d.ts +22 -0
- package/dist/principal/principal.d.ts.map +1 -0
- package/dist/principal/principal.js +65 -0
- package/dist/principal/principal.js.map +1 -0
- package/dist/safe.d.ts +154 -0
- package/dist/safe.d.ts.map +1 -0
- package/dist/safe.js +147 -0
- package/dist/safe.js.map +1 -0
- package/dist/schemas/errors.d.ts +2 -0
- package/dist/schemas/errors.d.ts.map +1 -0
- package/dist/schemas/errors.js +72 -0
- package/dist/schemas/errors.js.map +1 -0
- package/dist/schemas/index.d.ts +5 -0
- package/dist/schemas/index.d.ts.map +1 -0
- package/dist/schemas/index.js +5 -0
- package/dist/schemas/index.js.map +1 -0
- package/dist/schemas/passkey.d.ts +85 -0
- package/dist/schemas/passkey.d.ts.map +1 -0
- package/dist/schemas/passkey.js +64 -0
- package/dist/schemas/passkey.js.map +1 -0
- package/dist/schemas/principal.d.ts +88 -0
- package/dist/schemas/principal.d.ts.map +1 -0
- package/dist/schemas/principal.js +46 -0
- package/dist/schemas/principal.js.map +1 -0
- package/dist/schemas/satisfy.d.ts +2 -0
- package/dist/schemas/satisfy.d.ts.map +1 -0
- package/dist/schemas/satisfy.js +2 -0
- package/dist/schemas/satisfy.js.map +1 -0
- package/dist/schemas/signup.d.ts +13 -0
- package/dist/schemas/signup.d.ts.map +1 -0
- package/dist/schemas/signup.js +11 -0
- package/dist/schemas/signup.js.map +1 -0
- package/dist/shared.d.ts +19 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +9 -0
- package/dist/shared.js.map +1 -0
- package/package.json +93 -0
package/dist/network.js
ADDED
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { Context, Data, Effect, Layer } from "effect";
|
|
2
|
+
/**
|
|
3
|
+
* Effect service tag for the fetch implementation.
|
|
4
|
+
*
|
|
5
|
+
* Supply this service with `Effect.provide` / layers to swap fetch behavior
|
|
6
|
+
* in tests or alternate runtimes.
|
|
7
|
+
*/
|
|
8
|
+
export class NetworkFetch extends Context.Tag("NetworkFetch")() {
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Default live fetch layer backed by `globalThis.fetch`.
|
|
12
|
+
*/
|
|
13
|
+
export const NetworkFetchLive = Layer.succeed(NetworkFetch, globalThis.fetch);
|
|
14
|
+
/**
|
|
15
|
+
* Raised when the underlying fetch call fails before a response is received.
|
|
16
|
+
*/
|
|
17
|
+
export class NetworkRequestError extends Data.TaggedError("@error/NetworkRequest") {
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Raised when request payload serialization fails.
|
|
21
|
+
*/
|
|
22
|
+
export class NetworkPayloadError extends Data.TaggedError("@error/NetworkPayload") {
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Raised when response body parsing fails.
|
|
26
|
+
*/
|
|
27
|
+
export class NetworkResponseError extends Data.TaggedError("@error/NetworkResponse") {
|
|
28
|
+
}
|
|
29
|
+
const formatMessage = (cause, fallback) => cause instanceof Error ? cause.message : fallback;
|
|
30
|
+
/**
|
|
31
|
+
* Convert an HTTP status code into its status family bucket.
|
|
32
|
+
*
|
|
33
|
+
* Returns `undefined` for codes outside the 2xx-5xx families.
|
|
34
|
+
*/
|
|
35
|
+
export const statusToCase = (status) => {
|
|
36
|
+
if (status >= 200 && status <= 299)
|
|
37
|
+
return "2xx";
|
|
38
|
+
if (status >= 300 && status <= 399)
|
|
39
|
+
return "3xx";
|
|
40
|
+
if (status >= 400 && status <= 499)
|
|
41
|
+
return "4xx";
|
|
42
|
+
if (status >= 500 && status <= 599)
|
|
43
|
+
return "5xx";
|
|
44
|
+
return undefined;
|
|
45
|
+
};
|
|
46
|
+
const resolveStatusHandler = (response, cases) => {
|
|
47
|
+
const statusCase = statusToCase(response.status);
|
|
48
|
+
if (!statusCase)
|
|
49
|
+
return cases.orElse;
|
|
50
|
+
const handler = cases[statusCase];
|
|
51
|
+
return (handler ?? cases.orElse);
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Route a {@link NetworkResponse} to the first matching status-family handler.
|
|
55
|
+
*
|
|
56
|
+
* Invariants:
|
|
57
|
+
* - `2xx`/`3xx`/`4xx`/`5xx` handlers are matched by status family.
|
|
58
|
+
* - `orElse` is always used as a fallback when no specific family handler exists.
|
|
59
|
+
* - The returned effect type is inferred as the union of all handler effects.
|
|
60
|
+
*/
|
|
61
|
+
export const matchStatus = (response, cases) => Effect.suspend(() => {
|
|
62
|
+
const handler = resolveStatusHandler(response, cases);
|
|
63
|
+
return handler(response);
|
|
64
|
+
});
|
|
65
|
+
/**
|
|
66
|
+
* Serialize an optional payload into a JSON request body.
|
|
67
|
+
*
|
|
68
|
+
* Invariants:
|
|
69
|
+
* - `GET` requests cannot carry a payload and fail with `NetworkPayloadError`.
|
|
70
|
+
* - when a payload exists, `content-type: application/json` is emitted.
|
|
71
|
+
*/
|
|
72
|
+
const serializePayload = (method, payload) => {
|
|
73
|
+
if (payload === undefined) {
|
|
74
|
+
return Effect.succeed(undefined);
|
|
75
|
+
}
|
|
76
|
+
if (method === "get") {
|
|
77
|
+
return Effect.fail(new NetworkPayloadError({
|
|
78
|
+
method,
|
|
79
|
+
message: "GET requests do not support a request body",
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
return Effect.try({
|
|
83
|
+
try: () => ({
|
|
84
|
+
body: JSON.stringify(payload),
|
|
85
|
+
headers: { "content-type": "application/json" },
|
|
86
|
+
}),
|
|
87
|
+
catch: (cause) => new NetworkPayloadError({
|
|
88
|
+
method,
|
|
89
|
+
message: formatMessage(cause, "Unable to serialize payload to JSON"),
|
|
90
|
+
}),
|
|
91
|
+
});
|
|
92
|
+
};
|
|
93
|
+
/**
|
|
94
|
+
* Convert `Headers` into a readonly plain record.
|
|
95
|
+
*/
|
|
96
|
+
export const headersToRecord = (headers) => Object.fromEntries(headers.entries());
|
|
97
|
+
const normalizeHeaders = (headers) => {
|
|
98
|
+
if (headers instanceof Headers) {
|
|
99
|
+
return new Headers(headers);
|
|
100
|
+
}
|
|
101
|
+
if (Array.isArray(headers)) {
|
|
102
|
+
return new Headers(headers);
|
|
103
|
+
}
|
|
104
|
+
return new Headers(headers);
|
|
105
|
+
};
|
|
106
|
+
const mergeHeaders = (...headers) => Object.assign({}, ...headers);
|
|
107
|
+
/**
|
|
108
|
+
* Build a lazy, memoized JSON parser effect from a response.
|
|
109
|
+
*
|
|
110
|
+
* Invariants:
|
|
111
|
+
* - parsing happens on effect execution, not during response construction.
|
|
112
|
+
* - parsing uses `response.clone()` so the original response body remains untouched.
|
|
113
|
+
*/
|
|
114
|
+
const makeJsonEffect = (response, context) => {
|
|
115
|
+
let cached;
|
|
116
|
+
return Effect.tryPromise({
|
|
117
|
+
try: () => {
|
|
118
|
+
cached = cached ?? response.clone().json();
|
|
119
|
+
return cached;
|
|
120
|
+
},
|
|
121
|
+
catch: (cause) => new NetworkResponseError({
|
|
122
|
+
method: context.method,
|
|
123
|
+
url: context.url,
|
|
124
|
+
message: formatMessage(cause, "Unable to parse response JSON"),
|
|
125
|
+
}),
|
|
126
|
+
});
|
|
127
|
+
};
|
|
128
|
+
const toNetworkResponse = (response, context) => ({
|
|
129
|
+
status: response.status,
|
|
130
|
+
statusText: response.statusText,
|
|
131
|
+
statusMessage: response.statusText,
|
|
132
|
+
headers: headersToRecord(response.headers),
|
|
133
|
+
json: makeJsonEffect(response, context),
|
|
134
|
+
});
|
|
135
|
+
/**
|
|
136
|
+
* Execute a fetch request using the injected {@link NetworkFetch} service.
|
|
137
|
+
*
|
|
138
|
+
* Invariants:
|
|
139
|
+
* - method is always normalized to upper-case before dispatch.
|
|
140
|
+
* - JSON payload (if present) is serialized before request execution.
|
|
141
|
+
* - caller headers override payload-derived headers when keys overlap.
|
|
142
|
+
* - the returned `NetworkResponse.json` remains lazy.
|
|
143
|
+
*/
|
|
144
|
+
export const fetchNetwork = (url, method, payload, options) => Effect.gen(function* () {
|
|
145
|
+
const requestUrl = String(url);
|
|
146
|
+
const context = { method, url: requestUrl };
|
|
147
|
+
const fetchImpl = yield* NetworkFetch;
|
|
148
|
+
const serialized = yield* serializePayload(method, payload);
|
|
149
|
+
const providedHeaders = options?.headers
|
|
150
|
+
? headersToRecord(normalizeHeaders(options.headers))
|
|
151
|
+
: {};
|
|
152
|
+
const requestHeaders = mergeHeaders(serialized?.headers ?? {}, providedHeaders);
|
|
153
|
+
const hasHeaders = Object.keys(requestHeaders).length > 0;
|
|
154
|
+
const response = yield* Effect.tryPromise({
|
|
155
|
+
try: () => fetchImpl(requestUrl, {
|
|
156
|
+
method: method.toUpperCase(),
|
|
157
|
+
...(hasHeaders ? { headers: requestHeaders } : {}),
|
|
158
|
+
...(serialized
|
|
159
|
+
? {
|
|
160
|
+
body: serialized.body,
|
|
161
|
+
}
|
|
162
|
+
: {}),
|
|
163
|
+
}),
|
|
164
|
+
catch: (cause) => new NetworkRequestError({
|
|
165
|
+
method,
|
|
166
|
+
url: requestUrl,
|
|
167
|
+
message: formatMessage(cause, "Network request failed"),
|
|
168
|
+
}),
|
|
169
|
+
});
|
|
170
|
+
return toNetworkResponse(response, context);
|
|
171
|
+
});
|
|
172
|
+
//# sourceMappingURL=network.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"network.js","sourceRoot":"","sources":["../src/network.ts"],"names":[],"mappings":"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","sourcesContent":["import { Context, Data, Effect, Layer } from \"effect\"\n\n/**\n * Supported HTTP methods accepted by {@link fetchNetwork}.\n */\nexport type NetworkMethod = \"get\" | \"post\" | \"delete\" | \"patch\"\n\n/**\n * Lightweight response model used by this package.\n *\n * Invariants:\n * - `json` is lazy: parsing only happens when the effect is run.\n * - `json` is memoized per response wrapper, so repeated evaluation does not\n * parse the same payload multiple times.\n */\nexport interface NetworkResponse {\n readonly status: number\n readonly statusText: string\n readonly statusMessage: string\n readonly headers: Readonly<Record<string, string>>\n readonly json: Effect.Effect<unknown, NetworkResponseError>\n}\n\n/**\n * Accepted request header input formats.\n */\nexport type NetworkHeaders =\n | Headers\n | Readonly<Record<string, string>>\n | Array<[string, string]>\n\n/**\n * Optional request options for {@link fetchNetwork}.\n */\nexport interface FetchNetworkOptions {\n readonly headers?: NetworkHeaders\n}\n\n/**\n * Effect service tag for the fetch implementation.\n *\n * Supply this service with `Effect.provide` / layers to swap fetch behavior\n * in tests or alternate runtimes.\n */\nexport class NetworkFetch extends Context.Tag(\"NetworkFetch\")<\n NetworkFetch,\n typeof fetch\n>() {}\n\n/**\n * Default live fetch layer backed by `globalThis.fetch`.\n */\nexport const NetworkFetchLive: Layer.Layer<NetworkFetch> = Layer.succeed(\n NetworkFetch,\n globalThis.fetch\n)\n\n/**\n * HTTP status buckets used by {@link matchStatus}.\n */\nexport type NetworkResponseStatusCase = \"2xx\" | \"3xx\" | \"4xx\" | \"5xx\"\n\ntype MatchStatusHandler<\n Resp extends NetworkResponse = NetworkResponse,\n A = unknown,\n E = unknown,\n> = (response: Resp) => Effect.Effect<A, E, never>\n\ntype HandlerEffect<\n Cases extends MatchStatusCases<Resp>,\n Resp extends NetworkResponse,\n Case extends NetworkResponseStatusCase | \"orElse\",\n> = Case extends keyof Cases\n ? NonNullable<Cases[Case]> extends MatchStatusHandler<Resp>\n ? ReturnType<NonNullable<Cases[Case]>>\n : never\n : never\n\ntype MatchStatusEffectUnion<\n Cases extends MatchStatusCases<Resp>,\n Resp extends NetworkResponse,\n> =\n | HandlerEffect<Cases, Resp, \"2xx\">\n | HandlerEffect<Cases, Resp, \"3xx\">\n | HandlerEffect<Cases, Resp, \"4xx\">\n | HandlerEffect<Cases, Resp, \"5xx\">\n | HandlerEffect<Cases, Resp, \"orElse\">\n\ntype MatchStatusResolvedHandler<\n Cases extends MatchStatusCases<Resp>,\n Resp extends NetworkResponse,\n> = NonNullable<\n Cases[\"2xx\"] | Cases[\"3xx\"] | Cases[\"4xx\"] | Cases[\"5xx\"] | Cases[\"orElse\"]\n>\n\ntype EffectSuccess<T> =\n T extends Effect.Effect<infer A, unknown, unknown> ? A : never\n\ntype EffectError<T> =\n T extends Effect.Effect<unknown, infer E, unknown> ? E : never\n\ntype EffectContext<T> =\n T extends Effect.Effect<unknown, unknown, infer R> ? R : never\n\n/**\n * Handlers used by {@link matchStatus}.\n *\n * Invariants:\n * - `orElse` is always required.\n * - Specific status family handlers are optional and fall back to `orElse`\n * when missing.\n */\nexport interface MatchStatusCases<\n Resp extends NetworkResponse = NetworkResponse,\n> {\n readonly \"2xx\"?: MatchStatusHandler<Resp>\n readonly \"3xx\"?: MatchStatusHandler<Resp>\n readonly \"4xx\"?: MatchStatusHandler<Resp>\n readonly \"5xx\"?: MatchStatusHandler<Resp>\n readonly orElse: MatchStatusHandler<Resp>\n}\n\ntype RequestContext = {\n readonly method: NetworkMethod\n readonly url: string\n}\n\n/**\n * Raised when the underlying fetch call fails before a response is received.\n */\nexport class NetworkRequestError extends Data.TaggedError(\n \"@error/NetworkRequest\"\n)<{\n readonly method: NetworkMethod\n readonly url: string\n readonly message: string\n}> {}\n\n/**\n * Raised when request payload serialization fails.\n */\nexport class NetworkPayloadError extends Data.TaggedError(\n \"@error/NetworkPayload\"\n)<{\n readonly method: NetworkMethod\n readonly message: string\n}> {}\n\n/**\n * Raised when response body parsing fails.\n */\nexport class NetworkResponseError extends Data.TaggedError(\n \"@error/NetworkResponse\"\n)<{\n readonly method: NetworkMethod\n readonly url: string\n readonly message: string\n}> {}\n\nconst formatMessage = (cause: unknown, fallback: string): string =>\n cause instanceof Error ? cause.message : fallback\n\n/**\n * Convert an HTTP status code into its status family bucket.\n *\n * Returns `undefined` for codes outside the 2xx-5xx families.\n */\nexport const statusToCase = (\n status: number\n): NetworkResponseStatusCase | undefined => {\n if (status >= 200 && status <= 299) return \"2xx\"\n if (status >= 300 && status <= 399) return \"3xx\"\n if (status >= 400 && status <= 499) return \"4xx\"\n if (status >= 500 && status <= 599) return \"5xx\"\n\n return undefined\n}\n\nconst resolveStatusHandler = <\n Resp extends NetworkResponse,\n Cases extends MatchStatusCases<Resp>,\n>(\n response: Resp,\n cases: Cases\n): MatchStatusResolvedHandler<Cases, Resp> => {\n const statusCase = statusToCase(response.status)\n if (!statusCase)\n return cases.orElse as MatchStatusResolvedHandler<Cases, Resp>\n\n const handler = cases[statusCase]\n return (handler ?? cases.orElse) as MatchStatusResolvedHandler<Cases, Resp>\n}\n\n/**\n * Route a {@link NetworkResponse} to the first matching status-family handler.\n *\n * Invariants:\n * - `2xx`/`3xx`/`4xx`/`5xx` handlers are matched by status family.\n * - `orElse` is always used as a fallback when no specific family handler exists.\n * - The returned effect type is inferred as the union of all handler effects.\n */\nexport const matchStatus = <\n Resp extends NetworkResponse,\n Cases extends MatchStatusCases<Resp>,\n>(\n response: Resp,\n cases: Cases\n): Effect.Effect<\n EffectSuccess<MatchStatusEffectUnion<Cases, Resp>>,\n EffectError<MatchStatusEffectUnion<Cases, Resp>>,\n EffectContext<MatchStatusEffectUnion<Cases, Resp>>\n> =>\n Effect.suspend(() => {\n const handler = resolveStatusHandler(response, cases)\n return handler(response)\n }) as Effect.Effect<\n EffectSuccess<MatchStatusEffectUnion<Cases, Resp>>,\n EffectError<MatchStatusEffectUnion<Cases, Resp>>,\n EffectContext<MatchStatusEffectUnion<Cases, Resp>>\n >\n\n/**\n * Serialize an optional payload into a JSON request body.\n *\n * Invariants:\n * - `GET` requests cannot carry a payload and fail with `NetworkPayloadError`.\n * - when a payload exists, `content-type: application/json` is emitted.\n */\nconst serializePayload = (\n method: NetworkMethod,\n payload?: unknown\n): Effect.Effect<\n | {\n readonly body: string\n readonly headers: Readonly<Record<string, string>>\n }\n | undefined,\n NetworkPayloadError\n> => {\n if (payload === undefined) {\n return Effect.succeed(undefined)\n }\n\n if (method === \"get\") {\n return Effect.fail(\n new NetworkPayloadError({\n method,\n message: \"GET requests do not support a request body\",\n })\n )\n }\n\n return Effect.try({\n try: () => ({\n body: JSON.stringify(payload),\n headers: { \"content-type\": \"application/json\" },\n }),\n catch: (cause) =>\n new NetworkPayloadError({\n method,\n message: formatMessage(cause, \"Unable to serialize payload to JSON\"),\n }),\n })\n}\n\n/**\n * Convert `Headers` into a readonly plain record.\n */\nexport const headersToRecord = (\n headers: Headers\n): Readonly<Record<string, string>> => Object.fromEntries(headers.entries())\n\nconst normalizeHeaders = (headers: NetworkHeaders): Headers => {\n if (headers instanceof Headers) {\n return new Headers(headers)\n }\n\n if (Array.isArray(headers)) {\n return new Headers(headers)\n }\n\n return new Headers(headers)\n}\n\nconst mergeHeaders = (\n ...headers: ReadonlyArray<Readonly<Record<string, string>>>\n): Readonly<Record<string, string>> => Object.assign({}, ...headers)\n\n/**\n * Build a lazy, memoized JSON parser effect from a response.\n *\n * Invariants:\n * - parsing happens on effect execution, not during response construction.\n * - parsing uses `response.clone()` so the original response body remains untouched.\n */\nconst makeJsonEffect = (\n response: Response,\n context: RequestContext\n): Effect.Effect<unknown, NetworkResponseError> => {\n let cached: Promise<unknown> | undefined\n\n return Effect.tryPromise({\n try: () => {\n cached = cached ?? response.clone().json()\n return cached\n },\n catch: (cause) =>\n new NetworkResponseError({\n method: context.method,\n url: context.url,\n message: formatMessage(cause, \"Unable to parse response JSON\"),\n }),\n })\n}\n\nconst toNetworkResponse = (\n response: Response,\n context: RequestContext\n): NetworkResponse => ({\n status: response.status,\n statusText: response.statusText,\n statusMessage: response.statusText,\n headers: headersToRecord(response.headers),\n json: makeJsonEffect(response, context),\n})\n\n/**\n * Execute a fetch request using the injected {@link NetworkFetch} service.\n *\n * Invariants:\n * - method is always normalized to upper-case before dispatch.\n * - JSON payload (if present) is serialized before request execution.\n * - caller headers override payload-derived headers when keys overlap.\n * - the returned `NetworkResponse.json` remains lazy.\n */\nexport const fetchNetwork = (\n url: string | URL,\n method: NetworkMethod,\n payload?: unknown,\n options?: FetchNetworkOptions\n): Effect.Effect<\n NetworkResponse,\n NetworkRequestError | NetworkPayloadError,\n NetworkFetch\n> =>\n Effect.gen(function* () {\n const requestUrl = String(url)\n const context: RequestContext = { method, url: requestUrl }\n const fetchImpl = yield* NetworkFetch\n const serialized = yield* serializePayload(method, payload)\n\n const providedHeaders = options?.headers\n ? headersToRecord(normalizeHeaders(options.headers))\n : {}\n\n const requestHeaders = mergeHeaders(\n serialized?.headers ?? {},\n providedHeaders\n )\n const hasHeaders = Object.keys(requestHeaders).length > 0\n\n const response = yield* Effect.tryPromise({\n try: () =>\n fetchImpl(requestUrl, {\n method: method.toUpperCase(),\n ...(hasHeaders ? { headers: requestHeaders } : {}),\n ...(serialized\n ? {\n body: serialized.body,\n }\n : {}),\n }),\n catch: (cause) =>\n new NetworkRequestError({\n method,\n url: requestUrl,\n message: formatMessage(cause, \"Network request failed\"),\n }),\n })\n\n return toNetworkResponse(response, context)\n })\n"]}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { Effect, type Layer, Stream } from "effect";
|
|
2
|
+
import { type NetworkFetch } from "../network.js";
|
|
3
|
+
import { ForbiddenError, NotFoundError } from "../schemas/index.js";
|
|
4
|
+
import * as PasskeySchemas from "../schemas/passkey.js";
|
|
5
|
+
import type { AuthenticatedOptions } from "../shared.js";
|
|
6
|
+
/**
|
|
7
|
+
* WebAuthn specific passkey data
|
|
8
|
+
*/
|
|
9
|
+
export type Credential = {
|
|
10
|
+
id: string;
|
|
11
|
+
userId: string;
|
|
12
|
+
username: string;
|
|
13
|
+
aaguid: string;
|
|
14
|
+
backedUp: boolean;
|
|
15
|
+
counter: number;
|
|
16
|
+
deviceType: PasskeySchemas.CredentialDeviceType;
|
|
17
|
+
transports: ReadonlyArray<PasskeySchemas.Transports>;
|
|
18
|
+
publicKey: Uint8Array<ArrayBufferLike>;
|
|
19
|
+
rpId: string;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Passkeys are usually synced across devices **but only within
|
|
23
|
+
* a specific platform/ecosystem** e.g. a passkey created on Apple
|
|
24
|
+
* devices would typically be synced across devices sharing the same
|
|
25
|
+
* iCloud ID.
|
|
26
|
+
*
|
|
27
|
+
* However, if the user also wants to sign in from their Windows
|
|
28
|
+
* or Android/Chrome devices they will need an additional passkey.
|
|
29
|
+
* Therefore when listing the passkeys registered to a user's account
|
|
30
|
+
* it's a good idea to tell them which platform the passkeys relate to.
|
|
31
|
+
*
|
|
32
|
+
* We've also included links to icons (SVG) so you can give your users
|
|
33
|
+
* a quick visual indication.
|
|
34
|
+
*/
|
|
35
|
+
export type Platform = {
|
|
36
|
+
name?: string | undefined;
|
|
37
|
+
icon?: string | undefined;
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* The server-side component of a passkey
|
|
41
|
+
*
|
|
42
|
+
* @category Passkeys
|
|
43
|
+
*/
|
|
44
|
+
export type Passkey = {
|
|
45
|
+
_tag: "Passkey";
|
|
46
|
+
/**
|
|
47
|
+
* Not to be confused with the credential.id
|
|
48
|
+
*/
|
|
49
|
+
id: string;
|
|
50
|
+
/**
|
|
51
|
+
* Not to be confused with the credential.userId
|
|
52
|
+
*/
|
|
53
|
+
userId?: string | undefined;
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
credential: Credential;
|
|
56
|
+
platform?: Platform | undefined;
|
|
57
|
+
lastUsed?: number | undefined;
|
|
58
|
+
createdAt: number;
|
|
59
|
+
updatedAt: number;
|
|
60
|
+
};
|
|
61
|
+
export declare const isPasskey: (payload: unknown) => payload is Passkey;
|
|
62
|
+
export type PasskeySummary = {
|
|
63
|
+
readonly _tag: "PasskeySummary";
|
|
64
|
+
readonly id: string;
|
|
65
|
+
readonly userId: string;
|
|
66
|
+
readonly enabled: boolean;
|
|
67
|
+
readonly credential: {
|
|
68
|
+
readonly id: string;
|
|
69
|
+
readonly userId: string;
|
|
70
|
+
};
|
|
71
|
+
readonly lastUsed?: number | undefined;
|
|
72
|
+
readonly createdAt: number;
|
|
73
|
+
};
|
|
74
|
+
export declare const isPasskeySummary: (payload: unknown) => payload is PasskeySummary;
|
|
75
|
+
export type UpdatedPasskeys = {
|
|
76
|
+
_tag: "UpdatedPasskeys";
|
|
77
|
+
updated: ReadonlyArray<Passkey>;
|
|
78
|
+
};
|
|
79
|
+
export declare const isUpdatedPasskeys: (payload: unknown) => payload is UpdatedPasskeys;
|
|
80
|
+
export type FindAllPasskeys = {
|
|
81
|
+
readonly _tag: "FindAllPasskeys";
|
|
82
|
+
readonly cursor: string | null;
|
|
83
|
+
readonly records: ReadonlyArray<PasskeySummary>;
|
|
84
|
+
};
|
|
85
|
+
export declare const isFindAllPasskeys: (payload: unknown) => payload is FindAllPasskeys;
|
|
86
|
+
export type UpdatedPasskeyUsernames = {
|
|
87
|
+
_tag: "UpdatedPasskeyUsernames";
|
|
88
|
+
credentials: ReadonlyArray<{
|
|
89
|
+
rpId: string;
|
|
90
|
+
userId: string;
|
|
91
|
+
username: string;
|
|
92
|
+
displayName: string;
|
|
93
|
+
}>;
|
|
94
|
+
};
|
|
95
|
+
export declare const isUpdatedPasskeyUsernames: (payload: unknown) => payload is UpdatedPasskeyUsernames;
|
|
96
|
+
export interface GetPasskeyOptions extends AuthenticatedOptions {
|
|
97
|
+
passkeyId: string;
|
|
98
|
+
}
|
|
99
|
+
export declare const getPasskey: (options: GetPasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
100
|
+
export interface DeletePasskeyOptions extends AuthenticatedOptions {
|
|
101
|
+
passkeyId: string;
|
|
102
|
+
}
|
|
103
|
+
export declare const deletePasskey: (options: DeletePasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
104
|
+
/**
|
|
105
|
+
* @category Passkeys
|
|
106
|
+
*/
|
|
107
|
+
export interface AssignUserOptions extends AuthenticatedOptions {
|
|
108
|
+
passkeyId: string;
|
|
109
|
+
/**
|
|
110
|
+
* Custom User ID to align with your own systems
|
|
111
|
+
*/
|
|
112
|
+
userId: string;
|
|
113
|
+
}
|
|
114
|
+
export declare const assignUser: (options: AssignUserOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
115
|
+
export interface UpdatePasskeyOptions extends AuthenticatedOptions {
|
|
116
|
+
passkeyId: string;
|
|
117
|
+
userId?: string;
|
|
118
|
+
username?: string;
|
|
119
|
+
}
|
|
120
|
+
export declare const updatePasskey: (options: UpdatePasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<Passkey, NotFoundError | ForbiddenError>;
|
|
121
|
+
export interface UpdatePasskeyUsernamesOptions extends AuthenticatedOptions {
|
|
122
|
+
userId: string;
|
|
123
|
+
username: string;
|
|
124
|
+
displayName?: string;
|
|
125
|
+
}
|
|
126
|
+
export declare const updatePasskeyUsernames: (options: UpdatePasskeyUsernamesOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<UpdatedPasskeyUsernames, NotFoundError | ForbiddenError>;
|
|
127
|
+
export declare const listPasskeysStream: (options: AuthenticatedOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Stream.Stream<PasskeySummary, ForbiddenError>;
|
|
128
|
+
export interface ListPasskeyOptions extends AuthenticatedOptions {
|
|
129
|
+
cursor?: string;
|
|
130
|
+
}
|
|
131
|
+
export declare const listPasskeys: (options: ListPasskeyOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<FindAllPasskeys, ForbiddenError>;
|
|
132
|
+
//# sourceMappingURL=passkey.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey.d.ts","sourceRoot":"","sources":["../../src/passkey/passkey.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { Array, Chunk, Effect, Match, Option, pipe, Schema, Stream, } from "effect";
|
|
2
|
+
import { fetchNetwork, matchStatus, NetworkFetchLive, } from "../network.js";
|
|
3
|
+
import { FindAllPasskeys as FindAllPasskeysSchema, ForbiddenError, NotFoundError, } from "../schemas/index.js";
|
|
4
|
+
import * as PasskeySchemas from "../schemas/passkey.js";
|
|
5
|
+
export const isPasskey = (payload) => Schema.is(PasskeySchemas.Passkey)(payload);
|
|
6
|
+
export const isPasskeySummary = (payload) => Schema.is(PasskeySchemas.PasskeySummary)(payload);
|
|
7
|
+
export const isUpdatedPasskeys = (payload) => Schema.is(PasskeySchemas.UpdatedPasskeys)(payload);
|
|
8
|
+
export const isFindAllPasskeys = (payload) => Schema.is(PasskeySchemas.FindAllPasskeys)(payload);
|
|
9
|
+
export const isUpdatedPasskeyUsernames = (payload) => {
|
|
10
|
+
if (typeof payload !== "object")
|
|
11
|
+
return false;
|
|
12
|
+
if (payload === null)
|
|
13
|
+
return false;
|
|
14
|
+
if (!("_tag" in payload))
|
|
15
|
+
return false;
|
|
16
|
+
if (typeof payload._tag !== "string")
|
|
17
|
+
return false;
|
|
18
|
+
if (payload._tag !== "UpdatedPasskeyUsernames")
|
|
19
|
+
return false;
|
|
20
|
+
return true;
|
|
21
|
+
};
|
|
22
|
+
/* END UpdatedPasskeyUsernames */
|
|
23
|
+
const authorizationHeaders = (apiKey) => ({
|
|
24
|
+
authorization: `Bearer ${apiKey}`,
|
|
25
|
+
});
|
|
26
|
+
const decodeResponseJson = (response, schema) => pipe(response.json, Effect.flatMap(Schema.decodeUnknown(schema)));
|
|
27
|
+
export const getPasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
28
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
29
|
+
const { tenancyId, passkeyId } = options;
|
|
30
|
+
const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl);
|
|
31
|
+
const response = yield* fetchNetwork(url, "get", undefined, {
|
|
32
|
+
headers: authorizationHeaders(options.apiKey),
|
|
33
|
+
});
|
|
34
|
+
const encoded = yield* matchStatus(response, {
|
|
35
|
+
"2xx": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),
|
|
36
|
+
orElse: (res) => decodeResponseJson(res, Schema.Union(ForbiddenError, NotFoundError)),
|
|
37
|
+
});
|
|
38
|
+
return yield* pipe(Match.value(encoded), Match.tag("Passkey", (data) => Effect.succeed(data)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.tag("@error/NotFound", (err) => Effect.fail(err)), Match.exhaustive);
|
|
39
|
+
}), Effect.catchTags({
|
|
40
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
41
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
42
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
43
|
+
ParseError: (err) => Effect.die(err),
|
|
44
|
+
}), Effect.provide(fetchLayer));
|
|
45
|
+
export const deletePasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
46
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
47
|
+
const { tenancyId, passkeyId } = options;
|
|
48
|
+
const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl);
|
|
49
|
+
const response = yield* fetchNetwork(url, "delete", undefined, {
|
|
50
|
+
headers: authorizationHeaders(options.apiKey),
|
|
51
|
+
});
|
|
52
|
+
const encoded = yield* matchStatus(response, {
|
|
53
|
+
"2xx": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),
|
|
54
|
+
orElse: (res) => decodeResponseJson(res, Schema.Union(ForbiddenError, NotFoundError)),
|
|
55
|
+
});
|
|
56
|
+
return yield* pipe(Match.value(encoded), Match.tag("Passkey", (deletedPasskey) => Effect.succeed(deletedPasskey)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.tag("@error/NotFound", (err) => Effect.fail(err)), Match.exhaustive);
|
|
57
|
+
}), Effect.catchTags({
|
|
58
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
59
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
60
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
61
|
+
ParseError: (err) => Effect.die(err),
|
|
62
|
+
}), Effect.provide(fetchLayer));
|
|
63
|
+
// TODO reuse updatePasskey
|
|
64
|
+
export const assignUser = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
65
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
66
|
+
const { userId, passkeyId } = options;
|
|
67
|
+
const { tenancyId } = options;
|
|
68
|
+
const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl);
|
|
69
|
+
const response = yield* fetchNetwork(url, "patch", { userId }, {
|
|
70
|
+
headers: authorizationHeaders(options.apiKey),
|
|
71
|
+
});
|
|
72
|
+
const encoded = yield* matchStatus(response, {
|
|
73
|
+
"2xx": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),
|
|
74
|
+
orElse: (res) => decodeResponseJson(res, Schema.Union(NotFoundError, ForbiddenError)),
|
|
75
|
+
});
|
|
76
|
+
return yield* pipe(Match.value(encoded), Match.tag("Passkey", (passkey) => Effect.succeed(passkey)), Match.tag("@error/NotFound", (err) => Effect.fail(err)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.exhaustive);
|
|
77
|
+
}), Effect.catchTags({
|
|
78
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
79
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
80
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
81
|
+
ParseError: (err) => Effect.die(err),
|
|
82
|
+
}), Effect.provide(fetchLayer));
|
|
83
|
+
export const updatePasskey = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
84
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
85
|
+
const { userId, passkeyId, username } = options;
|
|
86
|
+
const { tenancyId } = options;
|
|
87
|
+
const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl);
|
|
88
|
+
const response = yield* fetchNetwork(url, "patch", { userId, username }, {
|
|
89
|
+
headers: authorizationHeaders(options.apiKey),
|
|
90
|
+
});
|
|
91
|
+
const encoded = yield* matchStatus(response, {
|
|
92
|
+
"2xx": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),
|
|
93
|
+
orElse: (res) => decodeResponseJson(res, Schema.Union(NotFoundError, ForbiddenError)),
|
|
94
|
+
});
|
|
95
|
+
return yield* pipe(Match.value(encoded), Match.tag("Passkey", (passkey) => Effect.succeed(passkey)), Match.tag("@error/NotFound", (err) => Effect.fail(err)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.exhaustive);
|
|
96
|
+
}), Effect.catchTags({
|
|
97
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
98
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
99
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
100
|
+
ParseError: (err) => Effect.die(err),
|
|
101
|
+
}), Effect.provide(fetchLayer));
|
|
102
|
+
const updateUserPasskeys = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
103
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
104
|
+
const { userId, username } = options;
|
|
105
|
+
const { tenancyId } = options;
|
|
106
|
+
const url = new URL(`/${tenancyId}/users/${userId}/passkeys/`, baseUrl);
|
|
107
|
+
const response = yield* fetchNetwork(url, "patch", { userId, username }, {
|
|
108
|
+
headers: authorizationHeaders(options.apiKey),
|
|
109
|
+
});
|
|
110
|
+
const encoded = yield* matchStatus(response, {
|
|
111
|
+
"2xx": (res) => decodeResponseJson(res, PasskeySchemas.UpdatedPasskeys),
|
|
112
|
+
orElse: (res) => decodeResponseJson(res, Schema.Union(NotFoundError, ForbiddenError)),
|
|
113
|
+
});
|
|
114
|
+
return yield* pipe(Match.value(encoded), Match.tag("UpdatedPasskeys", (result) => Effect.succeed(result)), Match.tag("@error/NotFound", (err) => Effect.fail(err)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.exhaustive);
|
|
115
|
+
}), Effect.catchTags({
|
|
116
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
117
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
118
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
119
|
+
ParseError: (err) => Effect.die(err),
|
|
120
|
+
}), Effect.provide(fetchLayer));
|
|
121
|
+
export const updatePasskeyUsernames = (options, fetchLayer = NetworkFetchLive) => pipe(updateUserPasskeys(options, fetchLayer), Effect.map((result) => result.updated), Effect.map(Array.map((passkey) => {
|
|
122
|
+
return {
|
|
123
|
+
rpId: passkey.credential.rpId,
|
|
124
|
+
userId: passkey.credential.userId,
|
|
125
|
+
username: passkey.credential.username,
|
|
126
|
+
displayName: options.displayName ?? passkey.credential.username,
|
|
127
|
+
};
|
|
128
|
+
})), Effect.map((credentials) => ({
|
|
129
|
+
_tag: "UpdatedPasskeyUsernames",
|
|
130
|
+
credentials,
|
|
131
|
+
})));
|
|
132
|
+
/* List Passkeys */
|
|
133
|
+
export const listPasskeysStream = (options, fetchLayer = NetworkFetchLive) => pipe(Stream.paginateChunkEffect(null, (cursor) => pipe(listPasskeys(cursor ? { ...options, cursor } : options, fetchLayer), Effect.map((result) => [
|
|
134
|
+
Chunk.fromIterable(result.records),
|
|
135
|
+
Option.fromNullable(result.cursor),
|
|
136
|
+
]))));
|
|
137
|
+
export const listPasskeys = (options, fetchLayer = NetworkFetchLive) => pipe(Effect.gen(function* () {
|
|
138
|
+
const baseUrl = options.endpoint ?? "https://api.passlock.dev";
|
|
139
|
+
const { tenancyId } = options;
|
|
140
|
+
const url = new URL(`/${tenancyId}/passkeys/`, baseUrl);
|
|
141
|
+
if (options.cursor) {
|
|
142
|
+
url.searchParams.append("cursor", options.cursor);
|
|
143
|
+
}
|
|
144
|
+
const response = yield* fetchNetwork(url, "get", undefined, {
|
|
145
|
+
headers: authorizationHeaders(options.apiKey),
|
|
146
|
+
});
|
|
147
|
+
const encoded = yield* matchStatus(response, {
|
|
148
|
+
"2xx": (res) => decodeResponseJson(res, FindAllPasskeysSchema),
|
|
149
|
+
orElse: (res) => decodeResponseJson(res, ForbiddenError),
|
|
150
|
+
});
|
|
151
|
+
return yield* pipe(Match.value(encoded), Match.tag("FindAllPasskeys", (data) => Effect.succeed(data)), Match.tag("@error/Forbidden", (err) => Effect.fail(err)), Match.exhaustive);
|
|
152
|
+
}), Effect.catchTags({
|
|
153
|
+
"@error/NetworkPayload": (err) => Effect.die(err),
|
|
154
|
+
"@error/NetworkRequest": (err) => Effect.die(err),
|
|
155
|
+
"@error/NetworkResponse": (err) => Effect.die(err),
|
|
156
|
+
ParseError: (err) => Effect.die(err),
|
|
157
|
+
}), Effect.provide(fetchLayer));
|
|
158
|
+
//# sourceMappingURL=passkey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"passkey.js","sourceRoot":"","sources":["../../src/passkey/passkey.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n Array,\n Chunk,\n Effect,\n type Layer,\n Match,\n Option,\n pipe,\n Schema,\n Stream,\n} from \"effect\"\nimport type { satisfy } from \"src/schemas/satisfy.js\"\nimport {\n fetchNetwork,\n matchStatus,\n type NetworkFetch,\n NetworkFetchLive,\n type NetworkPayloadError,\n type NetworkRequestError,\n type NetworkResponse,\n type NetworkResponseError,\n} from \"../network.js\"\nimport {\n FindAllPasskeys as FindAllPasskeysSchema,\n ForbiddenError,\n NotFoundError,\n} from \"../schemas/index.js\"\nimport * as PasskeySchemas from \"../schemas/passkey.js\"\nimport type { AuthenticatedOptions } from \"../shared.js\"\n\n/* Passkey */\n\n/**\n * WebAuthn specific passkey data\n */\nexport type Credential = {\n id: string\n userId: string\n username: string\n aaguid: string\n backedUp: boolean\n counter: number\n deviceType: PasskeySchemas.CredentialDeviceType\n transports: ReadonlyArray<PasskeySchemas.Transports>\n publicKey: Uint8Array<ArrayBufferLike>\n rpId: string\n}\n\n/**\n * Passkeys are usually synced across devices **but only within\n * a specific platform/ecosystem** e.g. a passkey created on Apple\n * devices would typically be synced across devices sharing the same\n * iCloud ID.\n *\n * However, if the user also wants to sign in from their Windows\n * or Android/Chrome devices they will need an additional passkey.\n * Therefore when listing the passkeys registered to a user's account\n * it's a good idea to tell them which platform the passkeys relate to.\n *\n * We've also included links to icons (SVG) so you can give your users\n * a quick visual indication.\n */\nexport type Platform = {\n name?: string | undefined\n icon?: string | undefined\n}\n\n/**\n * The server-side component of a passkey\n *\n * @category Passkeys\n */\nexport type Passkey = {\n _tag: \"Passkey\"\n /**\n * Not to be confused with the credential.id\n */\n id: string\n /**\n * Not to be confused with the credential.userId\n */\n userId?: string | undefined\n enabled: boolean\n credential: Credential\n platform?: Platform | undefined\n lastUsed?: number | undefined\n createdAt: number\n updatedAt: number\n}\n\nexport const isPasskey = (payload: unknown): payload is Passkey =>\n Schema.is(PasskeySchemas.Passkey)(payload)\n\n/**\n * needed to ensure the Passkey === Passkey.Type\n * @internal\n * */\nexport type _Passkey = satisfy<typeof PasskeySchemas.Passkey.Type, Passkey>\n\n/* PasskeySummary */\n\nexport type PasskeySummary = {\n readonly _tag: \"PasskeySummary\"\n readonly id: string\n readonly userId: string\n readonly enabled: boolean\n readonly credential: {\n readonly id: string\n readonly userId: string\n }\n readonly lastUsed?: number | undefined\n readonly createdAt: number\n}\n\nexport const isPasskeySummary = (payload: unknown): payload is PasskeySummary =>\n Schema.is(PasskeySchemas.PasskeySummary)(payload)\n\n/**\n * needed to ensure the PasskeySummary === PasskeySummary.Type\n * @internal\n */\nexport type _PasskeySummary = satisfy<\n typeof PasskeySchemas.PasskeySummary.Type,\n PasskeySummary\n>\n\n/* UpdatedPasskeys */\n\nexport type UpdatedPasskeys = {\n _tag: \"UpdatedPasskeys\"\n updated: ReadonlyArray<Passkey>\n}\n\nexport const isUpdatedPasskeys = (\n payload: unknown\n): payload is UpdatedPasskeys =>\n Schema.is(PasskeySchemas.UpdatedPasskeys)(payload)\n\n/**\n * needed to ensure the UpdatedPasskeys === UpdatedPasskeys.Type\n * @internal\n * */\nexport type _UpdatedPasskeys = satisfy<\n typeof PasskeySchemas.UpdatedPasskeys.Type,\n UpdatedPasskeys\n>\n\n/* FindAllPasskeys */\n\nexport type FindAllPasskeys = {\n readonly _tag: \"FindAllPasskeys\"\n readonly cursor: string | null\n readonly records: ReadonlyArray<PasskeySummary>\n}\n\nexport const isFindAllPasskeys = (\n payload: unknown\n): payload is FindAllPasskeys =>\n Schema.is(PasskeySchemas.FindAllPasskeys)(payload)\n\n/**\n * needed to ensure the FindAllPasskeys === FindAllPasskeys.Type\n * @internal\n */\nexport type _FindAllPasskeys = satisfy<\n typeof FindAllPasskeysSchema.Type,\n FindAllPasskeys\n>\n\n/* UpdatedPasskeyUsernames (update names by userId) */\n\nexport type UpdatedPasskeyUsernames = {\n _tag: \"UpdatedPasskeyUsernames\"\n credentials: ReadonlyArray<{\n rpId: string\n userId: string\n username: string\n displayName: string\n }>\n}\n\nexport const isUpdatedPasskeyUsernames = (\n payload: unknown\n): payload is UpdatedPasskeyUsernames => {\n if (typeof payload !== \"object\") return false\n if (payload === null) return false\n if (!(\"_tag\" in payload)) return false\n if (typeof payload._tag !== \"string\") return false\n if (payload._tag !== \"UpdatedPasskeyUsernames\") return false\n\n return true\n}\n\n/* END UpdatedPasskeyUsernames */\n\nconst authorizationHeaders = (apiKey: string) => ({\n authorization: `Bearer ${apiKey}`,\n})\n\nconst decodeResponseJson = <A, I, R>(\n response: NetworkResponse,\n schema: Schema.Schema<A, I, R>\n) => pipe(response.json, Effect.flatMap(Schema.decodeUnknown(schema)))\n\n/* Get Passkey */\n\nexport interface GetPasskeyOptions extends AuthenticatedOptions {\n passkeyId: string\n}\n\nexport const getPasskey = (\n options: GetPasskeyOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<Passkey, NotFoundError | ForbiddenError> =>\n pipe(\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\"\n const { tenancyId, passkeyId } = options\n\n const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl)\n\n const response = yield* fetchNetwork(url, \"get\", undefined, {\n headers: authorizationHeaders(options.apiKey),\n })\n\n const encoded: Passkey | ForbiddenError | NotFoundError =\n yield* matchStatus(response, {\n \"2xx\": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),\n orElse: (res) =>\n decodeResponseJson(\n res,\n Schema.Union(ForbiddenError, NotFoundError)\n ),\n })\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"Passkey\", (data) => Effect.succeed(data)),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.tag(\"@error/NotFound\", (err) => Effect.fail(err)),\n Match.exhaustive\n )\n }),\n Effect.catchTags({\n \"@error/NetworkPayload\": (err: NetworkPayloadError) => Effect.die(err),\n \"@error/NetworkRequest\": (err: NetworkRequestError) => Effect.die(err),\n \"@error/NetworkResponse\": (err: NetworkResponseError) => Effect.die(err),\n ParseError: (err) => Effect.die(err),\n }),\n Effect.provide(fetchLayer)\n )\n\n/* Delete Passkey */\n\nexport interface DeletePasskeyOptions extends AuthenticatedOptions {\n passkeyId: string\n}\n\nexport const deletePasskey = (\n options: DeletePasskeyOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<Passkey, NotFoundError | ForbiddenError> =>\n pipe(\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\"\n const { tenancyId, passkeyId } = options\n\n const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl)\n\n const response = yield* fetchNetwork(url, \"delete\", undefined, {\n headers: authorizationHeaders(options.apiKey),\n })\n\n const encoded: Passkey | ForbiddenError | NotFoundError =\n yield* matchStatus(response, {\n \"2xx\": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),\n orElse: (res) =>\n decodeResponseJson(\n res,\n Schema.Union(ForbiddenError, NotFoundError)\n ),\n })\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"Passkey\", (deletedPasskey) =>\n Effect.succeed(deletedPasskey)\n ),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.tag(\"@error/NotFound\", (err) => Effect.fail(err)),\n Match.exhaustive\n )\n }),\n Effect.catchTags({\n \"@error/NetworkPayload\": (err: NetworkPayloadError) => Effect.die(err),\n \"@error/NetworkRequest\": (err: NetworkRequestError) => Effect.die(err),\n \"@error/NetworkResponse\": (err: NetworkResponseError) => Effect.die(err),\n ParseError: (err) => Effect.die(err),\n }),\n Effect.provide(fetchLayer)\n )\n\n/* Assign User */\n\n/**\n * @category Passkeys\n */\nexport interface AssignUserOptions extends AuthenticatedOptions {\n passkeyId: string\n\n /**\n * Custom User ID to align with your own systems\n */\n userId: string\n}\n\n// TODO reuse updatePasskey\nexport const assignUser = (\n options: AssignUserOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<Passkey, NotFoundError | ForbiddenError> =>\n pipe(\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\"\n const { userId, passkeyId } = options\n const { tenancyId } = options\n\n const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl)\n\n const response = yield* fetchNetwork(\n url,\n \"patch\",\n { userId },\n {\n headers: authorizationHeaders(options.apiKey),\n }\n )\n\n const encoded: Passkey | NotFoundError | ForbiddenError =\n yield* matchStatus(response, {\n \"2xx\": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),\n orElse: (res) =>\n decodeResponseJson(\n res,\n Schema.Union(NotFoundError, ForbiddenError)\n ),\n })\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"Passkey\", (passkey) => Effect.succeed(passkey)),\n Match.tag(\"@error/NotFound\", (err) => Effect.fail(err)),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.exhaustive\n )\n }),\n Effect.catchTags({\n \"@error/NetworkPayload\": (err: NetworkPayloadError) => Effect.die(err),\n \"@error/NetworkRequest\": (err: NetworkRequestError) => Effect.die(err),\n \"@error/NetworkResponse\": (err: NetworkResponseError) => Effect.die(err),\n ParseError: (err) => Effect.die(err),\n }),\n Effect.provide(fetchLayer)\n )\n\n/* Update passkey */\n\nexport interface UpdatePasskeyOptions extends AuthenticatedOptions {\n passkeyId: string\n userId?: string\n username?: string\n}\n\nexport const updatePasskey = (\n options: UpdatePasskeyOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<Passkey, NotFoundError | ForbiddenError> =>\n pipe(\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\"\n\n const { userId, passkeyId, username } = options\n const { tenancyId } = options\n\n const url = new URL(`/${tenancyId}/passkeys/${passkeyId}`, baseUrl)\n\n const response = yield* fetchNetwork(\n url,\n \"patch\",\n { userId, username },\n {\n headers: authorizationHeaders(options.apiKey),\n }\n )\n\n const encoded: Passkey | NotFoundError | ForbiddenError =\n yield* matchStatus(response, {\n \"2xx\": (res) => decodeResponseJson(res, PasskeySchemas.Passkey),\n orElse: (res) =>\n decodeResponseJson(\n res,\n Schema.Union(NotFoundError, ForbiddenError)\n ),\n })\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"Passkey\", (passkey) => Effect.succeed(passkey)),\n Match.tag(\"@error/NotFound\", (err) => Effect.fail(err)),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.exhaustive\n )\n }),\n Effect.catchTags({\n \"@error/NetworkPayload\": (err: NetworkPayloadError) => Effect.die(err),\n \"@error/NetworkRequest\": (err: NetworkRequestError) => Effect.die(err),\n \"@error/NetworkResponse\": (err: NetworkResponseError) => Effect.die(err),\n ParseError: (err) => Effect.die(err),\n }),\n Effect.provide(fetchLayer)\n )\n\n/* Update passkeys by userId (currently not exported) */\n\ninterface UpdateUserPasskeyOptions extends AuthenticatedOptions {\n userId: string\n username?: string\n}\n\nconst updateUserPasskeys = (\n options: UpdateUserPasskeyOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<UpdatedPasskeys, NotFoundError | ForbiddenError> =>\n pipe(\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\"\n\n const { userId, username } = options\n const { tenancyId } = options\n\n const url = new URL(`/${tenancyId}/users/${userId}/passkeys/`, baseUrl)\n\n const response = yield* fetchNetwork(\n url,\n \"patch\",\n { userId, username },\n {\n headers: authorizationHeaders(options.apiKey),\n }\n )\n\n const encoded: UpdatedPasskeys | NotFoundError | ForbiddenError =\n yield* matchStatus(response, {\n \"2xx\": (res) =>\n decodeResponseJson(res, PasskeySchemas.UpdatedPasskeys),\n orElse: (res) =>\n decodeResponseJson(\n res,\n Schema.Union(NotFoundError, ForbiddenError)\n ),\n })\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"UpdatedPasskeys\", (result) => Effect.succeed(result)),\n Match.tag(\"@error/NotFound\", (err) => Effect.fail(err)),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.exhaustive\n )\n }),\n Effect.catchTags({\n \"@error/NetworkPayload\": (err: NetworkPayloadError) => Effect.die(err),\n \"@error/NetworkRequest\": (err: NetworkRequestError) => Effect.die(err),\n \"@error/NetworkResponse\": (err: NetworkResponseError) => Effect.die(err),\n ParseError: (err) => Effect.die(err),\n }),\n Effect.provide(fetchLayer)\n )\n\n/* Update usernames by userId */\n\nexport interface UpdatePasskeyUsernamesOptions extends AuthenticatedOptions {\n userId: string\n username: string\n displayName?: string\n}\n\nexport const updatePasskeyUsernames = (\n options: UpdatePasskeyUsernamesOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<UpdatedPasskeyUsernames, NotFoundError | ForbiddenError> =>\n pipe(\n updateUserPasskeys(options, fetchLayer),\n Effect.map((result) => result.updated),\n Effect.map(\n Array.map((passkey) => {\n return {\n rpId: passkey.credential.rpId,\n userId: passkey.credential.userId,\n username: passkey.credential.username,\n displayName: options.displayName ?? passkey.credential.username,\n }\n })\n ),\n Effect.map((credentials) => ({\n _tag: \"UpdatedPasskeyUsernames\",\n credentials,\n }))\n )\n\n/* List Passkeys */\n\nexport const listPasskeysStream = (\n options: AuthenticatedOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Stream.Stream<PasskeySummary, ForbiddenError> =>\n pipe(\n Stream.paginateChunkEffect(null as string | null, (cursor) =>\n pipe(\n listPasskeys(cursor ? { ...options, cursor } : options, fetchLayer),\n Effect.map((result) => [\n Chunk.fromIterable(result.records),\n Option.fromNullable(result.cursor),\n ])\n )\n )\n )\n\nexport interface ListPasskeyOptions extends AuthenticatedOptions {\n cursor?: string\n}\n\nexport const listPasskeys = (\n options: ListPasskeyOptions,\n fetchLayer: Layer.Layer<NetworkFetch> = NetworkFetchLive\n): Effect.Effect<FindAllPasskeys, ForbiddenError> =>\n pipe(\n Effect.gen(function* () {\n const baseUrl = options.endpoint ?? \"https://api.passlock.dev\"\n const { tenancyId } = options\n\n const url = new URL(`/${tenancyId}/passkeys/`, baseUrl)\n if (options.cursor) {\n url.searchParams.append(\"cursor\", options.cursor)\n }\n\n const response = yield* fetchNetwork(url, \"get\", undefined, {\n headers: authorizationHeaders(options.apiKey),\n })\n\n const encoded: FindAllPasskeys | ForbiddenError = yield* matchStatus(\n response,\n {\n \"2xx\": (res) => decodeResponseJson(res, FindAllPasskeysSchema),\n orElse: (res) => decodeResponseJson(res, ForbiddenError),\n }\n )\n\n return yield* pipe(\n Match.value(encoded),\n Match.tag(\"FindAllPasskeys\", (data) => Effect.succeed(data)),\n Match.tag(\"@error/Forbidden\", (err) => Effect.fail(err)),\n Match.exhaustive\n )\n }),\n Effect.catchTags({\n \"@error/NetworkPayload\": (err: NetworkPayloadError) => Effect.die(err),\n \"@error/NetworkRequest\": (err: NetworkRequestError) => Effect.die(err),\n \"@error/NetworkResponse\": (err: NetworkResponseError) => Effect.die(err),\n ParseError: (err) => Effect.die(err),\n }),\n Effect.provide(fetchLayer)\n )\n"]}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Effect, type Layer } from "effect";
|
|
2
|
+
import { type NetworkFetch } from "../network.js";
|
|
3
|
+
import { ForbiddenError, InvalidCodeError } from "../schemas/errors.js";
|
|
4
|
+
import { type ExtendedPrincipal, type Principal } from "../schemas/principal.js";
|
|
5
|
+
import type { AuthenticatedOptions, PasslockOptions } from "../shared.js";
|
|
6
|
+
export interface ExchangeCodeOptions extends AuthenticatedOptions {
|
|
7
|
+
code: string;
|
|
8
|
+
}
|
|
9
|
+
export declare const exchangeCode: (options: ExchangeCodeOptions, fetchLayer?: Layer.Layer<NetworkFetch>) => Effect.Effect<ExtendedPrincipal, InvalidCodeError | ForbiddenError>;
|
|
10
|
+
declare const VerificationError_base: new <A extends Record<string, any> = {}>(args: import("effect/Types").Equals<A, {}> extends true ? void : { readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }) => import("effect/Cause").YieldableError & {
|
|
11
|
+
readonly _tag: "@error/Verification";
|
|
12
|
+
} & Readonly<A>;
|
|
13
|
+
export declare class VerificationError extends VerificationError_base<{
|
|
14
|
+
message: string;
|
|
15
|
+
}> {
|
|
16
|
+
}
|
|
17
|
+
export interface VerifyIdTokenOptions extends PasslockOptions {
|
|
18
|
+
token: string;
|
|
19
|
+
}
|
|
20
|
+
export declare const verifyIdToken: (options: VerifyIdTokenOptions) => Effect.Effect<Principal, VerificationError>;
|
|
21
|
+
export {};
|
|
22
|
+
//# sourceMappingURL=principal.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"principal.d.ts","sourceRoot":"","sources":["../../src/principal/principal.ts"],"names":[],"mappings":"AAAA,OAAO,EAAQ,MAAM,EAAE,KAAK,KAAK,EAAuB,MAAM,QAAQ,CAAA;AAGtE,OAAO,EAGL,KAAK,YAAY,EAKlB,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,cAAc,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,EACL,KAAK,iBAAiB,EAGtB,KAAK,SAAS,EACf,MAAM,yBAAyB,CAAA;AAEhC,OAAO,KAAK,EAAE,oBAAoB,EAAE,eAAe,EAAE,MAAM,cAAc,CAAA;AAEzE,MAAM,WAAW,mBAAoB,SAAQ,oBAAoB;IAC/D,IAAI,EAAE,MAAM,CAAA;CACb;AAED,eAAO,MAAM,YAAY,GACvB,SAAS,mBAAmB,EAC5B,aAAY,KAAK,CAAC,KAAK,CAAC,YAAY,CAAoB,KACvD,MAAM,CAAC,MAAM,CAAC,iBAAiB,EAAE,gBAAgB,GAAG,cAAc,CAiDlE,CAAA;;;;AAEH,qBAAa,iBAAkB,SAAQ,uBAAwC;IAC7E,OAAO,EAAE,MAAM,CAAA;CAChB,CAAC;CAAG;AAEL,MAAM,WAAW,oBAAqB,SAAQ,eAAe;IAC3D,KAAK,EAAE,MAAM,CAAA;CACd;AAED,eAAO,MAAM,aAAa,GACxB,SAAS,oBAAoB,KAC5B,MAAM,CAAC,MAAM,CAAC,SAAS,EAAE,iBAAiB,CAwC1C,CAAA"}
|