@hatk/hatk 0.0.1-alpha.87 → 0.0.1-alpha.88

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.
@@ -18,5 +18,15 @@ export declare function discoverAuthServer(did: string, plcUrl: string): Promise
18
18
  authServerEndpoint: string;
19
19
  authServerMetadata: AuthServerMetadata;
20
20
  }>;
21
+ /**
22
+ * A handle to its DID.
23
+ *
24
+ * The protocol defines two ways, and both are asked first: the DNS TXT record
25
+ * and the well-known document. Either answers for a handle on any PDS, which
26
+ * is what lets somebody from another host sign in here. A handle neither
27
+ * method knows — a dev network's `.test` names, which have no DNS and no TLS
28
+ * — falls back to asking a PDS: the local one in dev, the one behind a
29
+ * self-hosted relay, or bsky.social.
30
+ */
21
31
  export declare function resolveHandle(handle: string, relayUrl?: string): Promise<string>;
22
32
  //# sourceMappingURL=discovery.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/oauth/discovery.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,sBAAsB,EAAE,MAAM,CAAA;IAC9B,cAAc,EAAE,MAAM,CAAA;IACtB,qCAAqC,CAAC,EAAE,MAAM,CAAA;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,iCAAiC,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAU1E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,wBAAsB,8BAA8B,CAClD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,qBAAqB,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAI9C;AAED,wBAAsB,uBAAuB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAIrG;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IACT,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,kBAAkB,EAAE,kBAAkB,CAAA;CACvC,CAAC,CAWD;AAED,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBtF"}
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/oauth/discovery.ts"],"names":[],"mappings":"AAIA,MAAM,WAAW,kBAAkB;IACjC,MAAM,EAAE,MAAM,CAAA;IACd,sBAAsB,EAAE,MAAM,CAAA;IAC9B,cAAc,EAAE,MAAM,CAAA;IACtB,qCAAqC,CAAC,EAAE,MAAM,CAAA;IAC9C,QAAQ,EAAE,MAAM,CAAA;IAChB,iCAAiC,CAAC,EAAE,MAAM,EAAE,CAAA;IAC5C,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAA;CACvB;AAED,wBAAsB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAU1E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI,CAGzD;AAED,wBAAsB,8BAA8B,CAClD,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC;IAAE,qBAAqB,EAAE,MAAM,EAAE,CAAA;CAAE,CAAC,CAI9C;AAED,wBAAsB,uBAAuB,CAAC,kBAAkB,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAIrG;AAED,wBAAsB,kBAAkB,CACtC,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,OAAO,CAAC;IACT,WAAW,EAAE,MAAM,CAAA;IACnB,kBAAkB,EAAE,MAAM,CAAA;IAC1B,kBAAkB,EAAE,kBAAkB,CAAA;CACvC,CAAC,CAWD;AA+BD;;;;;;;;;GASG;AACH,wBAAsB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAgBtF"}
@@ -1,4 +1,4 @@
1
- // packages/hatk/src/oauth/discovery.ts
1
+ import { resolveTxt } from 'node:dns/promises';
2
2
  export async function resolveDid(did, plcUrl) {
3
3
  if (did.startsWith('did:web:')) {
4
4
  const domain = did.slice('did:web:'.length);
@@ -40,10 +40,50 @@ export async function discoverAuthServer(did, plcUrl) {
40
40
  const authServerMetadata = await fetchAuthServerMetadata(authServerEndpoint);
41
41
  return { pdsEndpoint, authServerEndpoint, authServerMetadata };
42
42
  }
43
+ const HANDLE_RESOLVE_TIMEOUT_MS = 5000;
44
+ /** The DNS method: a `_atproto.<handle>` TXT record carrying `did=...`. */
45
+ async function resolveHandleViaDns(handle) {
46
+ try {
47
+ for (const chunks of await resolveTxt(`_atproto.${handle}`)) {
48
+ const txt = chunks.join('');
49
+ if (txt.startsWith('did='))
50
+ return txt.slice('did='.length).trim();
51
+ }
52
+ }
53
+ catch {
54
+ // No record, or not a resolvable name: not this method.
55
+ }
56
+ return null;
57
+ }
58
+ /** The HTTPS method: `https://<handle>/.well-known/atproto-did`, the DID as plain text. */
59
+ async function resolveHandleViaWellKnown(handle) {
60
+ try {
61
+ const res = await fetch(`https://${handle}/.well-known/atproto-did`, {
62
+ signal: AbortSignal.timeout(HANDLE_RESOLVE_TIMEOUT_MS),
63
+ });
64
+ if (!res.ok)
65
+ return null;
66
+ const did = (await res.text()).trim().split('\n')[0].trim();
67
+ return did.startsWith('did:') ? did : null;
68
+ }
69
+ catch {
70
+ return null;
71
+ }
72
+ }
73
+ /**
74
+ * A handle to its DID.
75
+ *
76
+ * The protocol defines two ways, and both are asked first: the DNS TXT record
77
+ * and the well-known document. Either answers for a handle on any PDS, which
78
+ * is what lets somebody from another host sign in here. A handle neither
79
+ * method knows — a dev network's `.test` names, which have no DNS and no TLS
80
+ * — falls back to asking a PDS: the local one in dev, the one behind a
81
+ * self-hosted relay, or bsky.social.
82
+ */
43
83
  export async function resolveHandle(handle, relayUrl) {
44
- // Resolve against the configured network: the localhost PDS in dev, the public
45
- // AppView in prod, or a self-hosted PDS (e.g. preview environments) derived
46
- // from its relay/firehose URL — otherwise self-hosted handles 400 against bsky.
84
+ const direct = (await resolveHandleViaDns(handle)) ?? (await resolveHandleViaWellKnown(handle));
85
+ if (direct)
86
+ return direct;
47
87
  let baseUrl;
48
88
  if (relayUrl?.includes('localhost:2583')) {
49
89
  baseUrl = 'http://localhost:2583';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hatk/hatk",
3
- "version": "0.0.1-alpha.87",
3
+ "version": "0.0.1-alpha.88",
4
4
  "license": "MIT",
5
5
  "bin": {
6
6
  "hatk": "dist/cli.js"