Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@atproto/xrpc

Package Overview
Dependencies
Maintainers
4
Versions
23
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@atproto/xrpc - npm Package Compare versions

Comparing version 0.6.0 to 0.6.1

190

CHANGELOG.md
# @atproto/xrpc
## 0.6.1
### Patch Changes
- [#2714](https://github.com/bluesky-social/atproto/pull/2714) [`d9ffa3c46`](https://github.com/bluesky-social/atproto/commit/d9ffa3c460924010d7002b616cb7a0c66111cc6c) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Improve handling of fetchHandler errors when turning them into `XrpcError`.
- [#2714](https://github.com/bluesky-social/atproto/pull/2714) [`d9ffa3c46`](https://github.com/bluesky-social/atproto/commit/d9ffa3c460924010d7002b616cb7a0c66111cc6c) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add ability to instantiate XrpcClient from FetchHandlerObject type
- [#2714](https://github.com/bluesky-social/atproto/pull/2714) [`d9ffa3c46`](https://github.com/bluesky-social/atproto/commit/d9ffa3c460924010d7002b616cb7a0c66111cc6c) Thanks [@matthieusieben](https://github.com/matthieusieben)! - Add global headers to `XrpcClient` instances
## 0.6.0

@@ -45,3 +55,3 @@

```ts
import { Agent, AtpAgent } from '@atproto/api'
import { Agent, AtpAgent } from "@atproto/api";

@@ -58,7 +68,7 @@ async function setupAgent(

},
})
});
await agent.login(username, password)
await agent.login(username, password);
return agent
return agent;
}

@@ -68,6 +78,6 @@ ```

```ts
import { Agent } from '@atproto/api'
import { Agent } from "@atproto/api";
async function doStuffWithAgent(agent: Agent, arg: string) {
return agent.resolveHandle(arg)
return agent.resolveHandle(arg);
}

@@ -77,9 +87,9 @@ ```

```ts
import { Agent, AtpAgent } from '@atproto/api'
import { Agent, AtpAgent } from "@atproto/api";
class MyClass {
agent: Agent
agent: Agent;
constructor() {
this.agent = new AtpAgent()
this.agent = new AtpAgent();
}

@@ -162,9 +172,9 @@ }

```ts
import { AtpBaseClient, ComAtprotoSyncSubscribeRepos } from '@atproto/api'
import { AtpBaseClient, ComAtprotoSyncSubscribeRepos } from "@atproto/api";
const baseClient = new AtpBaseClient()
const baseClient = new AtpBaseClient();
baseClient.xrpc.lex.assertValidXrpcMessage('io.example.doStuff', {
baseClient.xrpc.lex.assertValidXrpcMessage("io.example.doStuff", {
// ...
})
});
```

@@ -176,7 +186,7 @@

```ts
import { lexicons } from '@atproto/api'
import { lexicons } from "@atproto/api";
lexicons.assertValidXrpcMessage('io.example.doStuff', {
lexicons.assertValidXrpcMessage("io.example.doStuff", {
// ...
})
});
```

@@ -198,6 +208,6 @@

```ts
import { BskyAgent } from '@atproto/api'
import { BskyAgent } from "@atproto/api";
class MyAgent extends BskyAgent {
private accessToken?: string
private accessToken?: string;

@@ -207,11 +217,11 @@ async createOrRefreshSession(identifier: string, password: string) {

this.accessToken = 'my-access-jwt'
this.accessToken = "my-access-jwt";
}
async doStuff() {
return this.call('io.example.doStuff', {
return this.call("io.example.doStuff", {
headers: {
Authorization: this.accessToken && `Bearer ${this.accessToken}`,
},
})
});
}

@@ -225,7 +235,7 @@ }

```ts
import { Agent } from '@atproto/api'
import { Agent } from "@atproto/api";
class MyAgent extends Agent {
private accessToken?: string
public did?: string
private accessToken?: string;
public did?: string;

@@ -239,10 +249,10 @@ constructor(private readonly service: string | URL) {

},
})
});
}
clone(): MyAgent {
const agent = new MyAgent(this.service)
agent.accessToken = this.accessToken
agent.did = this.did
return this.copyInto(agent)
const agent = new MyAgent(this.service);
agent.accessToken = this.accessToken;
agent.did = this.did;
return this.copyInto(agent);
}

@@ -253,4 +263,4 @@

this.did = 'did:example:123'
this.accessToken = 'my-access-jwt'
this.did = "did:example:123";
this.accessToken = "my-access-jwt";
}

@@ -274,13 +284,13 @@ }

```ts
import { BskyAgent } from '@atproto/api'
import { RateLimitThreshold } from 'rate-limit-threshold'
import { BskyAgent } from "@atproto/api";
import { RateLimitThreshold } from "rate-limit-threshold";
const agent = new BskyAgent()
const limiter = new RateLimitThreshold(3000, 300_000)
const agent = new BskyAgent();
const limiter = new RateLimitThreshold(3000, 300_000);
const origCall = agent.api.xrpc.call
const origCall = agent.api.xrpc.call;
agent.api.xrpc.call = async function (...args) {
await limiter.wait()
return origCall.call(this, ...args)
}
await limiter.wait();
return origCall.call(this, ...args);
};
```

@@ -292,9 +302,9 @@

```ts
import { AtpAgent } from '@atproto/api'
import { RateLimitThreshold } from 'rate-limit-threshold'
import { AtpAgent } from "@atproto/api";
import { RateLimitThreshold } from "rate-limit-threshold";
class LimitedAtpAgent extends AtpAgent {
constructor(options: AtpAgentOptions) {
const fetch: typeof globalThis.fetch = options.fetch ?? globalThis.fetch
const limiter = new RateLimitThreshold(3000, 300_000)
const fetch: typeof globalThis.fetch = options.fetch ?? globalThis.fetch;
const limiter = new RateLimitThreshold(3000, 300_000);

@@ -304,6 +314,6 @@ super({

fetch: async (...args) => {
await limiter.wait()
return fetch(...args)
await limiter.wait();
return fetch(...args);
},
})
});
}

@@ -329,13 +339,13 @@ }

