@atcute/client 1.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.
@@ -0,0 +1,4 @@
1
+ /* eslint-disable */
2
+ // This file is automatically generated, do not edit!
3
+ export {};
4
+ //# sourceMappingURL=lexicons.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"lexicons.js","sourceRoot":"","sources":["../lib/lexicons.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,qDAAqD"}
@@ -0,0 +1,91 @@
1
+ /**
2
+ * @module
3
+ * Contains a middleware that handles authentication to a personal data server.
4
+ */
5
+ import { type XRPC } from '../index.js';
6
+ import type { At } from '../lexicons.js';
7
+ /** Interface for the decoded access token, for convenience */
8
+ export interface AtpAccessJwt {
9
+ /** Access token scope, app password returns a different scope. */
10
+ scope: 'com.atproto.access' | 'com.atproto.appPass' | 'com.atproto.appPassPrivileged';
11
+ /** Account DID */
12
+ sub: At.DID;
13
+ /** Expiration time */
14
+ exp: number;
15
+ /** Creation/issued time */
16
+ iat: number;
17
+ }
18
+ /** Interface for the decoded refresh token, for convenience */
19
+ export interface AtpRefreshJwt {
20
+ /** Refresh token scope */
21
+ scope: 'com.atproto.refresh';
22
+ /** ID of this refresh token */
23
+ jti: string;
24
+ /** Account DID */
25
+ sub: At.DID;
26
+ /** Intended audience of this refresh token, in DID */
27
+ aud: At.DID;
28
+ /** Expiration time */
29
+ exp: number;
30
+ /** Creation/issued time */
31
+ iat: number;
32
+ }
33
+ /** Saved session data, this can be reused again for next time. */
34
+ export interface AtpSessionData {
35
+ /** Refresh token */
36
+ refreshJwt: string;
37
+ /** Access token */
38
+ accessJwt: string;
39
+ /** Account handle */
40
+ handle: string;
41
+ /** Account DID */
42
+ did: At.DID;
43
+ /** PDS endpoint found in the DID document, this will be used as the service URI if provided */
44
+ pdsUri?: string;
45
+ /** Email address of the account, might not be available if on app password */
46
+ email?: string;
47
+ /** If the email address has been confirmed or not */
48
+ emailConfirmed?: boolean;
49
+ /** If the account has email-based two-factor authentication enabled */
50
+ emailAuthFactor?: boolean;
51
+ /** Whether the account is active (not deactivated, taken down, or suspended) */
52
+ active: boolean;
53
+ /** Possible reason for why the account is inactive */
54
+ inactiveStatus?: string;
55
+ }
56
+ /** Additional options for constructing an authentication middleware */
57
+ export interface AtpAuthOptions {
58
+ /** This function gets called if the session turned out to have expired during an XRPC request */
59
+ onExpired?: (session: AtpSessionData) => void;
60
+ /** This function gets called if the session has been refreshed during an XRPC request */
61
+ onRefresh?: (session: AtpSessionData) => void;
62
+ /** This function gets called if the session object has been refreshed */
63
+ onSessionUpdate?: (session: AtpSessionData) => void;
64
+ }
65
+ /** Authentication/session management middleware */
66
+ export declare class AtpAuth {
67
+ #private;
68
+ /** Current session state */
69
+ session?: AtpSessionData;
70
+ constructor(rpc: XRPC, { onExpired, onRefresh, onSessionUpdate }?: AtpAuthOptions);
71
+ /**
72
+ * Resume a saved session
73
+ * @param session Session information, taken from `AtpAuth#session` after login
74
+ */
75
+ resume(session: AtpSessionData): Promise<AtpSessionData>;
76
+ /**
77
+ * Perform a login operation
78
+ * @param options Login options
79
+ * @returns Session data that can be saved for later
80
+ */
81
+ login(options: AuthLoginOptions): Promise<AtpSessionData>;
82
+ }
83
+ /** Login options */
84
+ export interface AuthLoginOptions {
85
+ /** What account to login as, this could be domain handle, DID, or email address */
86
+ identifier: string;
87
+ /** Account password */
88
+ password: string;
89
+ /** Two-factor authentication code */
90
+ code?: string;
91
+ }
@@ -0,0 +1,150 @@
1
+ /**
2
+ * @module
3
+ * Contains a middleware that handles authentication to a personal data server.
4
+ */
5
+ import { fetchHandler, isErrorResponse, XRPCError } from '../index.js';
6
+ import { getPdsEndpoint } from '../utils/did.js';
7
+ import { decodeJwt } from '../utils/jwt.js';
8
+ /** Authentication/session management middleware */
9
+ export class AtpAuth {
10
+ #rpc;
11
+ #refreshSessionPromise;
12
+ #onExpired;
13
+ #onRefresh;
14
+ #onSessionUpdate;
15
+ /** Current session state */
16
+ session;
17
+ constructor(rpc, { onExpired, onRefresh, onSessionUpdate } = {}) {
18
+ this.#rpc = rpc;
19
+ this.#onRefresh = onRefresh;
20
+ this.#onExpired = onExpired;
21
+ this.#onSessionUpdate = onSessionUpdate;
22
+ rpc.hook((next) => async (request) => {
23
+ await this.#refreshSessionPromise;
24
+ let res = await next(this.#decorateRequest(request));
25
+ if (isErrorResponse(res.body, ['ExpiredToken']) && this.session?.refreshJwt) {
26
+ await this.#refreshSession();
27
+ if (this.session) {
28
+ // retry fetch
29
+ res = await next(this.#decorateRequest(request));
30
+ }
31
+ }
32
+ return res;
33
+ });
34
+ }
35
+ #decorateRequest(req) {
36
+ const session = this.session;
37
+ if (session && !req.headers['Authorization']) {
38
+ return {
39
+ ...req,
40
+ service: session.pdsUri || req.service,
41
+ headers: {
42
+ ...req.headers,
43
+ Authorization: `Bearer ${session.accessJwt}`,
44
+ },
45
+ };
46
+ }
47
+ return req;
48
+ }
49
+ #refreshSession() {
50
+ return (this.#refreshSessionPromise ||= this.#refreshSessionInner().finally(() => {
51
+ this.#refreshSessionPromise = undefined;
52
+ }));
53
+ }
54
+ async #refreshSessionInner() {
55
+ const session = this.session;
56
+ if (!session || !session.refreshJwt) {
57
+ return;
58
+ }
59
+ const res = await fetchHandler({
60
+ service: session.pdsUri || this.#rpc.service,
61
+ type: 'post',
62
+ nsid: 'com.atproto.server.refreshSession',
63
+ headers: {
64
+ Authorization: `Bearer ${session.refreshJwt}`,
65
+ },
66
+ params: {},
67
+ });
68
+ if (isErrorResponse(res.body, ['ExpiredToken', 'InvalidToken'])) {
69
+ // failed due to a bad refresh token
70
+ this.session = undefined;
71
+ this.#onExpired?.(session);
72
+ }
73
+ else if (res.status === 200) {
74
+ // succeeded, update the session
75
+ this.#updateSession({ ...session, ...res.body });
76
+ this.#onRefresh?.(this.session);
77
+ }
78
+ }
79
+ #updateSession(raw) {
80
+ const didDoc = raw.didDoc;
81
+ let pdsUri;
82
+ if (didDoc) {
83
+ pdsUri = getPdsEndpoint(didDoc);
84
+ }
85
+ const newSession = {
86
+ accessJwt: raw.accessJwt,
87
+ refreshJwt: raw.refreshJwt,
88
+ handle: raw.handle,
89
+ did: raw.did,
90
+ pdsUri: pdsUri,
91
+ email: raw.email,
92
+ emailConfirmed: raw.emailConfirmed,
93
+ emailAuthFactor: raw.emailConfirmed,
94
+ active: raw.active ?? true,
95
+ inactiveStatus: raw.status,
96
+ };
97
+ this.session = newSession;
98
+ this.#onSessionUpdate?.(newSession);
99
+ return newSession;
100
+ }
101
+ /**
102
+ * Resume a saved session
103
+ * @param session Session information, taken from `AtpAuth#session` after login
104
+ */
105
+ async resume(session) {
106
+ const now = Date.now() / 1000 + 60 * 5;
107
+ const refreshToken = decodeJwt(session.refreshJwt);
108
+ if (now >= refreshToken.exp) {
109
+ throw new XRPCError(401, { kind: 'InvalidToken' });
110
+ }
111
+ const accessToken = decodeJwt(session.accessJwt);
112
+ this.session = session;
113
+ if (now >= accessToken.exp) {
114
+ await this.#refreshSession();
115
+ }
116
+ else {
117
+ const promise = this.#rpc.get('com.atproto.server.getSession', {});
118
+ promise.then((response) => {
119
+ const existing = this.session;
120
+ const next = response.data;
121
+ if (!existing) {
122
+ return;
123
+ }
124
+ this.#updateSession({ ...existing, ...next });
125
+ });
126
+ }
127
+ if (!this.session) {
128
+ throw new XRPCError(401, { kind: 'InvalidToken' });
129
+ }
130
+ return this.session;
131
+ }
132
+ /**
133
+ * Perform a login operation
134
+ * @param options Login options
135
+ * @returns Session data that can be saved for later
136
+ */
137
+ async login(options) {
138
+ // Reset the session
139
+ this.session = undefined;
140
+ const res = await this.#rpc.call('com.atproto.server.createSession', {
141
+ data: {
142
+ identifier: options.identifier,
143
+ password: options.password,
144
+ authFactorToken: options.code,
145
+ },
146
+ });
147
+ return this.#updateSession(res.data);
148
+ }
149
+ }
150
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../lib/middlewares/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @module
3
+ * Contains a middleware that adds `atproto-accept-labelers` header to requests.
4
+ */
5
+ import type { XRPC } from '../index.js';
6
+ import type { At } from '../lexicons.js';
7
+ /** Options for constructing a moderation middleware */
8
+ export interface AtpModOptions {
9
+ /** Array of moderation services to use */
10
+ labelers?: ModerationService[];
11
+ }
12
+ /** Moderation middleware, unstable. */
13
+ export declare class AtpMod {
14
+ /** Array of moderation services that gets forwarded as a header */
15
+ labelers: ModerationService[];
16
+ constructor(rpc: XRPC, { labelers }?: AtpModOptions);
17
+ }
18
+ /** Interface detailing what moderator service to use and how it should be used. */
19
+ export interface ModerationService {
20
+ /** Moderator service to use */
21
+ did: At.DID;
22
+ /** Whether it should apply takedowns made by this service. */
23
+ redact?: boolean;
24
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @module
3
+ * Contains a middleware that adds `atproto-accept-labelers` header to requests.
4
+ */
5
+ /** Moderation middleware, unstable. */
6
+ export class AtpMod {
7
+ /** Array of moderation services that gets forwarded as a header */
8
+ labelers;
9
+ constructor(rpc, { labelers = [] } = {}) {
10
+ this.labelers = labelers;
11
+ rpc.hook((next) => (request) => {
12
+ return next({
13
+ ...request,
14
+ headers: {
15
+ ...request.headers,
16
+ 'atproto-accept-labelers': this.labelers
17
+ .map((labeler) => labeler.did + (labeler.redact ? `;redact` : ``))
18
+ .join(', '),
19
+ },
20
+ });
21
+ });
22
+ }
23
+ }
24
+ //# sourceMappingURL=mod.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mod.js","sourceRoot":"","sources":["../../lib/middlewares/mod.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAWH,uCAAuC;AACvC,MAAM,OAAO,MAAM;IAClB,mEAAmE;IACnE,QAAQ,CAAsB;IAE9B,YAAY,GAAS,EAAE,EAAE,QAAQ,GAAG,EAAE,KAAoB,EAAE;QAC3D,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QAEzB,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,OAAO,EAAE,EAAE;YAC9B,OAAO,IAAI,CAAC;gBACX,GAAG,OAAO;gBACV,OAAO,EAAE;oBACR,GAAG,OAAO,CAAC,OAAO;oBAClB,yBAAyB,EAAE,IAAI,CAAC,QAAQ;yBACtC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;yBACjE,IAAI,CAAC,IAAI,CAAC;iBACZ;aACD,CAAC,CAAC;QACJ,CAAC,CAAC,CAAC;IACJ,CAAC;CACD"}
@@ -0,0 +1,36 @@
1
+ /**
2
+ * @module
3
+ * DID document-related functionalities
4
+ */
5
+ /**
6
+ * Retrieves AT Protocol PDS endpoint from the DID document, if available
7
+ * @param doc DID document
8
+ * @returns The PDS endpoint, if available
9
+ */
10
+ export declare const getPdsEndpoint: (doc: DidDocument) => string | undefined;
11
+ /**
12
+ * Retrieve a service endpoint from the DID document, if available
13
+ * @param doc DID document
14
+ * @param serviceId Service ID
15
+ * @param serviceType Service type
16
+ * @returns The requested service endpoint, if available
17
+ */
18
+ export declare const getServiceEndpoint: (doc: DidDocument, serviceId: string, serviceType: string) => string | undefined;
19
+ /**
20
+ * DID document
21
+ */
22
+ export interface DidDocument {
23
+ id: string;
24
+ alsoKnownAs?: string[];
25
+ verificationMethod?: Array<{
26
+ id: string;
27
+ type: string;
28
+ controller: string;
29
+ publicKeyMultibase?: string;
30
+ }>;
31
+ service?: Array<{
32
+ id: string;
33
+ type: string;
34
+ serviceEndpoint: string | Record<string, unknown>;
35
+ }>;
36
+ }
@@ -0,0 +1,42 @@
1
+ /**
2
+ * @module
3
+ * DID document-related functionalities
4
+ */
5
+ /**
6
+ * Retrieves AT Protocol PDS endpoint from the DID document, if available
7
+ * @param doc DID document
8
+ * @returns The PDS endpoint, if available
9
+ */
10
+ export const getPdsEndpoint = (doc) => {
11
+ return getServiceEndpoint(doc, '#atproto_pds', 'AtprotoPersonalDataServer');
12
+ };
13
+ /**
14
+ * Retrieve a service endpoint from the DID document, if available
15
+ * @param doc DID document
16
+ * @param serviceId Service ID
17
+ * @param serviceType Service type
18
+ * @returns The requested service endpoint, if available
19
+ */
20
+ export const getServiceEndpoint = (doc, serviceId, serviceType) => {
21
+ const did = doc.id;
22
+ const didServiceId = did + serviceId;
23
+ const found = doc.service?.find((service) => service.id === serviceId || service.id === didServiceId);
24
+ if (!found || found.type !== serviceType || typeof found.serviceEndpoint !== 'string') {
25
+ return undefined;
26
+ }
27
+ return validateUrl(found.serviceEndpoint);
28
+ };
29
+ const validateUrl = (urlStr) => {
30
+ let url;
31
+ try {
32
+ url = new URL(urlStr);
33
+ }
34
+ catch {
35
+ return undefined;
36
+ }
37
+ const proto = url.protocol;
38
+ if (url.hostname && (proto === 'http:' || proto === 'https:')) {
39
+ return urlStr;
40
+ }
41
+ };
42
+ //# sourceMappingURL=did.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"did.js","sourceRoot":"","sources":["../../lib/utils/did.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAgB,EAAsB,EAAE;IACtE,OAAO,kBAAkB,CAAC,GAAG,EAAE,cAAc,EAAE,2BAA2B,CAAC,CAAC;AAC7E,CAAC,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,kBAAkB,GAAG,CACjC,GAAgB,EAChB,SAAiB,EACjB,WAAmB,EACE,EAAE;IACvB,MAAM,GAAG,GAAG,GAAG,CAAC,EAAE,CAAC;IAEnB,MAAM,YAAY,GAAG,GAAG,GAAG,SAAS,CAAC;IACrC,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,KAAK,YAAY,CAAC,CAAC;IAEtG,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,WAAW,IAAI,OAAO,KAAK,CAAC,eAAe,KAAK,QAAQ,EAAE,CAAC;QACvF,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,OAAO,WAAW,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;AAC3C,CAAC,CAAC;AAEF,MAAM,WAAW,GAAG,CAAC,MAAc,EAAsB,EAAE;IAC1D,IAAI,GAAG,CAAC;IACR,IAAI,CAAC;QACJ,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,CAAC;IACvB,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,SAAS,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,CAAC;IAE3B,IAAI,GAAG,CAAC,QAAQ,IAAI,CAAC,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,QAAQ,CAAC,EAAE,CAAC;QAC/D,OAAO,MAAM,CAAC;IACf,CAAC;AACF,CAAC,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * @module
3
+ * JWT decoding utilities for session resumption checks.
4
+ * This module is exported for convenience and is no way part of public API,
5
+ * it can be removed at any time.
6
+ */
7
+ /**
8
+ * Decodes a JWT token
9
+ * @param token The token string
10
+ * @returns JSON object from the token
11
+ */
12
+ export declare const decodeJwt: (token: string) => unknown;
13
+ /**
14
+ * Decodes a URL-safe Base64 string
15
+ * @param str URL-safe Base64 that needed to be decoded
16
+ * @returns The actual string
17
+ */
18
+ export declare const base64UrlDecode: (str: string) => string;
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @module
3
+ * JWT decoding utilities for session resumption checks.
4
+ * This module is exported for convenience and is no way part of public API,
5
+ * it can be removed at any time.
6
+ */
7
+ /**
8
+ * Decodes a JWT token
9
+ * @param token The token string
10
+ * @returns JSON object from the token
11
+ */
12
+ export const decodeJwt = (token) => {
13
+ const pos = 1;
14
+ const part = token.split('.')[1];
15
+ let decoded;
16
+ if (typeof part !== 'string') {
17
+ throw new Error('invalid token: missing part ' + (pos + 1));
18
+ }
19
+ try {
20
+ decoded = base64UrlDecode(part);
21
+ }
22
+ catch (e) {
23
+ throw new Error('invalid token: invalid b64 for part ' + (pos + 1) + ' (' + e.message + ')');
24
+ }
25
+ try {
26
+ return JSON.parse(decoded);
27
+ }
28
+ catch (e) {
29
+ throw new Error('invalid token: invalid json for part ' + (pos + 1) + ' (' + e.message + ')');
30
+ }
31
+ };
32
+ /**
33
+ * Decodes a URL-safe Base64 string
34
+ * @param str URL-safe Base64 that needed to be decoded
35
+ * @returns The actual string
36
+ */
37
+ export const base64UrlDecode = (str) => {
38
+ let output = str.replace(/-/g, '+').replace(/_/g, '/');
39
+ switch (output.length % 4) {
40
+ case 0:
41
+ break;
42
+ case 2:
43
+ output += '==';
44
+ break;
45
+ case 3:
46
+ output += '=';
47
+ break;
48
+ default:
49
+ throw new Error('base64 string is not of the correct length');
50
+ }
51
+ try {
52
+ return b64DecodeUnicode(output);
53
+ }
54
+ catch {
55
+ return atob(output);
56
+ }
57
+ };
58
+ const b64DecodeUnicode = (str) => {
59
+ return decodeURIComponent(atob(str).replace(/(.)/g, (_m, p) => {
60
+ let code = p.charCodeAt(0).toString(16).toUpperCase();
61
+ if (code.length < 2) {
62
+ code = '0' + code;
63
+ }
64
+ return '%' + code;
65
+ }));
66
+ };
67
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../lib/utils/jwt.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,KAAa,EAAW,EAAE;IACnD,MAAM,GAAG,GAAG,CAAC,CAAC;IACd,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IAEjC,IAAI,OAAe,CAAC;IAEpB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,IAAI,KAAK,CAAC,8BAA8B,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,GAAG,eAAe,CAAC,IAAI,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,sCAAsC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,GAAI,CAAW,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;IACzG,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC5B,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CAAC,uCAAuC,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,GAAG,IAAI,GAAI,CAAW,CAAC,OAAO,GAAG,GAAG,CAAC,CAAC;IAC1G,CAAC;AACF,CAAC,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,GAAW,EAAU,EAAE;IACtD,IAAI,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAEvD,QAAQ,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3B,KAAK,CAAC;YACL,MAAM;QACP,KAAK,CAAC;YACL,MAAM,IAAI,IAAI,CAAC;YACf,MAAM;QACP,KAAK,CAAC;YACL,MAAM,IAAI,GAAG,CAAC;YACd,MAAM;QACP;YACC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAChE,CAAC;IAED,IAAI,CAAC;QACJ,OAAO,gBAAgB,CAAC,MAAM,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACR,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;AACF,CAAC,CAAC;AAEF,MAAM,gBAAgB,GAAG,CAAC,GAAW,EAAU,EAAE;IAChD,OAAO,kBAAkB,CACxB,IAAI,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC,EAAE,EAAE;QACnC,IAAI,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,WAAW,EAAE,CAAC;QAEtD,IAAI,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YACrB,IAAI,GAAG,GAAG,GAAG,IAAI,CAAC;QACnB,CAAC;QAED,OAAO,GAAG,GAAG,IAAI,CAAC;IACnB,CAAC,CAAC,CACF,CAAC;AACH,CAAC,CAAC"}
package/package.json ADDED
@@ -0,0 +1,29 @@
1
+ {
2
+ "type": "module",
3
+ "name": "@atcute/client",
4
+ "version": "1.0.0",
5
+ "description": "lightweight and cute API client for AT Protocol",
6
+ "license": "MIT",
7
+ "repository": {
8
+ "url": "https://codeberg.org/mary-ext/atcute"
9
+ },
10
+ "files": [
11
+ "dist/"
12
+ ],
13
+ "exports": {
14
+ ".": "./dist/index.js",
15
+ "./lexicons": "./dist/lexicons.js",
16
+ "./middlewares/auth": "./dist/middlewares/auth.js",
17
+ "./middlewares/mod": "./dist/middlewares/mod.js",
18
+ "./utils/did": "./dist/utils/did.js",
19
+ "./utils/jwt": "./dist/utils/jwt.js"
20
+ },
21
+ "devDependencies": {
22
+ "@atcute/lex-cli": "^1.0.0"
23
+ },
24
+ "scripts": {
25
+ "build": "tsc",
26
+ "generate": "./scripts/generate-lexicons.sh",
27
+ "prepublish": "rm -rf dist; pnpm run build"
28
+ }
29
+ }