@atcute/client 3.0.1 → 4.0.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 +72 -13
- package/dist/client.d.ts +166 -0
- package/dist/client.js +192 -0
- package/dist/client.js.map +1 -0
- package/dist/credential-manager.d.ts +52 -43
- package/dist/credential-manager.js +51 -39
- package/dist/credential-manager.js.map +1 -1
- package/dist/fetch-handler.d.ts +2 -2
- package/dist/fetch-handler.js +1 -1
- package/dist/fetch-handler.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/lib/client.ts +461 -0
- package/lib/credential-manager.ts +129 -96
- package/lib/env.d.ts +1 -0
- package/lib/fetch-handler.ts +3 -3
- package/lib/index.ts +1 -1
- package/package.json +12 -11
- package/dist/lexicons.d.ts +0 -2199
- package/dist/lexicons.js +0 -4
- package/dist/lexicons.js.map +0 -1
- package/dist/rpc.d.ts +0 -96
- package/dist/rpc.js +0 -141
- package/dist/rpc.js.map +0 -1
- package/dist/utils/did.d.ts +0 -38
- package/dist/utils/did.js +0 -44
- package/dist/utils/did.js.map +0 -1
- package/dist/utils/http.d.ts +0 -7
- package/dist/utils/http.js +0 -20
- package/dist/utils/http.js.map +0 -1
- package/lib/lexicons.ts +0 -2204
- package/lib/rpc.ts +0 -262
- package/lib/utils/did.ts +0 -73
- package/lib/utils/http.ts +0 -27
package/README.md
CHANGED
|
@@ -7,24 +7,83 @@ lightweight and cute API client for AT Protocol.
|
|
|
7
7
|
be trusted in returning valid responses.
|
|
8
8
|
|
|
9
9
|
```ts
|
|
10
|
-
import {
|
|
10
|
+
import { Client, CredentialManager, ok, simpleFetchHandler } from '@atcute/client';
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
// import additional lexicons
|
|
13
|
+
import '@atcute/bluesky/lexicons';
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
// basic usage
|
|
16
|
+
{
|
|
17
|
+
const handler = simpleFetchHandler({ service: 'https://public.api.bsky.app' });
|
|
18
|
+
const rpc = new Client({ handler });
|
|
16
19
|
|
|
17
|
-
|
|
18
|
-
|
|
20
|
+
// explicit response handling
|
|
21
|
+
{
|
|
22
|
+
const { ok, data } = await rpc.get('app.bsky.actor.getProfile', {
|
|
23
|
+
params: {
|
|
24
|
+
actor: 'bsky.app',
|
|
25
|
+
},
|
|
26
|
+
});
|
|
19
27
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
28
|
+
if (!ok) {
|
|
29
|
+
switch (data.error) {
|
|
30
|
+
case 'InvalidRequest': {
|
|
31
|
+
// Account doesn't exist
|
|
32
|
+
break;
|
|
33
|
+
}
|
|
34
|
+
case 'AccountTakedown': {
|
|
35
|
+
// Account taken down
|
|
36
|
+
break;
|
|
37
|
+
}
|
|
38
|
+
case 'AccountDeactivated': {
|
|
39
|
+
// Account deactivated
|
|
40
|
+
break;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
25
44
|
|
|
26
|
-
|
|
27
|
-
|
|
45
|
+
if (ok) {
|
|
46
|
+
console.log(data.displayName);
|
|
47
|
+
// -> "Bluesky"
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// optimistic response handling
|
|
52
|
+
{
|
|
53
|
+
const data = await ok(
|
|
54
|
+
rpc.get('app.bsky.actor.getProfile', {
|
|
55
|
+
params: {
|
|
56
|
+
actor: 'bsky.app',
|
|
57
|
+
},
|
|
58
|
+
}),
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
console.log(data.displayName);
|
|
62
|
+
// -> "Bluesky"
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// performing authenticated requests
|
|
67
|
+
{
|
|
68
|
+
const manager = new CredentialManager({ service: 'https://bsky.social' });
|
|
69
|
+
const rpc = new Client({ handler: manager });
|
|
70
|
+
|
|
71
|
+
await manager.login({ identifier: 'example.com', password: 'ofki-yrwl-hmcc-cvau' });
|
|
72
|
+
|
|
73
|
+
console.log(manager.session);
|
|
74
|
+
// -> { refreshJwt: 'eyJhb...', ... }
|
|
75
|
+
|
|
76
|
+
const data = await ok(
|
|
77
|
+
rpc.get('com.atproto.identity.resolveHandle', {
|
|
78
|
+
params: {
|
|
79
|
+
handle: 'pfrazee.com',
|
|
80
|
+
},
|
|
81
|
+
}),
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
console.log(data.did);
|
|
85
|
+
// -> 'did:plc:ragtjsm2j2vknwkz3zp4oxrd'
|
|
86
|
+
}
|
|
28
87
|
```
|
|
29
88
|
|
|
30
89
|
by default, the API client only ships with the base AT Protocol (`com.atproto.*`) lexicons and
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import type { Did } from '@atcute/lexicons';
|
|
2
|
+
import type { XRPCProcedures, XRPCQueries } from '@atcute/lexicons/ambient';
|
|
3
|
+
import type { InferInput, InferOutput, ObjectSchema, XRPCBlobBodyParam, XRPCLexBodyParam, XRPCProcedureMetadata, XRPCQueryMetadata } from '@atcute/lexicons/validations';
|
|
4
|
+
import { type FetchHandler, type FetchHandlerObject } from './fetch-handler.js';
|
|
5
|
+
type RequiredKeysOf<TType extends object> = TType extends any ? Exclude<{
|
|
6
|
+
[Key in keyof TType]: TType extends Record<Key, TType[Key]> ? Key : never;
|
|
7
|
+
}[keyof TType], undefined> : never;
|
|
8
|
+
type HasRequiredKeys<TType extends object> = RequiredKeysOf<TType> extends never ? false : true;
|
|
9
|
+
type ResponseFormat = 'json' | 'blob' | 'bytes' | 'stream';
|
|
10
|
+
type FormattedResponse<TDef> = {
|
|
11
|
+
json: TDef extends XRPCQueryMetadata<any, infer Body extends XRPCLexBodyParam, any> ? InferOutput<Body['schema']> : TDef extends XRPCProcedureMetadata<any, any, infer Body extends XRPCLexBodyParam, any> ? InferOutput<Body['schema']> : unknown;
|
|
12
|
+
blob: Blob;
|
|
13
|
+
bytes: Uint8Array;
|
|
14
|
+
stream: ReadableStream<Uint8Array>;
|
|
15
|
+
};
|
|
16
|
+
type BaseRequestOptions = {
|
|
17
|
+
signal?: AbortSignal;
|
|
18
|
+
headers?: HeadersInit;
|
|
19
|
+
};
|
|
20
|
+
export type QueryRequestOptions<TDef> = BaseRequestOptions & (TDef extends XRPCQueryMetadata<infer Params, infer Output, any> ? (Params extends ObjectSchema ? {
|
|
21
|
+
params: InferInput<Params>;
|
|
22
|
+
} : {
|
|
23
|
+
params?: Record<string, unknown>;
|
|
24
|
+
}) & (Output extends XRPCLexBodyParam ? {
|
|
25
|
+
as?: ResponseFormat | null;
|
|
26
|
+
} : {
|
|
27
|
+
as: ResponseFormat | null;
|
|
28
|
+
}) : {
|
|
29
|
+
as: ResponseFormat | null;
|
|
30
|
+
params?: Record<string, unknown>;
|
|
31
|
+
});
|
|
32
|
+
export type ProcedureRequestOptions<TDef> = BaseRequestOptions & (TDef extends XRPCProcedureMetadata<infer Params, infer Input, infer Output, any> ? (Params extends ObjectSchema ? {
|
|
33
|
+
params: InferInput<Params>;
|
|
34
|
+
} : {
|
|
35
|
+
params?: Record<string, unknown>;
|
|
36
|
+
}) & (Input extends XRPCLexBodyParam ? {
|
|
37
|
+
input: InferInput<Input['schema']>;
|
|
38
|
+
} : Input extends XRPCBlobBodyParam ? {
|
|
39
|
+
input: Blob | ArrayBuffer | ArrayBufferView | ReadableStream;
|
|
40
|
+
} : {
|
|
41
|
+
input?: Record<string, unknown> | Blob | ArrayBuffer | ArrayBufferView | ReadableStream;
|
|
42
|
+
}) & (Output extends XRPCLexBodyParam ? {
|
|
43
|
+
as?: ResponseFormat | null;
|
|
44
|
+
} : {
|
|
45
|
+
as: ResponseFormat | null;
|
|
46
|
+
}) : {
|
|
47
|
+
as: ResponseFormat | null;
|
|
48
|
+
input?: Record<string, unknown> | Blob | ArrayBuffer | ArrayBufferView | ReadableStream;
|
|
49
|
+
params?: Record<string, unknown>;
|
|
50
|
+
});
|
|
51
|
+
/** standard XRPC error payload structure */
|
|
52
|
+
export type XRPCErrorPayload = {
|
|
53
|
+
/** error name */
|
|
54
|
+
error: string;
|
|
55
|
+
/** error description */
|
|
56
|
+
message?: string;
|
|
57
|
+
};
|
|
58
|
+
type BaseClientResponse = {
|
|
59
|
+
/** response status */
|
|
60
|
+
status: number;
|
|
61
|
+
/** response headers */
|
|
62
|
+
headers: Headers;
|
|
63
|
+
};
|
|
64
|
+
/** represents a successful response returned by the client */
|
|
65
|
+
export type SuccessClientResponse<TDef, TInit> = BaseClientResponse & {
|
|
66
|
+
ok: true;
|
|
67
|
+
/** response data */
|
|
68
|
+
data: TInit extends {
|
|
69
|
+
as: infer TFormat;
|
|
70
|
+
} ? TFormat extends ResponseFormat ? FormattedResponse<TDef>[TFormat] : TFormat extends null ? null : never : TDef extends XRPCQueryMetadata<any, infer Body extends XRPCLexBodyParam, any> ? InferOutput<Body['schema']> : TDef extends XRPCProcedureMetadata<any, any, infer Body extends XRPCLexBodyParam, any> ? InferOutput<Body['schema']> : never;
|
|
71
|
+
};
|
|
72
|
+
/** represents a failed response returned by the client */
|
|
73
|
+
export type FailedClientResponse = BaseClientResponse & {
|
|
74
|
+
ok: false;
|
|
75
|
+
/** response data */
|
|
76
|
+
data: XRPCErrorPayload;
|
|
77
|
+
};
|
|
78
|
+
/** represents a response returned by the client */
|
|
79
|
+
export type ClientResponse<TDef, TInit> = SuccessClientResponse<TDef, TInit> | FailedClientResponse;
|
|
80
|
+
/** options for configuring service proxying */
|
|
81
|
+
export type ServiceProxyOptions = {
|
|
82
|
+
/** DID identifier that the upstream service should look up */
|
|
83
|
+
did: Did;
|
|
84
|
+
/**
|
|
85
|
+
* the specific service ID within the resolved DID document's `service` array
|
|
86
|
+
* that the upstream service should forward requests to.
|
|
87
|
+
*
|
|
88
|
+
* must start with `#`
|
|
89
|
+
*
|
|
90
|
+
* common values include:
|
|
91
|
+
* - `#atproto_pds` (personal data server)
|
|
92
|
+
* - `#atproto_labeler` (labeler service)
|
|
93
|
+
* - `#bsky_chat` (Bluesky chat service)
|
|
94
|
+
*/
|
|
95
|
+
serviceId: `#${string}`;
|
|
96
|
+
};
|
|
97
|
+
/** options for configuring the client */
|
|
98
|
+
export type ClientOptions = {
|
|
99
|
+
/** the underlying fetch handler it should make requests with */
|
|
100
|
+
handler: FetchHandler | FetchHandlerObject;
|
|
101
|
+
/** service proxy configuration */
|
|
102
|
+
proxy?: ServiceProxyOptions | null;
|
|
103
|
+
};
|
|
104
|
+
/** XRPC API client */
|
|
105
|
+
export declare class Client<TQueries = XRPCQueries, TProcedures = XRPCProcedures> {
|
|
106
|
+
#private;
|
|
107
|
+
handler: FetchHandler;
|
|
108
|
+
proxy: ServiceProxyOptions | null;
|
|
109
|
+
constructor({ handler, proxy }: ClientOptions);
|
|
110
|
+
/**
|
|
111
|
+
* clones this XRPC client
|
|
112
|
+
* @param opts options to merge with
|
|
113
|
+
* @returns the cloned XRPC client
|
|
114
|
+
*/
|
|
115
|
+
clone({ handler, proxy }?: Partial<ClientOptions>): Client<TQueries, TProcedures>;
|
|
116
|
+
/**
|
|
117
|
+
* performs an XRPC query request (HTTP GET)
|
|
118
|
+
* @param name NSID of the query
|
|
119
|
+
* @param options query options
|
|
120
|
+
*/
|
|
121
|
+
get<TName extends keyof TQueries, TInit extends QueryRequestOptions<TQueries[TName]>>(name: TName, ...options: HasRequiredKeys<TInit> extends true ? [init: TInit] : [init?: TInit]): Promise<ClientResponse<TQueries[TName], TInit>>;
|
|
122
|
+
/**
|
|
123
|
+
* performs an XRPC procedure request (HTTP POST)
|
|
124
|
+
* @param name NSID of the procedure
|
|
125
|
+
* @param options procedure options
|
|
126
|
+
*/
|
|
127
|
+
post<TName extends keyof TProcedures, TInit extends ProcedureRequestOptions<TProcedures[TName]>>(name: TName, ...options: HasRequiredKeys<TInit> extends true ? [init: TInit] : [init?: TInit]): Promise<ClientResponse<TProcedures[TName], TInit>>;
|
|
128
|
+
}
|
|
129
|
+
export declare const isXRPCErrorPayload: (input: any) => input is XRPCErrorPayload;
|
|
130
|
+
type SuccessData<R> = R extends {
|
|
131
|
+
ok: true;
|
|
132
|
+
data: infer D;
|
|
133
|
+
} ? D : never;
|
|
134
|
+
/**
|
|
135
|
+
* takes in the response returned by the client, and either returns the data if
|
|
136
|
+
* it is a successful response, or throws if it's a failed response.
|
|
137
|
+
* @param input either a ClientResponse, or a promise that resolves to a ClientResponse
|
|
138
|
+
* @returns the data from a successful response
|
|
139
|
+
*
|
|
140
|
+
* @example
|
|
141
|
+
* const data = await ok(client.get('com.atproto.server.describeServer'));
|
|
142
|
+
* // ^? ComAtprotoServerDescribeServer.Output
|
|
143
|
+
*/
|
|
144
|
+
export declare const ok: {
|
|
145
|
+
<T extends Promise<ClientResponse<any, any>>>(promise: T): Promise<SuccessData<Awaited<T>>>;
|
|
146
|
+
<T extends ClientResponse<any, any>>(response: T): SuccessData<T>;
|
|
147
|
+
};
|
|
148
|
+
/** options when constructing a ClientResponseError */
|
|
149
|
+
export type ClientResponseErrorOptions = {
|
|
150
|
+
status: number;
|
|
151
|
+
headers?: Headers;
|
|
152
|
+
data: XRPCErrorPayload;
|
|
153
|
+
};
|
|
154
|
+
/** represents an error response returned by the client */
|
|
155
|
+
export declare class ClientResponseError extends Error {
|
|
156
|
+
/** error name returned by service */
|
|
157
|
+
readonly error: string;
|
|
158
|
+
/** error message returned by service */
|
|
159
|
+
readonly description?: string;
|
|
160
|
+
/** response status */
|
|
161
|
+
readonly status: number;
|
|
162
|
+
/** response headers */
|
|
163
|
+
readonly headers: Headers;
|
|
164
|
+
constructor({ status, headers, data }: ClientResponseErrorOptions);
|
|
165
|
+
}
|
|
166
|
+
export {};
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { buildFetchHandler } from './fetch-handler.js';
|
|
2
|
+
const JSON_CONTENT_TYPE_RE = /\bapplication\/json\b/;
|
|
3
|
+
/** XRPC API client */
|
|
4
|
+
export class Client {
|
|
5
|
+
constructor({ handler, proxy = null }) {
|
|
6
|
+
this.handler = buildFetchHandler(handler);
|
|
7
|
+
this.proxy = proxy;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* clones this XRPC client
|
|
11
|
+
* @param opts options to merge with
|
|
12
|
+
* @returns the cloned XRPC client
|
|
13
|
+
*/
|
|
14
|
+
clone({ handler = this.handler, proxy = this.proxy } = {}) {
|
|
15
|
+
return new Client({ handler, proxy });
|
|
16
|
+
}
|
|
17
|
+
get(name, options = {}) {
|
|
18
|
+
return this.#perform('get', name, options);
|
|
19
|
+
}
|
|
20
|
+
post(name, options = {}) {
|
|
21
|
+
return this.#perform('post', name, options);
|
|
22
|
+
}
|
|
23
|
+
async #perform(method, name, { signal, as: format = 'json', headers, input, params }) {
|
|
24
|
+
const isWebInput = input &&
|
|
25
|
+
(input instanceof Blob ||
|
|
26
|
+
ArrayBuffer.isView(input) ||
|
|
27
|
+
input instanceof ArrayBuffer ||
|
|
28
|
+
input instanceof ReadableStream);
|
|
29
|
+
const url = `/xrpc/${name}` + _constructSearchParams(params);
|
|
30
|
+
const response = await this.handler(url, {
|
|
31
|
+
method,
|
|
32
|
+
signal,
|
|
33
|
+
body: input && !isWebInput ? JSON.stringify(input) : input,
|
|
34
|
+
headers: _mergeHeaders(headers, {
|
|
35
|
+
'content-type': input && !isWebInput ? 'application/json' : null,
|
|
36
|
+
'atproto-proxy': _constructProxyHeader(this.proxy),
|
|
37
|
+
}),
|
|
38
|
+
});
|
|
39
|
+
{
|
|
40
|
+
const status = response.status;
|
|
41
|
+
const headers = response.headers;
|
|
42
|
+
const type = headers.get('content-type');
|
|
43
|
+
if (status !== 200) {
|
|
44
|
+
let json;
|
|
45
|
+
if (type != null && JSON_CONTENT_TYPE_RE.test(type)) {
|
|
46
|
+
// it should be okay to swallow the parsing error here
|
|
47
|
+
try {
|
|
48
|
+
const parsed = await response.json();
|
|
49
|
+
if (isXRPCErrorPayload(parsed)) {
|
|
50
|
+
json = parsed;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch { }
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
await response.body?.cancel();
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
ok: false,
|
|
60
|
+
status: status,
|
|
61
|
+
headers: headers,
|
|
62
|
+
data: json ?? {
|
|
63
|
+
error: `UnknownXRPCError`,
|
|
64
|
+
message: `Request failed with status code ${status}`,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
{
|
|
69
|
+
let data;
|
|
70
|
+
switch (format) {
|
|
71
|
+
case 'json': {
|
|
72
|
+
if (type != null && JSON_CONTENT_TYPE_RE.test(type)) {
|
|
73
|
+
// we shouldn't be handling parsing errors
|
|
74
|
+
data = await response.json();
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
await response.body?.cancel();
|
|
78
|
+
throw new TypeError(`Invalid response content-type (got ${type})`);
|
|
79
|
+
}
|
|
80
|
+
break;
|
|
81
|
+
}
|
|
82
|
+
case null: {
|
|
83
|
+
data = null;
|
|
84
|
+
await response.body?.cancel();
|
|
85
|
+
if (type != null) {
|
|
86
|
+
throw new TypeError(`Invalid response content-type (got ${type})`);
|
|
87
|
+
}
|
|
88
|
+
break;
|
|
89
|
+
}
|
|
90
|
+
case 'blob': {
|
|
91
|
+
data = await response.blob();
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
case 'bytes': {
|
|
95
|
+
data = new Uint8Array(await response.arrayBuffer());
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
case 'stream': {
|
|
99
|
+
data = response.body;
|
|
100
|
+
break;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return {
|
|
104
|
+
ok: true,
|
|
105
|
+
status: status,
|
|
106
|
+
headers: headers,
|
|
107
|
+
data: data,
|
|
108
|
+
};
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
// #endregion
|
|
114
|
+
// #region Utility functions
|
|
115
|
+
const _constructSearchParams = (params) => {
|
|
116
|
+
let searchParams;
|
|
117
|
+
for (const key in params) {
|
|
118
|
+
const value = params[key];
|
|
119
|
+
if (value !== undefined) {
|
|
120
|
+
searchParams ??= new URLSearchParams();
|
|
121
|
+
if (Array.isArray(value)) {
|
|
122
|
+
for (let idx = 0, len = value.length; idx < len; idx++) {
|
|
123
|
+
const val = value[idx];
|
|
124
|
+
searchParams.append(key, '' + val);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
searchParams.set(key, '' + value);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return searchParams ? `?` + searchParams.toString() : '';
|
|
133
|
+
};
|
|
134
|
+
const _constructProxyHeader = (proxy) => {
|
|
135
|
+
if (proxy != null) {
|
|
136
|
+
return `${proxy.did}${proxy.serviceId}`;
|
|
137
|
+
}
|
|
138
|
+
return null;
|
|
139
|
+
};
|
|
140
|
+
const _mergeHeaders = (init, defaults) => {
|
|
141
|
+
let headers;
|
|
142
|
+
for (const name in defaults) {
|
|
143
|
+
const value = defaults[name];
|
|
144
|
+
if (value !== null) {
|
|
145
|
+
headers ??= new Headers(init);
|
|
146
|
+
if (!headers.has(name)) {
|
|
147
|
+
headers.set(name, value);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return headers ?? init;
|
|
152
|
+
};
|
|
153
|
+
export const isXRPCErrorPayload = (input) => {
|
|
154
|
+
if (typeof input !== 'object' || input == null) {
|
|
155
|
+
return false;
|
|
156
|
+
}
|
|
157
|
+
const kindType = typeof input.error;
|
|
158
|
+
const messageType = typeof input.message;
|
|
159
|
+
return kindType === 'string' && (messageType === 'undefined' || messageType === 'string');
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* takes in the response returned by the client, and either returns the data if
|
|
163
|
+
* it is a successful response, or throws if it's a failed response.
|
|
164
|
+
* @param input either a ClientResponse, or a promise that resolves to a ClientResponse
|
|
165
|
+
* @returns the data from a successful response
|
|
166
|
+
*
|
|
167
|
+
* @example
|
|
168
|
+
* const data = await ok(client.get('com.atproto.server.describeServer'));
|
|
169
|
+
* // ^? ComAtprotoServerDescribeServer.Output
|
|
170
|
+
*/
|
|
171
|
+
export const ok = (input) => {
|
|
172
|
+
if (input instanceof Promise) {
|
|
173
|
+
return input.then(ok);
|
|
174
|
+
}
|
|
175
|
+
if (input.ok) {
|
|
176
|
+
return input.data;
|
|
177
|
+
}
|
|
178
|
+
throw new ClientResponseError(input);
|
|
179
|
+
};
|
|
180
|
+
/** represents an error response returned by the client */
|
|
181
|
+
export class ClientResponseError extends Error {
|
|
182
|
+
constructor({ status, headers = new Headers(), data }) {
|
|
183
|
+
super(`${data.error} > ${data.message ?? '(unspecified description)'}`);
|
|
184
|
+
this.name = 'ClientResponseError';
|
|
185
|
+
this.error = data.error;
|
|
186
|
+
this.description = data.message;
|
|
187
|
+
this.status = status;
|
|
188
|
+
this.headers = headers;
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
// #endregion
|
|
192
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../lib/client.ts"],"names":[],"mappings":"AAYA,OAAO,EAAE,iBAAiB,EAA8C,MAAM,oBAAoB,CAAC;AAgKnG,MAAM,oBAAoB,GAAG,uBAAuB,CAAC;AAErD,sBAAsB;AACtB,MAAM,OAAO,MAAM;IAIlB,YAAY,EAAE,OAAO,EAAE,KAAK,GAAG,IAAI,EAAiB;QACnD,IAAI,CAAC,OAAO,GAAG,iBAAiB,CAAC,OAAO,CAAC,CAAC;QAC1C,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACpB,CAAC;IAED;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,GAAG,IAAI,CAAC,KAAK,KAA6B,EAAE;QAIhF,OAAO,IAAI,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;IACvC,CAAC;IAYD,GAAG,CAAC,IAAY,EAAE,UAAkC,EAAE;QACrD,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC5C,CAAC;IAYD,IAAI,CAAC,IAAY,EAAE,UAAkC,EAAE;QACtD,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;IAC7C,CAAC;IAED,KAAK,CAAC,QAAQ,CACb,MAAsB,EACtB,IAAY,EACZ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,EAA0B;QAE/E,MAAM,UAAU,GACf,KAAK;YACL,CAAC,KAAK,YAAY,IAAI;gBACrB,WAAW,CAAC,MAAM,CAAC,KAAK,CAAC;gBACzB,KAAK,YAAY,WAAW;gBAC5B,KAAK,YAAY,cAAc,CAAC,CAAC;QAEnC,MAAM,GAAG,GAAG,SAAS,IAAI,EAAE,GAAG,sBAAsB,CAAC,MAAM,CAAC,CAAC;QAE7D,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;YACxC,MAAM;YACN,MAAM;YACN,IAAI,EAAE,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK;YAC1D,OAAO,EAAE,aAAa,CAAC,OAAO,EAAE;gBAC/B,cAAc,EAAE,KAAK,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,kBAAkB,CAAC,CAAC,CAAC,IAAI;gBAChE,eAAe,EAAE,qBAAqB,CAAC,IAAI,CAAC,KAAK,CAAC;aAClD,CAAC;SACF,CAAC,CAAC;QAEH,CAAC;YACA,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC;YAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC;YAEjC,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;YAEzC,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;gBACpB,IAAI,IAAS,CAAC;gBAEd,IAAI,IAAI,IAAI,IAAI,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;oBACrD,sDAAsD;oBACtD,IAAI,CAAC;wBACJ,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;wBACrC,IAAI,kBAAkB,CAAC,MAAM,CAAC,EAAE,CAAC;4BAChC,IAAI,GAAG,MAAM,CAAC;wBACf,CAAC;oBACF,CAAC;oBAAC,MAAM,CAAC,CAAA,CAAC;gBACX,CAAC;qBAAM,CAAC;oBACP,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;gBAC/B,CAAC;gBAED,OAAO;oBACN,EAAE,EAAE,KAAK;oBACT,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,OAAO;oBAChB,IAAI,EAAE,IAAI,IAAI;wBACb,KAAK,EAAE,kBAAkB;wBACzB,OAAO,EAAE,mCAAmC,MAAM,EAAE;qBACpD;iBACD,CAAC;YACH,CAAC;YAED,CAAC;gBACA,IAAI,IAAS,CAAC;gBACd,QAAQ,MAAM,EAAE,CAAC;oBAChB,KAAK,MAAM,CAAC,CAAC,CAAC;wBACb,IAAI,IAAI,IAAI,IAAI,IAAI,oBAAoB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;4BACrD,0CAA0C;4BAC1C,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAC9B,CAAC;6BAAM,CAAC;4BACP,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;4BAE9B,MAAM,IAAI,SAAS,CAAC,sCAAsC,IAAI,GAAG,CAAC,CAAC;wBACpE,CAAC;wBAED,MAAM;oBACP,CAAC;oBAED,KAAK,IAAI,CAAC,CAAC,CAAC;wBACX,IAAI,GAAG,IAAI,CAAC;wBAEZ,MAAM,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC;wBAE9B,IAAI,IAAI,IAAI,IAAI,EAAE,CAAC;4BAClB,MAAM,IAAI,SAAS,CAAC,sCAAsC,IAAI,GAAG,CAAC,CAAC;wBACpE,CAAC;wBAED,MAAM;oBACP,CAAC;oBAED,KAAK,MAAM,CAAC,CAAC,CAAC;wBACb,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAC7B,MAAM;oBACP,CAAC;oBACD,KAAK,OAAO,CAAC,CAAC,CAAC;wBACd,IAAI,GAAG,IAAI,UAAU,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;wBACpD,MAAM;oBACP,CAAC;oBACD,KAAK,QAAQ,CAAC,CAAC,CAAC;wBACf,IAAI,GAAG,QAAQ,CAAC,IAAK,CAAC;wBACtB,MAAM;oBACP,CAAC;gBACF,CAAC;gBAED,OAAO;oBACN,EAAE,EAAE,IAAI;oBACR,MAAM,EAAE,MAAM;oBACd,OAAO,EAAE,OAAO;oBAChB,IAAI,EAAE,IAAI;iBACV,CAAC;YACH,CAAC;QACF,CAAC;IACF,CAAC;CACD;AAED,aAAa;AAEb,4BAA4B;AAC5B,MAAM,sBAAsB,GAAG,CAAC,MAA2C,EAAU,EAAE;IACtF,IAAI,YAAyC,CAAC;IAE9C,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAE1B,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACzB,YAAY,KAAK,IAAI,eAAe,EAAE,CAAC;YAEvC,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC1B,KAAK,IAAI,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,KAAK,CAAC,MAAM,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;oBACxD,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;oBACvB,YAAY,CAAC,MAAM,CAAC,GAAG,EAAE,EAAE,GAAG,GAAG,CAAC,CAAC;gBACpC,CAAC;YACF,CAAC;iBAAM,CAAC;gBACP,YAAY,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC;YACnC,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,YAAY,CAAC,CAAC,CAAC,GAAG,GAAG,YAAY,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;AAC1D,CAAC,CAAC;AAEF,MAAM,qBAAqB,GAAG,CAAC,KAA6C,EAAiB,EAAE;IAC9F,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QACnB,OAAO,GAAG,KAAK,CAAC,GAAG,GAAG,KAAK,CAAC,SAAS,EAAE,CAAC;IACzC,CAAC;IAED,OAAO,IAAI,CAAC;AACb,CAAC,CAAC;AAEF,MAAM,aAAa,GAAG,CACrB,IAA6B,EAC7B,QAAuC,EACb,EAAE;IAC5B,IAAI,OAA4B,CAAC;IAEjC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;QAC7B,MAAM,KAAK,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAE7B,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YACpB,OAAO,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;YAE9B,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBACxB,OAAO,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;YAC1B,CAAC;QACF,CAAC;IACF,CAAC;IAED,OAAO,OAAO,IAAI,IAAI,CAAC;AACxB,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,KAAU,EAA6B,EAAE;IAC3E,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,IAAI,IAAI,EAAE,CAAC;QAChD,OAAO,KAAK,CAAC;IACd,CAAC;IAED,MAAM,QAAQ,GAAG,OAAO,KAAK,CAAC,KAAK,CAAC;IACpC,MAAM,WAAW,GAAG,OAAO,KAAK,CAAC,OAAO,CAAC;IAEzC,OAAO,QAAQ,KAAK,QAAQ,IAAI,CAAC,WAAW,KAAK,WAAW,IAAI,WAAW,KAAK,QAAQ,CAAC,CAAC;AAC3F,CAAC,CAAC;AAMF;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,EAAE,GAGX,CAAC,KAAmE,EAAO,EAAE;IAChF,IAAI,KAAK,YAAY,OAAO,EAAE,CAAC;QAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACvB,CAAC;IAED,IAAI,KAAK,CAAC,EAAE,EAAE,CAAC;QACd,OAAO,KAAK,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,MAAM,IAAI,mBAAmB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC,CAAC;AASF,0DAA0D;AAC1D,MAAM,OAAO,mBAAoB,SAAQ,KAAK;IAW7C,YAAY,EAAE,MAAM,EAAE,OAAO,GAAG,IAAI,OAAO,EAAE,EAAE,IAAI,EAA8B;QAChF,KAAK,CAAC,GAAG,IAAI,CAAC,KAAK,MAAM,IAAI,CAAC,OAAO,IAAI,2BAA2B,EAAE,CAAC,CAAC;QAExE,IAAI,CAAC,IAAI,GAAG,qBAAqB,CAAC;QAElC,IAAI,CAAC,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC;QACxB,IAAI,CAAC,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC;QAEhC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACxB,CAAC;CACD;AAED,aAAa"}
|
|
@@ -1,95 +1,104 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Did } from '@atcute/lexicons';
|
|
2
2
|
import { type FetchHandlerObject } from './fetch-handler.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* represents the decoded access token, for convenience
|
|
5
|
+
* @deprecated
|
|
6
|
+
*/
|
|
4
7
|
export interface AtpAccessJwt {
|
|
5
|
-
/**
|
|
8
|
+
/** access token scope */
|
|
6
9
|
scope: 'com.atproto.access' | 'com.atproto.appPass' | 'com.atproto.appPassPrivileged' | 'com.atproto.signupQueued' | 'com.atproto.takendown';
|
|
7
|
-
/**
|
|
8
|
-
sub:
|
|
9
|
-
/**
|
|
10
|
+
/** account DID */
|
|
11
|
+
sub: Did;
|
|
12
|
+
/** expiration time in Unix seconds */
|
|
10
13
|
exp: number;
|
|
11
|
-
/**
|
|
14
|
+
/** token issued time in Unix seconds */
|
|
12
15
|
iat: number;
|
|
13
16
|
}
|
|
14
|
-
/**
|
|
17
|
+
/**
|
|
18
|
+
* represents the the decoded refresh token, for convenience
|
|
19
|
+
* @deprecated
|
|
20
|
+
*/
|
|
15
21
|
export interface AtpRefreshJwt {
|
|
16
|
-
/**
|
|
22
|
+
/** refresh token scope */
|
|
17
23
|
scope: 'com.atproto.refresh';
|
|
18
|
-
/**
|
|
24
|
+
/** unique identifier for this session */
|
|
19
25
|
jti: string;
|
|
20
|
-
/**
|
|
21
|
-
sub:
|
|
22
|
-
/**
|
|
23
|
-
aud:
|
|
24
|
-
/**
|
|
26
|
+
/** account DID */
|
|
27
|
+
sub: Did;
|
|
28
|
+
/** intended audience of this refresh token, in DID */
|
|
29
|
+
aud: Did;
|
|
30
|
+
/** token expiration time in seconds */
|
|
25
31
|
exp: number;
|
|
26
|
-
/**
|
|
32
|
+
/** token issued time in seconds */
|
|
27
33
|
iat: number;
|
|
28
34
|
}
|
|
29
|
-
/**
|
|
35
|
+
/** session data, can be persisted and reused */
|
|
30
36
|
export interface AtpSessionData {
|
|
31
|
-
/**
|
|
37
|
+
/** refresh token */
|
|
32
38
|
refreshJwt: string;
|
|
33
|
-
/**
|
|
39
|
+
/** access token */
|
|
34
40
|
accessJwt: string;
|
|
35
|
-
/**
|
|
41
|
+
/** account handle */
|
|
36
42
|
handle: string;
|
|
37
|
-
/**
|
|
38
|
-
did:
|
|
43
|
+
/** account DID */
|
|
44
|
+
did: Did;
|
|
39
45
|
/** PDS endpoint found in the DID document, this will be used as the service URI if provided */
|
|
40
46
|
pdsUri?: string;
|
|
41
|
-
/**
|
|
47
|
+
/** email address of the account, might not be available if on app password */
|
|
42
48
|
email?: string;
|
|
43
|
-
/**
|
|
49
|
+
/** whether the email address has been confirmed or not */
|
|
44
50
|
emailConfirmed?: boolean;
|
|
45
|
-
/**
|
|
51
|
+
/** whether the account has email-based two-factor authentication enabled */
|
|
46
52
|
emailAuthFactor?: boolean;
|
|
47
|
-
/**
|
|
53
|
+
/** whether the account is active (not deactivated, taken down, or suspended) */
|
|
48
54
|
active: boolean;
|
|
49
|
-
/**
|
|
55
|
+
/** possible reason for why the account is inactive */
|
|
50
56
|
inactiveStatus?: string;
|
|
51
57
|
}
|
|
52
58
|
export interface CredentialManagerOptions {
|
|
53
59
|
/** PDS server URL */
|
|
54
60
|
service: string;
|
|
55
|
-
/**
|
|
56
|
-
fetch?: typeof
|
|
57
|
-
/**
|
|
61
|
+
/** custom fetch function */
|
|
62
|
+
fetch?: typeof fetch;
|
|
63
|
+
/** function called when the session expires and can't be refreshed */
|
|
58
64
|
onExpired?: (session: AtpSessionData) => void;
|
|
59
|
-
/**
|
|
65
|
+
/** function called after a successful session refresh */
|
|
60
66
|
onRefresh?: (session: AtpSessionData) => void;
|
|
61
|
-
/**
|
|
67
|
+
/** function called whenever the session object is updated (login, resume, refresh) */
|
|
62
68
|
onSessionUpdate?: (session: AtpSessionData) => void;
|
|
63
69
|
}
|
|
64
70
|
export declare class CredentialManager implements FetchHandlerObject {
|
|
65
71
|
#private;
|
|
72
|
+
/** service URL to make authentication requests with */
|
|
66
73
|
readonly serviceUrl: string;
|
|
74
|
+
/** fetch implementation */
|
|
67
75
|
fetch: typeof fetch;
|
|
68
|
-
/**
|
|
76
|
+
/** current active session, undefined if not authenticated */
|
|
69
77
|
session?: AtpSessionData;
|
|
70
78
|
constructor({ service, onExpired, onRefresh, onSessionUpdate, fetch: _fetch, }: CredentialManagerOptions);
|
|
79
|
+
/** service URL to make actual API requests with */
|
|
71
80
|
get dispatchUrl(): string;
|
|
72
81
|
handle(pathname: string, init: RequestInit): Promise<Response>;
|
|
73
82
|
/**
|
|
74
|
-
*
|
|
75
|
-
* @param session
|
|
83
|
+
* resume from a persisted session
|
|
84
|
+
* @param session session data, taken from `AtpAuth#session` after login
|
|
76
85
|
*/
|
|
77
86
|
resume(session: AtpSessionData): Promise<AtpSessionData>;
|
|
78
87
|
/**
|
|
79
|
-
*
|
|
80
|
-
* @param options
|
|
81
|
-
* @returns
|
|
88
|
+
* sign in to an account
|
|
89
|
+
* @param options credential options
|
|
90
|
+
* @returns session data
|
|
82
91
|
*/
|
|
83
92
|
login(options: AuthLoginOptions): Promise<AtpSessionData>;
|
|
84
93
|
}
|
|
85
|
-
/**
|
|
94
|
+
/** credentials */
|
|
86
95
|
export interface AuthLoginOptions {
|
|
87
|
-
/**
|
|
96
|
+
/** what account to login as, this could be domain handle, DID, or email address */
|
|
88
97
|
identifier: string;
|
|
89
|
-
/**
|
|
98
|
+
/** account password */
|
|
90
99
|
password: string;
|
|
91
|
-
/**
|
|
100
|
+
/** two-factor authentication code, if email TOTP is enabled */
|
|
92
101
|
code?: string;
|
|
93
|
-
/**
|
|
102
|
+
/** allow signing in even if the account has been taken down */
|
|
94
103
|
allowTakendown?: boolean;
|
|
95
104
|
}
|