```ts
import { BskyAgent, defaultFetchHandler } from '@atproto/api'
import { BskyAgent, defaultFetchHandler } from "@atproto/api";
BskyAgent.configure({
fetch: async (httpUri, httpMethod, httpHeaders, httpReqBody) => {
const ua = httpHeaders['User-Agent']
const ua = httpHeaders["User-Agent"];
httpHeaders['User-Agent'] = ua ? `${ua} ${userAgent}` : userAgent
httpHeaders["User-Agent"] = ua ? `${ua} ${userAgent}` : userAgent;
return defaultFetchHandler(httpUri, httpMethod, httpHeaders, httpReqBody)
return defaultFetchHandler(httpUri, httpMethod, httpHeaders, httpReqBody);
},
})
});
```

@@ -347,7 +357,7 @@

```ts
import { AtpAgent } from '@atproto/api'
import { AtpAgent } from "@atproto/api";
class MyAtpAgent extends AtpAgent {
constructor(options: AtpAgentOptions) {
const fetch = options.fetch ?? globalThis.fetch
const fetch = options.fetch ?? globalThis.fetch;

@@ -357,10 +367,10 @@ super({

fetch: async (url, init) => {
const headers = new Headers(init.headers)
const headers = new Headers(init.headers);
const ua = headersList.get('User-Agent')
headersList.set('User-Agent', ua ? `${ua} ${userAgent}` : userAgent)
const ua = headersList.get("User-Agent");
headersList.set("User-Agent", ua ? `${ua} ${userAgent}` : userAgent);
return fetch(url, { ...init, headers })
return fetch(url, { ...init, headers });
},
})
});
}

@@ -424,3 +434,3 @@ }

init: RequestInit,
) => Promise<Response>
) => Promise<Response>;
```

@@ -463,3 +473,3 @@

```ts
import client, { defaultFetchHandler } from '@atproto/xrpc'
import client, { defaultFetchHandler } from "@atproto/xrpc";

@@ -473,16 +483,16 @@ client.fetch = function (

// Custom logic here
return defaultFetchHandler(httpUri, httpMethod, httpHeaders, httpReqBody)
}
return defaultFetchHandler(httpUri, httpMethod, httpHeaders, httpReqBody);
};
client.addLexicon({
lexicon: 1,
id: 'io.example.doStuff',
id: "io.example.doStuff",
defs: {},
})
});
const instance = client.service('http://my-service.com')
const instance = client.service("http://my-service.com");
instance.setHeader('my-header', 'my-value')
instance.setHeader("my-header", "my-value");
await instance.call('io.example.doStuff')
await instance.call("io.example.doStuff");
```

