@hatk/hatk 0.0.1-alpha.74 → 0.0.1-alpha.76
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/dist/config.d.ts +15 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +1 -0
- package/dist/oauth/server.d.ts.map +1 -1
- package/dist/oauth/server.js +4 -2
- package/dist/oauth/service-describe.d.ts +31 -0
- package/dist/oauth/service-describe.d.ts.map +1 -0
- package/dist/oauth/service-describe.js +61 -0
- package/dist/pds-proxy.d.ts +22 -0
- package/dist/pds-proxy.d.ts.map +1 -1
- package/dist/pds-proxy.js +39 -3
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +6 -0
- package/dist/xrpc.d.ts +7 -0
- package/dist/xrpc.d.ts.map +1 -1
- package/dist/xrpc.js +8 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -21,6 +21,21 @@ export interface OAuthConfig {
|
|
|
21
21
|
scopes: string[];
|
|
22
22
|
clients: OAuthClientConfig[];
|
|
23
23
|
cookieName?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Scopes requested only from PDSes that serve `whenMethod`, discovered
|
|
26
|
+
* through `community.lexicon.service.describe` before the authorization
|
|
27
|
+
* request is pushed.
|
|
28
|
+
*
|
|
29
|
+
* For optional protocol features — permissioned spaces (proposal 0016) being
|
|
30
|
+
* the first — where asking every PDS for the scope would put a permission on
|
|
31
|
+
* the consent screen that most servers cannot honor.
|
|
32
|
+
*/
|
|
33
|
+
conditionalScopes?: ConditionalScopeConfig[];
|
|
34
|
+
}
|
|
35
|
+
export interface ConditionalScopeConfig {
|
|
36
|
+
/** An XRPC method whose presence means the PDS implements the feature. */
|
|
37
|
+
whenMethod: string;
|
|
38
|
+
scopes: string[];
|
|
24
39
|
}
|
|
25
40
|
export interface BackfillConfig {
|
|
26
41
|
signalCollections?: string[];
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,EAAE,MAAM,CAAA;CACpB;AAED,MAAM,WAAW,eAAe;IAC9B,UAAU,EAAE,MAAM,CAAA;IAClB,QAAQ,EAAE,OAAO,GAAG,QAAQ,GAAG,MAAM,CAAA;IACrC,KAAK,EAAE,OAAO,GAAG,SAAS,GAAG,MAAM,CAAA;IACnC,cAAc,EAAE,MAAM,GAAG,MAAM,GAAG,QAAQ,CAAA;IAC1C,OAAO,CAAC,EAAE,WAAW,EAAE,CAAA;CACxB;AAED,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAA;IACjB,WAAW,EAAE,MAAM,CAAA;IACnB,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,OAAO,EAAE,iBAAiB,EAAE,CAAA;IAC5B,UAAU,CAAC,EAAE,MAAM,CAAA;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/config.js
CHANGED
|
@@ -70,6 +70,7 @@ export async function loadConfig(configPath) {
|
|
|
70
70
|
issuer: process.env.OAUTH_ISSUER || oauthRaw.issuer || `http://127.0.0.1:${config.port}`,
|
|
71
71
|
scopes: oauthRaw.scopes || ['atproto'],
|
|
72
72
|
clients: oauthRaw.clients || [],
|
|
73
|
+
conditionalScopes: oauthRaw.conditionalScopes || [],
|
|
73
74
|
};
|
|
74
75
|
}
|
|
75
76
|
return config;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/oauth/server.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/oauth/server.ts"],"names":[],"mappings":"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"}
|
package/dist/oauth/server.js
CHANGED
|
@@ -3,6 +3,7 @@ import { generateKeyPair, importPrivateKey, computeJwkThumbprint, signJwt, parse
|
|
|
3
3
|
import { parseDpopProof, createDpopProof } from "./dpop.js";
|
|
4
4
|
import { initSession } from "./session.js";
|
|
5
5
|
import { resolveClient, validateRedirectUri, isLoopbackClient } from "./client.js";
|
|
6
|
+
import { negotiateScope } from "./service-describe.js";
|
|
6
7
|
import { discoverAuthServer, resolveHandle, fetchProtectedResourceMetadata, fetchAuthServerMetadata, } from "./discovery.js";
|
|
7
8
|
import { getServerKey, storeServerKey, storeOAuthRequest, getOAuthRequest, deleteOAuthRequest, storeAuthCode, consumeAuthCode, storeSession, deleteSession, checkAndStoreDpopJti, cleanupExpiredOAuth, storeRefreshToken, getRefreshToken, revokeRefreshToken, } from "./db.js";
|
|
8
9
|
import { emit } from "../logger.js";
|
|
@@ -312,13 +313,14 @@ export async function handlePar(config, body, dpopHeader, requestUrl) {
|
|
|
312
313
|
// PAR to the PDS
|
|
313
314
|
const parEndpoint = authServerMetadata.pushed_authorization_request_endpoint || `${pdsAuthServer}/oauth/par`;
|
|
314
315
|
const serverDpopProof = await createDpopProof(serverPrivateJwk, serverPublicJwk, 'POST', parEndpoint);
|
|
316
|
+
const pdsScope = await negotiateScope(config, body.scope || 'atproto transition:generic', pdsEndpoint, isLoopbackClient(config.issuer));
|
|
315
317
|
const pdsParParams = {
|
|
316
318
|
client_id: pdsClientId(config.issuer, config),
|
|
317
319
|
redirect_uri: pdsRedirectUri(config.issuer),
|
|
318
320
|
response_type: 'code',
|
|
319
321
|
code_challenge: pdsCodeChallenge,
|
|
320
322
|
code_challenge_method: 'S256',
|
|
321
|
-
scope:
|
|
323
|
+
scope: pdsScope,
|
|
322
324
|
state: pdsState,
|
|
323
325
|
};
|
|
324
326
|
if (prompt === 'create') {
|
|
@@ -452,7 +454,7 @@ export async function serverLogin(config, handle, options) {
|
|
|
452
454
|
// PAR to the PDS
|
|
453
455
|
const parEndpoint = authServerMetadata.pushed_authorization_request_endpoint || `${pdsAuthServer}/oauth/par`;
|
|
454
456
|
const serverDpopProof = await createDpopProof(serverPrivateJwk, serverPublicJwk, 'POST', parEndpoint);
|
|
455
|
-
const scope = config.scopes?.join(' ') || 'atproto transition:generic';
|
|
457
|
+
const scope = await negotiateScope(config, config.scopes?.join(' ') || 'atproto transition:generic', pdsEndpoint, isLoopbackClient(config.issuer));
|
|
456
458
|
const pdsParParams = {
|
|
457
459
|
client_id: pdsClientId(config.issuer, config),
|
|
458
460
|
redirect_uri: pdsRedirectUri(config.issuer),
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* What a PDS says it serves, and the scopes worth asking it for.
|
|
3
|
+
*
|
|
4
|
+
* `community.lexicon.service.describe` answers with a service's roles and every
|
|
5
|
+
* XRPC method it routes. It is the only way to ask: atproto publishes no method
|
|
6
|
+
* list, so the alternative is to call a method and read the failure, where a
|
|
7
|
+
* server without an optional feature and one that is broken look alike.
|
|
8
|
+
*
|
|
9
|
+
* Used before pushing an authorization request, so a PDS is asked for a
|
|
10
|
+
* feature's scopes only when it implements the feature.
|
|
11
|
+
*/
|
|
12
|
+
import type { OAuthConfig } from '../config.ts';
|
|
13
|
+
/**
|
|
14
|
+
* Every XRPC method a PDS serves. An empty set for a server that answers no
|
|
15
|
+
* describe — which is every PDS that predates the method, so absence has to
|
|
16
|
+
* read as "no optional features" rather than as an error.
|
|
17
|
+
*/
|
|
18
|
+
export declare function describeMethods(pdsEndpoint: string): Promise<Set<string>>;
|
|
19
|
+
/**
|
|
20
|
+
* The scope string to request from this PDS: `base`, plus any conditional set
|
|
21
|
+
* whose `whenMethod` the server serves.
|
|
22
|
+
*
|
|
23
|
+
* Loopback clients are left alone. Their client_id encodes the scope they may
|
|
24
|
+
* request, and the token exchange rebuilds that client_id from config — vary
|
|
25
|
+
* the request and the two disagree. A local setup that needs the extra scopes
|
|
26
|
+
* lists them in its client's own `scope` instead.
|
|
27
|
+
*/
|
|
28
|
+
export declare function negotiateScope(config: OAuthConfig, base: string, pdsEndpoint: string | undefined, isLoopback: boolean): Promise<string>;
|
|
29
|
+
/** Drop cached describe answers. For tests. */
|
|
30
|
+
export declare function clearDescribeCache(): void;
|
|
31
|
+
//# sourceMappingURL=service-describe.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service-describe.d.ts","sourceRoot":"","sources":["../../src/oauth/service-describe.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAU/C;;;;GAIG;AACH,wBAAsB,eAAe,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAwB/E;AAED;;;;;;;;GAQG;AACH,wBAAsB,cAAc,CAClC,MAAM,EAAE,WAAW,EACnB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,GAAG,SAAS,EAC/B,UAAU,EAAE,OAAO,GAClB,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,+CAA+C;AAC/C,wBAAgB,kBAAkB,IAAI,IAAI,CAEzC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { emit } from "../logger.js";
|
|
2
|
+
const DESCRIBE_NSID = 'community.lexicon.service.describe';
|
|
3
|
+
const PROBE_TIMEOUT_MS = 5000;
|
|
4
|
+
const CACHE_TTL_MS = 60 * 60 * 1000;
|
|
5
|
+
/** Answers are a property of the server, so one entry covers every account on it. */
|
|
6
|
+
const cache = new Map();
|
|
7
|
+
/**
|
|
8
|
+
* Every XRPC method a PDS serves. An empty set for a server that answers no
|
|
9
|
+
* describe — which is every PDS that predates the method, so absence has to
|
|
10
|
+
* read as "no optional features" rather than as an error.
|
|
11
|
+
*/
|
|
12
|
+
export async function describeMethods(pdsEndpoint) {
|
|
13
|
+
const cached = cache.get(pdsEndpoint);
|
|
14
|
+
if (cached && cached.expires > Date.now())
|
|
15
|
+
return cached.methods;
|
|
16
|
+
let methods = new Set();
|
|
17
|
+
try {
|
|
18
|
+
const res = await fetch(`${pdsEndpoint.replace(/\/$/, '')}/xrpc/${DESCRIBE_NSID}`, {
|
|
19
|
+
headers: { accept: 'application/json' },
|
|
20
|
+
signal: AbortSignal.timeout(PROBE_TIMEOUT_MS),
|
|
21
|
+
});
|
|
22
|
+
if (res.ok) {
|
|
23
|
+
const body = (await res.json().catch(() => null));
|
|
24
|
+
if (Array.isArray(body?.methods)) {
|
|
25
|
+
for (const m of body.methods) {
|
|
26
|
+
if (typeof m?.value === 'string')
|
|
27
|
+
methods.add(m.value);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
methods = new Set();
|
|
34
|
+
}
|
|
35
|
+
cache.set(pdsEndpoint, { methods, expires: Date.now() + CACHE_TTL_MS });
|
|
36
|
+
return methods;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The scope string to request from this PDS: `base`, plus any conditional set
|
|
40
|
+
* whose `whenMethod` the server serves.
|
|
41
|
+
*
|
|
42
|
+
* Loopback clients are left alone. Their client_id encodes the scope they may
|
|
43
|
+
* request, and the token exchange rebuilds that client_id from config — vary
|
|
44
|
+
* the request and the two disagree. A local setup that needs the extra scopes
|
|
45
|
+
* lists them in its client's own `scope` instead.
|
|
46
|
+
*/
|
|
47
|
+
export async function negotiateScope(config, base, pdsEndpoint, isLoopback) {
|
|
48
|
+
const conditional = config.conditionalScopes ?? [];
|
|
49
|
+
if (conditional.length === 0 || !pdsEndpoint || isLoopback)
|
|
50
|
+
return base;
|
|
51
|
+
const methods = await describeMethods(pdsEndpoint);
|
|
52
|
+
const granted = conditional.filter((c) => methods.has(c.whenMethod)).flatMap((c) => c.scopes);
|
|
53
|
+
if (granted.length === 0)
|
|
54
|
+
return base;
|
|
55
|
+
emit('oauth', 'conditional_scopes', { pds: pdsEndpoint, scopes: granted });
|
|
56
|
+
return [base, ...granted].join(' ');
|
|
57
|
+
}
|
|
58
|
+
/** Drop cached describe answers. For tests. */
|
|
59
|
+
export function clearDescribeCache() {
|
|
60
|
+
cache.clear();
|
|
61
|
+
}
|
package/dist/pds-proxy.d.ts
CHANGED
|
@@ -6,6 +6,28 @@ export declare class ProxyError extends Error {
|
|
|
6
6
|
export declare class ScopeMissingProxyError extends ProxyError {
|
|
7
7
|
constructor();
|
|
8
8
|
}
|
|
9
|
+
export interface PdsXrpcOptions {
|
|
10
|
+
/** Defaults to GET, matching the XRPC convention for queries. */
|
|
11
|
+
method?: 'GET' | 'POST';
|
|
12
|
+
/** Query parameters. Undefined values are dropped; arrays repeat the key. */
|
|
13
|
+
params?: Record<string, string | number | boolean | string[] | undefined>;
|
|
14
|
+
/** JSON request body. Ignored for GET. */
|
|
15
|
+
body?: unknown;
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Call any XRPC method on the user's PDS with their session.
|
|
19
|
+
*
|
|
20
|
+
* The escape hatch beside the typed record helpers above, for methods hatk has
|
|
21
|
+
* no opinion about — `com.atproto.space.*` and the rest of proposal 0016 being
|
|
22
|
+
* the case it was added for. Nothing is validated or indexed: the response is
|
|
23
|
+
* whatever the PDS sent, and it is the caller's job to know its shape.
|
|
24
|
+
*
|
|
25
|
+
* The session's granted scopes still apply. A method the user never authorized
|
|
26
|
+
* comes back as a 403 from the PDS, not from here.
|
|
27
|
+
*/
|
|
28
|
+
export declare function pdsXrpc(oauthConfig: OAuthConfig, viewer: {
|
|
29
|
+
did: string;
|
|
30
|
+
}, nsid: string, options?: PdsXrpcOptions): Promise<Record<string, unknown>>;
|
|
9
31
|
export declare function pdsCreateRecord(oauthConfig: OAuthConfig, viewer: {
|
|
10
32
|
did: string;
|
|
11
33
|
}, input: {
|
package/dist/pds-proxy.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pds-proxy.d.ts","sourceRoot":"","sources":["../src/pds-proxy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAU9C,qBAAa,UAAW,SAAQ,KAAK;IAE1B,MAAM,EAAE,MAAM;gBAAd,MAAM,EAAE,MAAM,EACrB,OAAO,EAAE,MAAM;CAIlB;AAED,qBAAa,sBAAuB,SAAQ,UAAU;;CAIrD;
|
|
1
|
+
{"version":3,"file":"pds-proxy.d.ts","sourceRoot":"","sources":["../src/pds-proxy.ts"],"names":[],"mappings":"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"}
|
package/dist/pds-proxy.js
CHANGED
|
@@ -66,14 +66,17 @@ async function proxyToPds(oauthConfig, session, method, pdsUrl, body) {
|
|
|
66
66
|
const publicJwk = JSON.parse(serverKey.publicKey);
|
|
67
67
|
return withDpopRetry(oauthConfig, session, async (token, nonce) => {
|
|
68
68
|
const proof = await createDpopProof(privateJwk, publicJwk, method, pdsUrl, token, nonce);
|
|
69
|
+
// A GET carries no body, and sending a JSON content-type without one makes
|
|
70
|
+
// some servers try to parse it. Queries reach here through pdsXrpc.
|
|
71
|
+
const hasBody = method !== 'GET' && body !== undefined;
|
|
69
72
|
const res = await fetch(pdsUrl, {
|
|
70
73
|
method,
|
|
71
74
|
headers: {
|
|
72
|
-
'Content-Type': 'application/json',
|
|
75
|
+
...(hasBody ? { 'Content-Type': 'application/json' } : {}),
|
|
73
76
|
Authorization: `DPoP ${token}`,
|
|
74
77
|
DPoP: proof,
|
|
75
78
|
},
|
|
76
|
-
body: JSON.stringify(body),
|
|
79
|
+
body: hasBody ? JSON.stringify(body) : undefined,
|
|
77
80
|
});
|
|
78
81
|
const resBody = await res.json().catch(() => ({}));
|
|
79
82
|
return { ok: res.ok, status: res.status, body: resBody, headers: res.headers };
|
|
@@ -100,7 +103,40 @@ async function proxyToPdsRaw(oauthConfig, session, pdsUrl, body, contentType) {
|
|
|
100
103
|
return { ok: res.ok, status: res.status, body: resBody, headers: res.headers };
|
|
101
104
|
});
|
|
102
105
|
}
|
|
103
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Call any XRPC method on the user's PDS with their session.
|
|
108
|
+
*
|
|
109
|
+
* The escape hatch beside the typed record helpers above, for methods hatk has
|
|
110
|
+
* no opinion about — `com.atproto.space.*` and the rest of proposal 0016 being
|
|
111
|
+
* the case it was added for. Nothing is validated or indexed: the response is
|
|
112
|
+
* whatever the PDS sent, and it is the caller's job to know its shape.
|
|
113
|
+
*
|
|
114
|
+
* The session's granted scopes still apply. A method the user never authorized
|
|
115
|
+
* comes back as a 403 from the PDS, not from here.
|
|
116
|
+
*/
|
|
117
|
+
export async function pdsXrpc(oauthConfig, viewer, nsid, options = {}) {
|
|
118
|
+
const session = await getSession(viewer.did);
|
|
119
|
+
if (!session)
|
|
120
|
+
throw new ProxyError(401, 'No PDS session for user');
|
|
121
|
+
const method = options.method ?? 'GET';
|
|
122
|
+
const url = new URL(`${session.pds_endpoint}/xrpc/${nsid}`);
|
|
123
|
+
for (const [key, value] of Object.entries(options.params ?? {})) {
|
|
124
|
+
if (value === undefined)
|
|
125
|
+
continue;
|
|
126
|
+
if (Array.isArray(value)) {
|
|
127
|
+
for (const v of value)
|
|
128
|
+
url.searchParams.append(key, String(v));
|
|
129
|
+
}
|
|
130
|
+
else {
|
|
131
|
+
url.searchParams.append(key, String(value));
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const res = await proxyToPds(oauthConfig, session, method, url.toString(), options.body);
|
|
135
|
+
if (!res.ok) {
|
|
136
|
+
throw new ProxyError(res.status, String(res.body.error || `${nsid} failed`));
|
|
137
|
+
}
|
|
138
|
+
return res.body;
|
|
139
|
+
}
|
|
104
140
|
export async function pdsCreateRecord(oauthConfig, viewer, input) {
|
|
105
141
|
const validationError = validateRecord(getLexiconArray(), input.collection, input.record);
|
|
106
142
|
if (validationError) {
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAqEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA4B9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAqM3F;AAgDD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAqEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AA4B9C;;;GAGG;AACH,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,KAAK,EAAE,WAAW,GAAG,IAAI,GAAG,IAAI,CAqM3F;AAgDD,MAAM,WAAW,aAAa;IAC5B,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,SAAS,EAAE,MAAM,GAAG,IAAI,CAAA;IACxB,KAAK,EAAE,WAAW,GAAG,IAAI,CAAA;IACzB,MAAM,EAAE,MAAM,EAAE,CAAA;IAChB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,GAAG,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IACxF,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAA;CACtB;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAkhC5F;AAGD,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,MAAM,EAAE,EACrB,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,KAAK,EAAE,WAAW,GAAG,IAAI,EACzB,MAAM,GAAE,MAAM,EAAO,EACrB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC5D,QAAQ,CAAC,EAAE,MAAM,IAAI,GACpB,OAAO,WAAW,EAAE,MAAM,CAG5B"}
|
package/dist/server.js
CHANGED
|
@@ -1170,6 +1170,12 @@ export function createHandler(config) {
|
|
|
1170
1170
|
}
|
|
1171
1171
|
try {
|
|
1172
1172
|
const result = await executeXrpc(method, params, cursor, limit, viewer, input);
|
|
1173
|
+
// A handler may answer with a Response of its own, which is the only
|
|
1174
|
+
// way to serve anything but JSON — com.atproto.sync.getBlob is the
|
|
1175
|
+
// shape in the wild, and a lexicon declaring `encoding: "*/*"` has no
|
|
1176
|
+
// other way to honour it. Everything else is serialized as before.
|
|
1177
|
+
if (result instanceof Response)
|
|
1178
|
+
return withCors(result);
|
|
1173
1179
|
if (result)
|
|
1174
1180
|
return withCors(json(result, 200, acceptEncoding));
|
|
1175
1181
|
}
|
package/dist/xrpc.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { BaseContext } from './hydrate.ts';
|
|
2
2
|
import type { Row, FlatRow } from './lex-types.ts';
|
|
3
3
|
import type { OAuthConfig, CdnConfig } from './config.ts';
|
|
4
|
+
import type { PdsXrpcOptions } from './pds-proxy.ts';
|
|
4
5
|
export type { Row, FlatRow };
|
|
5
6
|
/** Set the OAuth config used for record write helpers. Called once during boot. */
|
|
6
7
|
export declare function configureOAuth(config: OAuthConfig | null): void;
|
|
@@ -73,6 +74,12 @@ export interface XrpcContext<P = Record<string, string>, Records extends Record<
|
|
|
73
74
|
cid?: string;
|
|
74
75
|
}>;
|
|
75
76
|
}>;
|
|
77
|
+
/**
|
|
78
|
+
* Call any XRPC method on the viewer's PDS with their session. The escape
|
|
79
|
+
* hatch beside the record helpers above: nothing is validated or indexed, and
|
|
80
|
+
* the granted scopes still apply. See {@link pdsXrpc}.
|
|
81
|
+
*/
|
|
82
|
+
pds: (nsid: string, options?: PdsXrpcOptions) => Promise<Record<string, unknown>>;
|
|
76
83
|
}
|
|
77
84
|
/** Set the relay URL used for blob URL generation. Called once during boot. */
|
|
78
85
|
export declare function configureRelay(relay: string): void;
|
package/dist/xrpc.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"xrpc.d.ts","sourceRoot":"","sources":["../src/xrpc.ts"],"names":[],"mappings":"AAsCA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAA;AAE/C,OAAO,KAAK,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,KAAK,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAEzD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAA;AAEpD,YAAY,EAAE,GAAG,EAAE,OAAO,EAAE,CAAA;AAI5B,mFAAmF;AACnF,wBAAgB,cAAc,CAAC,MAAM,EAAE,WAAW,GAAG,IAAI,QAExD;AAED,gFAAgF;AAChF,qBAAa,mBAAoB,SAAQ,KAAK;IAC5C,MAAM,SAAM;IACZ,SAAS,CAAC,EAAE,MAAM,CAAA;gBACN,OAAO,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM;CAIhD;AACD,0DAA0D;AAC1D,qBAAa,aAAc,SAAQ,mBAAmB;IACpD,MAAM,SAAM;gBACA,OAAO,SAAc;CAGlC;AAED;;;;;;;;GAQG;AACH,MAAM,WAAW,WAAW,CAC1B,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC1B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACzD,CAAC,GAAG,OAAO,CACX,SAAQ,WAAW;IACnB,EAAE,EAAE;QACF,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;QAC9D,GAAG,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;KACxD,CAAA;IACD,MAAM,EAAE,CAAC,CAAA;IACT,KAAK,EAAE,CAAC,CAAA;IACR,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,EAAE,MAAM,CAAA;IACb,UAAU,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,MAAM,CAAA;IAC7D,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IACzE,WAAW,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAC9C,mBAAmB,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAA;IAC7D,MAAM,EAAE,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,OAAO,EACvC,UAAU,EAAE,CAAC,EACb,CAAC,EAAE,MAAM,EACT,IAAI,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE,KACxD,OAAO,CAAC;QAAE,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC7D,OAAO,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAA;IAC3D,MAAM,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACjF,YAAY,EAAE,CACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,CAAC,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAA;KAAE,KACrB,OAAO,CAAC;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5C,SAAS,EAAE,CACT,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAC5B,OAAO,CAAC;QAAE,GAAG,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC5C,YAAY,EAAE,CAAC,UAAU,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACjE,WAAW,EAAE,CACX,MAAM,EAAE,KAAK,CAAC;QACZ,KAAK,EAAE,MAAM,CAAA;QACb,UAAU,EAAE,MAAM,CAAA;QAClB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAChC,CAAC,KACC,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,KAAK,CAAC;YAAE,KAAK,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAC;YAAC,GAAG,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC,CAAA;KAAE,CAAC,CAAA;IAChF;;;;OAIG;IACH,GAAG,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,KAAK,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;CAClF;AAiBD,+EAA+E;AAC/E,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,QAE3C;AAED,4EAA4E;AAC5E,wBAAgB,YAAY,CAAC,GAAG,EAAE,SAAS,GAAG,IAAI,QAUjD;AAWD;;;GAGG;AACH,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,GAAE,MAAiB,GAAG,MAAM,GAAG,SAAS,CAYhG;AAED,mGAAmG;AACnG,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC/C,KAAK,CAAC,EAAE,OAAO,GACd,WAAW,CA8Cb;AAoBD;;;;GAIG;AACH,wBAAsB,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAwC7D;AAED,oEAAoE;AACpE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,aAAa,EAAE;IAAE,OAAO,EAAE,CAAC,GAAG,EAAE,GAAG,KAAK,OAAO,CAAC,GAAG,CAAC,CAAA;CAAE,GAAG,IAAI,CA2B9G;AAED,qFAAqF;AACrF,wBAAsB,WAAW,CAC/B,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,CAAC,EAAE;IAAE,GAAG,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC/B,KAAK,CAAC,EAAE,OAAO,GACd,OAAO,CAAC,GAAG,GAAG,IAAI,CAAC,CAYrB;AAED,mFAAmF;AACnF,wBAAsB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAM,EAAE,KAAK,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,CAgB5G;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CACF,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,MAAM,EAAE,MAAM,GAAG,SAAS,EAC1B,KAAK,EAAE,MAAM,EACb,MAAM,EAAE;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,EAC/C,KAAK,CAAC,EAAE,OAAO,KACZ,OAAO,CAAC,GAAG,CAAC,GAChB,IAAI,CAEN;AAED,+CAA+C;AAC/C,wBAAgB,QAAQ,IAAI,MAAM,EAAE,CAEnC"}
|
package/dist/xrpc.js
CHANGED
|
@@ -33,7 +33,7 @@ import { querySQL, runSQL, packCursor, unpackCursor, isTakendownDid, filterTaken
|
|
|
33
33
|
import { resolveRecords, buildBaseContext } from "./hydrate.js";
|
|
34
34
|
import { getLexicon } from "./database/schema.js";
|
|
35
35
|
import { createHmac } from 'node:crypto';
|
|
36
|
-
import { pdsCreateRecord, pdsPutRecord, pdsDeleteRecord, pdsApplyWrites } from "./pds-proxy.js";
|
|
36
|
+
import { pdsCreateRecord, pdsPutRecord, pdsDeleteRecord, pdsApplyWrites, pdsXrpc } from "./pds-proxy.js";
|
|
37
37
|
let _oauthConfig = null;
|
|
38
38
|
/** Set the OAuth config used for record write helpers. Called once during boot. */
|
|
39
39
|
export function configureOAuth(config) {
|
|
@@ -150,6 +150,13 @@ export function buildXrpcContext(params, cursor, limit, viewer, input) {
|
|
|
150
150
|
throw new Error('Authentication required to write records');
|
|
151
151
|
return pdsApplyWrites(_oauthConfig, viewer, { writes });
|
|
152
152
|
},
|
|
153
|
+
pds: async (nsid, options) => {
|
|
154
|
+
if (!_oauthConfig)
|
|
155
|
+
throw new Error('No OAuth config — cannot call the PDS');
|
|
156
|
+
if (!viewer)
|
|
157
|
+
throw new Error('Authentication required to call the PDS');
|
|
158
|
+
return pdsXrpc(_oauthConfig, viewer, nsid, options);
|
|
159
|
+
},
|
|
153
160
|
};
|
|
154
161
|
}
|
|
155
162
|
const handlers = new Map();
|