Matthieu Sieben b934b396b1
Client SDK rework (#2483)
* feat(api): support creation of oauth based AtpAgents

* oauth: misc fixes for confidential clients

* fix(xprc): remove ReadableStream.from polyfill

* OAuth docs tweaks (#2679)

* OAuth: clarification about client_name being shown

* OAuth: re-write handle resolution privacy concern

* avoid relying on ReadableStream.from in xrpc-server tests

* feat(oauth-types): expose "ALLOW_UNSECURE_ORIGINS" constant

* feat(handle-resolver): expose "AtprotoIdentityDidMethods" type

* fix(oauth-client): ensure that the oauth metadata document contains client_id_metadata_document_supported

* fix(oauth-types): prevent unknown query string in loopback client id

* fix(identity-resolver): check that handle is in did doc's "alsoKnownAs"

* feat(oauth-client:oauth-resolver): allow logging in using either the PDS URL or Entryway URL

* fix(oauth-client): return better error in case of invalid "oauth-protected-resource" status code

* refactor(did): group atproto specific checks in own

* feat(api): relax typing of "appLabelers" and "labelers" AtpClient properties

* allow any did as labeller (for tests mainly)

* fix(api): allow to override "atproto-proxy" on a per-request basis

* remove release candidate versions from changelog

* update changeset for api and xrpc packages

* Add missing changeset

* revert RC versions

* Proper wording in OAUTH.md api example

* remove "pre" changeset file

* xrpc: restore original behavior of setHEader and unsetHeader

* docs: add comment for XrpcClient 's constructor arg

* feat(api): expose "schemas" publicly

* feat(api): allow customizing the whatwg fetch function of the AtpAgent

* docs(api): improve migration docs

* docs: change reference to BskyAgent to AtpAgent

* docs: mention the breaking change regarding setSessionPersistHandler

* fix(api): better split AtpClient concerns

* fix(xrpc): remove unused import

* refactor(api): simplify class hierarchu by removeing AtpClient

* fix(api): mock proper method for facets detection

* restore ability to restore session asynchronously

* feat(api): allow instantiating Agent with same argument as super class

* docs(api): properly extend Agent class

* style(xrpc): var name

* docs(api): remove "async" to header getter

---------

Co-authored-by: Devin Ivy <devinivy@gmail.com>
Co-authored-by: bnewbold <bnewbold@robocracy.org>
Co-authored-by: Hailey <me@haileyok.com>
2024-08-12 19:57:21 +02:00

3.0 KiB

@atproto/xrpc: atproto HTTP API Client

TypeScript client library for talking to atproto services, with Lexicon schema validation.

NPM Github CI Status

Usage

import { LexiconDoc } from '@atproto/lexicon'
import { XrpcClient } from '@atproto/xrpc'

const pingLexicon = {
  lexicon: 1,
  id: 'io.example.ping',
  defs: {
    main: {
      type: 'query',
      description: 'Ping the server',
      parameters: {
        type: 'params',
        properties: { message: { type: 'string' } },
      },
      output: {
        encoding: 'application/json',
        schema: {
          type: 'object',
          required: ['message'],
          properties: { message: { type: 'string' } },
        },
      },
    },
  },
} satisfies LexiconDoc

const xrpc = new XrpcClient('https://ping.example.com', [
  // Any number of lexicon here
  pingLexicon,
])

const res1 = await xrpc.call('io.example.ping', {
  message: 'hello world',
})
res1.encoding // => 'application/json'
res1.body // => {message: 'hello world'}

With a custom fetch handler

import { XrpcClient } from '@atproto/xrpc'

const session = {
  serviceUrl: 'https://ping.example.com',
  token: '<my-token>',
  async refreshToken() {
    const { token } = await fetch('https://auth.example.com/refresh', {
      method: 'POST',
      headers: { Authorization: `Bearer ${this.token}` },
    }).then((res) => res.json())

    this.token = token

    return token
  },
}

const sessionBasedFetch: FetchHandler = async (
  url: string,
  init: RequestInit,
) => {
  const headers = new Headers(init.headers)

  headers.set('Authorization', `Bearer ${session.token}`)

  const response = await fetch(new URL(url, session.serviceUrl), {
    ...init,
    headers,
  })

  if (response.status === 401) {
    // Refresh token, then try again.
    const newToken = await session.refreshToken()
    headers.set('Authorization', `Bearer ${newToken}`)
    return fetch(new URL(url, session.serviceUrl), { ...init, headers })
  }

  return response
}

const xrpc = new XrpcClient(sessionBasedFetch, [
  // Any number of lexicon here
  pingLexicon,
])

//

License

This project is dual-licensed under MIT and Apache 2.0 terms:

Downstream projects and end users may chose either license individually, or both together, at their discretion. The motivation for this dual-licensing is the additional software patent assurance provided by Apache 2.0.