@@ -494,15 +504,15 @@

```ts
import { XrpcClient } from '@atproto/xrpc'
import { XrpcClient } from "@atproto/xrpc";
const instance = new XrpcClient(
async (url, init) => {
const headers = new Headers(init.headers)
const headers = new Headers(init.headers);
headers.set('my-header', 'my-value')
headers.set("my-header", "my-value");
// Custom logic here
const fullUrl = new URL(url, 'http://my-service.com')
const fullUrl = new URL(url, "http://my-service.com");
return fetch(fullUrl, { ...init, headers })
return fetch(fullUrl, { ...init, headers });
},

@@ -512,9 +522,9 @@ [

lexicon: 1,
id: 'io.example.doStuff',
id: "io.example.doStuff",
defs: {},
},
],
)
);
await instance.call('io.example.doStuff')
await instance.call("io.example.doStuff");
```

@@ -531,11 +541,11 @@

```ts
import { XrpcClient } from '@atproto/xrpc'
import { XrpcClient } from "@atproto/xrpc";
const instance = new XrpcClient('http://my-service.com', [
const instance = new XrpcClient("http://my-service.com", [
{
lexicon: 1,
id: 'io.example.doStuff',
id: "io.example.doStuff",
defs: {},
},
])
]);
```

@@ -547,9 +557,9 @@

```ts
import { XrpcClient } from '@atproto/xrpc'
import { XrpcClient } from "@atproto/xrpc";
const instance = new XrpcClient(
{
service: 'http://my-service.com',
service: "http://my-service.com",
headers: {
'my-header': 'my-value',
"my-header": "my-value",
},

@@ -560,7 +570,7 @@ },

lexicon: 1,
id: 'io.example.doStuff',
id: "io.example.doStuff",
defs: {},
},
],
)
);
```

@@ -572,10 +582,10 @@

```ts
import { XrpcClient } from '@atproto/xrpc'
import { XrpcClient } from "@atproto/xrpc";
const instance = new XrpcClient(
{
service: () => 'http://my-service.com',
service: () => "http://my-service.com",
headers: {
'my-header': () => 'my-value',
'my-ignored-header': () => null, // ignored
"my-header": () => "my-value",
"my-ignored-header": () => null, // ignored
},

@@ -586,7 +596,7 @@ },

lexicon: 1,
id: 'io.example.doStuff',
id: "io.example.doStuff",
defs: {},
},
],
)
);
```

@@ -593,0 +603,0 @@

@@ -21,7 +21,4 @@ import { LexiconDoc, Lexicons } from '@atproto/lexicon';

uri: URL;
headers: Record<string, string>;
constructor(baseClient: Client, serviceUri: string | URL);
setHeader(key: string, value: string): void;
unsetHeader(key: string): void;
}
//# sourceMappingURL=client.d.ts.map

@@ -67,18 +67,6 @@ "use strict";

});
Object.defineProperty(this, "headers", {
enumerable: true,
configurable: true,
writable: true,
value: {}
});
this.uri = typeof serviceUri === 'string' ? new URL(serviceUri) : serviceUri;
}
setHeader(key, value) {
this.headers[key] = value;
}
unsetHeader(key) {
delete this.headers[key];
}
}
exports.ServiceClient = ServiceClient;
//# sourceMappingURL=client.js.map

@@ -32,3 +32,12 @@ import { Gettable } from './types';

};
export declare function buildFetchHandler(options: FetchHandler | FetchHandlerOptions): FetchHandler;
export interface FetchHandlerObject {
fetchHandler: (this: FetchHandlerObject,
/**
* The URL (pathname + query parameters) to make the request to, without the
* origin. The origin (protocol, hostname, and port) must be added by this
* {@link FetchHandler}, typically based on authentication or other factors.
*/
url: string, init: RequestInit) => Promise<Response>;
}
export declare function buildFetchHandler(options: FetchHandler | FetchHandlerObject | FetchHandlerOptions): FetchHandler;
//# sourceMappingURL=fetch-handler.d.ts.map

@@ -9,2 +9,5 @@ "use strict";

return options;
if (typeof options === 'object' && 'fetchHandler' in options) {
return options.fetchHandler.bind(options);
}
const { service, headers: defaultHeaders = undefined, fetch = globalThis.fetch, } = typeof options === 'string' || options instanceof URL

@@ -11,0 +14,0 @@ ? { service: options }

