@atcute/oauth-browser-client 1.0.25 → 2.0.0-next.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/lib/resolvers.ts CHANGED
@@ -1,92 +1,61 @@
1
- import type { ComAtprotoIdentityResolveHandle } from '@atcute/atproto';
2
- import { type DidDocument, getPdsEndpoint } from '@atcute/identity';
3
- import type { Did, InferXRPCBodyOutput } from '@atcute/lexicons';
1
+ import { getPdsEndpoint } from '@atcute/identity';
2
+ import type { ActorIdentifier, Did } from '@atcute/lexicons';
4
3
  import { isDid } from '@atcute/lexicons/syntax';
5
4
 
6
- import { DEFAULT_APPVIEW_URL } from './constants.js';
5
+ import { didDocumentResolver, handleResolver } from './environment.js';
7
6
  import { ResolverError } from './errors.js';
8
7
  import type { IdentityMetadata } from './types/identity.js';
9
8
  import type { AuthorizationServerMetadata, ProtectedResourceMetadata } from './types/server.js';
10
9
  import { extractContentType } from './utils/response.js';
11
10
  import { isValidUrl } from './utils/strings.js';
12
11
 
13
- const DID_WEB_RE = /^([a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*(?:\.[a-zA-Z]{2,}))$/;
14
-
15
- /**
16
- * Resolves domain handles into DID identifiers, by requesting Bluesky's AppView
17
- * for identity resolution.
18
- * @param handle Domain handle to resolve
19
- * @returns DID identifier resolved from the domain handle
20
- */
21
- export const resolveHandle = async (handle: string): Promise<Did> => {
22
- const url = DEFAULT_APPVIEW_URL + `/xrpc/com.atproto.identity.resolveHandle` + `?handle=${handle}`;
23
-
24
- const response = await fetch(url);
25
- if (response.status === 400) {
26
- throw new ResolverError(`domain handle not found`);
27
- } else if (!response.ok) {
28
- throw new ResolverError(`directory is unreachable`);
12
+ export const resolveFromIdentifier = async (
13
+ ident: ActorIdentifier,
14
+ ): Promise<{ identity: IdentityMetadata; metadata: AuthorizationServerMetadata }> => {
15
+ let did: Did;
16
+ if (isDid(ident)) {
17
+ did = ident;
18
+ } else {
19
+ const resolved = await handleResolver.resolve(ident);
20
+ did = resolved;
29
21
  }
30
22
 
31
- const json = (await response.json()) as InferXRPCBodyOutput<
32
- ComAtprotoIdentityResolveHandle.mainSchema['output']
33
- >;
34
- return json.did;
35
- };
36
-
37
- /**
38
- * Get DID documents of did:plc (via plc.directory) and did:web identifiers
39
- * @param did DID identifier we're seeking DID doc from
40
- * @returns Retrieved DID document
41
- */
42
- export const getDidDocument = async (did: Did): Promise<DidDocument> => {
43
- const colon_index = did.indexOf(':', 4);
44
-
45
- const type = did.slice(4, colon_index);
46
- const ident = did.slice(colon_index + 1);
47
-
48
- // 2. retrieve their DID documents
49
- let doc: DidDocument;
50
-
51
- if (type === 'plc') {
52
- const response = await fetch(`https://plc.directory/${did}`);
53
-
54
- if (response.status === 404) {
55
- throw new ResolverError(`did not found in directory`);
56
- } else if (!response.ok) {
57
- throw new ResolverError(`directory is unreachable`);
58
- }
59
-
60
- const json = await response.json();
23
+ const doc = await didDocumentResolver.resolve(did);
24
+ const pds = getPdsEndpoint(doc);
61
25
 
62
- doc = json as DidDocument;
63
- } else if (type === 'web') {
64
- if (!DID_WEB_RE.test(ident)) {
65
- throw new ResolverError(`invalid identifier`);
66
- }
26
+ if (!pds) {
27
+ throw new ResolverError(`missing pds endpoint`);
28
+ }
67
29
 
68
- const response = await fetch(`https://${ident}/.well-known/did.json`);
30
+ return {
31
+ identity: {
32
+ id: did,
33
+ raw: ident,
34
+ pds: new URL(pds),
35
+ },
36
+ metadata: await getMetadataFromResourceServer(pds),
37
+ };
38
+ };
69
39
 
70
- if (!response.ok) {
71
- throw new ResolverError(`did document is unreachable`);
40
+ export const resolveFromService = async (
41
+ host: string,
42
+ ): Promise<{ metadata: AuthorizationServerMetadata }> => {
43
+ try {
44
+ const metadata = await getMetadataFromResourceServer(host);
45
+ return { metadata };
46
+ } catch (err) {
47
+ if (err instanceof ResolverError) {
48
+ try {
49
+ const metadata = await getAuthorizationServerMetadata(host);
50
+ return { metadata };
51
+ } catch {}
72
52
  }
73
53
 
74
- const json = await response.json();
75
-
76
- doc = json as DidDocument;
77
- } else {
78
- throw new ResolverError(`unsupported did method`);
54
+ throw err;
79
55
  }
80
-
81
- return doc;
82
56
  };
83
57
 
84
- /**
85
- * Get OAuth protected resource metadata from a host
86
- * @param host URL of the host
87
- * @returns Retrieved protected resource metadata
88
- */
89
- export const getProtectedResourceMetadata = async (host: string): Promise<ProtectedResourceMetadata> => {
58
+ const getProtectedResourceMetadata = async (host: string): Promise<ProtectedResourceMetadata> => {
90
59
  const url = new URL(`/.well-known/oauth-protected-resource`, host);
91
60
  const response = await fetch(url, {
92
61
  redirect: 'manual',
@@ -107,12 +76,7 @@ export const getProtectedResourceMetadata = async (host: string): Promise<Protec
107
76
  return metadata;
108
77
  };
109
78
 
110
- /**
111
- * Get OAuth authorization server metadata from a host
112
- * @param host URL of the host
113
- * @returns Retrieved authorization server metadata
114
- */
115
- export const getAuthorizationServerMetadata = async (host: string): Promise<AuthorizationServerMetadata> => {
79
+ const getAuthorizationServerMetadata = async (host: string): Promise<AuthorizationServerMetadata> => {
116
80
  const url = new URL(`/.well-known/oauth-authorization-server`, host);
117
81
  const response = await fetch(url, {
118
82
  redirect: 'manual',
@@ -147,68 +111,7 @@ export const getAuthorizationServerMetadata = async (host: string): Promise<Auth
147
111
  return metadata;
148
112
  };
149
113
 
150
- /**
151
- * Resolve handle domains or DID identifiers to get their PDS and its authorization server metadata
152
- * @param ident Handle domain or DID identifier to resolve
153
- * @returns Resolved PDS and authorization server metadata
154
- */
155
- export const resolveFromIdentity = async (
156
- ident: string,
157
- ): Promise<{ identity: IdentityMetadata; metadata: AuthorizationServerMetadata }> => {
158
- let did: Did;
159
- if (isDid(ident)) {
160
- did = ident;
161
- } else {
162
- const resolved = await resolveHandle(ident);
163
- did = resolved;
164
- }
165
-
166
- const doc = await getDidDocument(did);
167
- const pds = getPdsEndpoint(doc);
168
-
169
- if (!pds) {
170
- throw new ResolverError(`missing pds endpoint`);
171
- }
172
-
173
- return {
174
- identity: {
175
- id: did,
176
- raw: ident,
177
- pds: new URL(pds),
178
- },
179
- metadata: await getMetadataFromResourceServer(pds),
180
- };
181
- };
182
-
183
- /**
184
- * Request authorization server metadata from a PDS
185
- * @param host URL of the host
186
- * @returns Resolved authorization server metadata
187
- */
188
- export const resolveFromService = async (
189
- host: string,
190
- ): Promise<{ metadata: AuthorizationServerMetadata }> => {
191
- try {
192
- const metadata = await getMetadataFromResourceServer(host);
193
- return { metadata };
194
- } catch (err) {
195
- if (err instanceof ResolverError) {
196
- try {
197
- const metadata = await getAuthorizationServerMetadata(host);
198
- return { metadata };
199
- } catch {}
200
- }
201
-
202
- throw err;
203
- }
204
- };
205
-
206
- /**
207
- * Request authorization server metadata from its protected resource metadata
208
- * @param input URL of the host whose authorization server is delegated
209
- * @returns Resolved authorization server metadata
210
- */
211
- export const getMetadataFromResourceServer = async (input: string) => {
114
+ const getMetadataFromResourceServer = async (input: string) => {
212
115
  const rs_metadata = await getProtectedResourceMetadata(input);
213
116
 
214
117
  if (rs_metadata.authorization_servers?.length !== 1) {
package/package.json CHANGED
@@ -1,9 +1,9 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@atcute/oauth-browser-client",
4
- "version": "1.0.25",
4
+ "version": "2.0.0-next.0",
5
5
  "description": "minimal OAuth browser client implementation for AT Protocol",
6
- "license": "MIT",
6
+ "license": "0BSD",
7
7
  "repository": {
8
8
  "url": "https://github.com/mary-ext/atcute",
9
9
  "directory": "packages/oauth/browser-client"
@@ -20,14 +20,15 @@
20
20
  "sideEffects": false,
21
21
  "dependencies": {
22
22
  "nanoid": "^5.1.5",
23
- "@atcute/identity": "^1.0.2",
24
- "@atcute/lexicons": "^1.0.4",
23
+ "@atcute/identity": "^1.1.0",
24
+ "@atcute/identity-resolver": "^1.1.3",
25
25
  "@atcute/client": "^4.0.3",
26
+ "@atcute/lexicons": "^1.1.1",
26
27
  "@atcute/multibase": "^1.1.4",
27
28
  "@atcute/uint8array": "^1.0.3"
28
29
  },
29
30
  "devDependencies": {
30
- "@atcute/atproto": "^3.0.3"
31
+ "@atcute/atproto": "^3.1.2"
31
32
  },
32
33
  "scripts": {
33
34
  "build": "tsc --project tsconfig.build.json",