@@ -5,4 +5,5 @@ import { z } from 'zod';

export type HeadersMap = Record<string, string>;
export type {
/** @deprecated not to be confused with the WHATWG Headers constructor */
export type Headers = HeadersMap;
HeadersMap as Headers, };
export type Gettable<T> = T | (() => T);

@@ -78,5 +79,5 @@ export interface CallOptions {

data: any;
headers: Headers;
headers: HeadersMap;
success: boolean;
constructor(data: any, headers: Headers);
constructor(data: any, headers: HeadersMap);
}

@@ -83,0 +84,0 @@ export declare class XRPCError extends Error {

@@ -148,13 +148,25 @@ "use strict";

}
// Type cast the cause to an Error if it is one
const causeErr = cause instanceof Error ? cause : undefined;
// Try and find a Response object in the cause
const causeResponse = cause instanceof Response
? cause
: cause?.['response'] instanceof Response
? cause['response']
: undefined;
const statusCode =
// Extract status code from "http-errors" like errors
const statusCode = cause instanceof Error
? ('statusCode' in cause ? cause.statusCode : undefined) ??
('status' in cause ? cause.status : undefined)
: undefined;
causeErr?.['statusCode'] ??
causeErr?.['status'] ??
// Use the status code from the response object as fallback
causeResponse?.status;
// Convert the status code to a ResponseType
const status = typeof statusCode === 'number'
? httpResponseCodeToEnum(statusCode)
: fallbackStatus ?? ResponseType.Unknown;
const error = exports.ResponseTypeNames[status];
const message = cause instanceof Error ? cause.message : String(cause);
return new XRPCError(status, error, message, undefined, { cause });
const message = causeErr?.message ?? String(cause);
const headers = causeResponse
? Object.fromEntries(causeResponse.headers.entries())
: undefined;
return new XRPCError(status, undefined, message, headers, { cause });
}

@@ -161,0 +173,0 @@ }

import { LexiconDoc, Lexicons } from '@atproto/lexicon';
import { FetchHandler, FetchHandlerOptions } from './fetch-handler';
import { CallOptions, QueryParams, XRPCResponse } from './types';
import { FetchHandler, FetchHandlerObject, FetchHandlerOptions } from './fetch-handler';
import { CallOptions, Gettable, QueryParams, XRPCResponse } from './types';
export declare class XrpcClient {
readonly fetchHandler: FetchHandler;
readonly headers: Map<string, Gettable<string | null>>;
readonly lex: Lexicons;
constructor(fetchHandlerOpts: FetchHandler | FetchHandlerOptions, lex: Lexicons | Iterable<LexiconDoc>);
constructor(fetchHandlerOpts: FetchHandler | FetchHandlerObject | FetchHandlerOptions, lex: Lexicons | Iterable<LexiconDoc>);
setHeader(key: string, value: Gettable<null | string>): void;
unsetHeader(key: string): void;
clearHeaders(): void;
call(methodNsid: string, params?: QueryParams, data?: unknown, opts?: CallOptions): Promise<XRPCResponse>;
}
//# sourceMappingURL=xrpc-client.d.ts.map

@@ -19,2 +19,8 @@ "use strict";

});
Object.defineProperty(this, "headers", {
enumerable: true,
configurable: true,
writable: true,
value: new Map()
});
Object.defineProperty(this, "lex", {

@@ -29,2 +35,11 @@ enumerable: true,

}
setHeader(key, value) {
this.headers.set(key.toLowerCase(), value);
}
unsetHeader(key) {
this.headers.delete(key.toLowerCase());
}
clearHeaders() {
this.headers.clear();
}
async call(methodNsid, params, data, opts) {

@@ -48,3 +63,3 @@ const def = this.lex.getDefOrThrow(methodNsid);

method: reqMethod,
headers: reqHeaders,
headers: (0, util_1.combineHeaders)(reqHeaders, this.headers),
body: reqBody,

@@ -51,0 +66,0 @@ duplex: 'half',

{
"name": "@atproto/xrpc",
"version": "0.6.0",
"version": "0.6.1",
"license": "MIT",

@@ -5,0 +5,0 @@ "description": "atproto HTTP API (XRPC) client library",

@@ -62,3 +62,2 @@ import { LexiconDoc, Lexicons } from '@atproto/lexicon'

uri: URL
headers: Record<string, string> = {}

@@ -75,10 +74,2 @@ constructor(

}
setHeader(key: string, value: string): void {
this.headers[key] = value
}
unsetHeader(key: string): void {
delete this.headers[key]
}
}

@@ -42,7 +42,23 @@ import { Gettable } from './types'

export interface FetchHandlerObject {
fetchHandler: (
this: FetchHandlerObject,
/**
* The URL (pathname + query parameters) to make the request to, without the
* origin. The origin (protocol, hostname, and port) must be added by this
* {@link FetchHandler}, typically based on authentication or other factors.
*/
url: string,
init: RequestInit,
) => Promise<Response>
}
export function buildFetchHandler(
options: FetchHandler | FetchHandlerOptions,
options: FetchHandler | FetchHandlerObject | FetchHandlerOptions,
): FetchHandler {
// Already a fetch handler (allowed for convenience)
if (typeof options === 'function') return options
if (typeof options === 'object' && 'fetchHandler' in options) {
return options.fetchHandler.bind(options)
}

@@ -49,0 +65,0 @@ const {

@@ -7,4 +7,6 @@ import { z } from 'zod'

/** @deprecated not to be confused with the WHATWG Headers constructor */
export type Headers = HeadersMap
export type {
/** @deprecated not to be confused with the WHATWG Headers constructor */
HeadersMap as Headers,
}

@@ -105,3 +107,3 @@ export type Gettable<T> = T | (() => T)

public data: any,
public headers: Headers,
public headers: HeadersMap,
) {}

@@ -119,3 +121,3 @@ }

message?: string,
public headers?: Headers,
public headers?: HeadersMap,
options?: ErrorOptions,

@@ -139,9 +141,21 @@ ) {

// Extract status code from "http-errors" like errors
// Type cast the cause to an Error if it is one
const causeErr = cause instanceof Error ? cause : undefined
// Try and find a Response object in the cause
const causeResponse: Response | undefined =
cause instanceof Response
? cause
: cause?.['response'] instanceof Response
? cause['response']
: undefined
const statusCode: unknown =
cause instanceof Error
? ('statusCode' in cause ? cause.statusCode : undefined) ??
('status' in cause ? cause.status : undefined)
: undefined
// Extract status code from "http-errors" like errors
causeErr?.['statusCode'] ??
causeErr?.['status'] ??
// Use the status code from the response object as fallback
causeResponse?.status
// Convert the status code to a ResponseType
const status: ResponseType =

@@ -152,6 +166,9 @@ typeof statusCode === 'number'

const error = ResponseTypeNames[status]
const message = cause instanceof Error ? cause.message : String(cause)
const message = causeErr?.message ?? String(cause)
return new XRPCError(status, error, message, undefined, { cause })
const headers = causeResponse
? Object.fromEntries(causeResponse.headers.entries())
: undefined
return new XRPCError(status, undefined, message, headers, { cause })
}

@@ -158,0 +175,0 @@ }

import { LexiconDoc, Lexicons, ValidationError } from '@atproto/lexicon'
import {
FetchHandler,
FetchHandlerObject,
FetchHandlerOptions,

@@ -9,2 +10,3 @@ buildFetchHandler,

CallOptions,
Gettable,
QueryParams,

@@ -18,2 +20,3 @@ ResponseType,

import {
combineHeaders,
constructMethodCallHeaders,

@@ -29,6 +32,7 @@ constructMethodCallUrl,

readonly fetchHandler: FetchHandler
readonly headers = new Map<string, Gettable<null | string>>()
readonly lex: Lexicons
constructor(
fetchHandlerOpts: FetchHandler | FetchHandlerOptions,
fetchHandlerOpts: FetchHandler | FetchHandlerObject | FetchHandlerOptions,
// "Lexicons" is redundant here (because that class implements

@@ -43,2 +47,14 @@ // "Iterable<LexiconDoc>") but we keep it for explicitness:

setHeader(key: string, value: Gettable<null | string>): void {
this.headers.set(key.toLowerCase(), value)
}
unsetHeader(key: string): void {
this.headers.delete(key.toLowerCase())
}
clearHeaders(): void {
this.headers.clear()
}
async call(

@@ -72,3 +88,3 @@ methodNsid: string,

method: reqMethod,
headers: reqHeaders,
headers: combineHeaders(reqHeaders, this.headers),
body: reqBody,

@@ -75,0 +91,0 @@ duplex: 'half',

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc