Upgrade API, implement XRPC rework (#4857)
Co-authored-by: Matthieu Sieben <matthieu.sieben@gmail.com>zio/stable
parent
ae883e2df7
commit
7df2327424
9
index.js
9
index.js
|
@ -1,14 +1,11 @@
|
|||
import 'react-native-gesture-handler' // must be first
|
||||
import {LogBox} from 'react-native'
|
||||
|
||||
import '#/platform/polyfills'
|
||||
import {IS_TEST} from '#/env'
|
||||
|
||||
import {LogBox} from 'react-native'
|
||||
import {registerRootComponent} from 'expo'
|
||||
import {doPolyfill} from '#/lib/api/api-polyfill'
|
||||
|
||||
import App from '#/App'
|
||||
|
||||
doPolyfill()
|
||||
import {IS_TEST} from '#/env'
|
||||
|
||||
if (IS_TEST) {
|
||||
LogBox.ignoreAllLogs() // suppress all logs in tests
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
import '#/platform/markBundleStartTime'
|
||||
|
||||
import '#/platform/polyfills'
|
||||
|
||||
import {registerRootComponent} from 'expo'
|
||||
import {doPolyfill} from '#/lib/api/api-polyfill'
|
||||
|
||||
import App from '#/App'
|
||||
|
||||
doPolyfill()
|
||||
registerRootComponent(App)
|
||||
|
|
|
@ -156,7 +156,7 @@ class Mocker {
|
|||
}
|
||||
|
||||
async createUser(name: string) {
|
||||
const agent = new BskyAgent({service: this.agent.service})
|
||||
const agent = new BskyAgent({service: this.service})
|
||||
|
||||
const inviteRes = await agent.api.com.atproto.server.createInviteCode(
|
||||
{useCount: 1},
|
||||
|
@ -332,7 +332,7 @@ class Mocker {
|
|||
}
|
||||
|
||||
async createInvite(forAccount: string) {
|
||||
const agent = new BskyAgent({service: this.agent.service})
|
||||
const agent = new BskyAgent({service: this.service})
|
||||
await agent.api.com.atproto.server.createInviteCode(
|
||||
{useCount: 1, forAccount},
|
||||
{
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
"open-analyzer": "EXPO_PUBLIC_OPEN_ANALYZER=1 yarn build-web"
|
||||
},
|
||||
"dependencies": {
|
||||
"@atproto/api": "0.12.29",
|
||||
"@atproto/api": "0.13.0",
|
||||
"@bam.tech/react-native-image-resizer": "^3.0.4",
|
||||
"@braintree/sanitize-url": "^6.0.2",
|
||||
"@discord/bottom-sheet": "bluesky-social/react-native-bottom-sheet",
|
||||
|
@ -208,7 +208,7 @@
|
|||
"zod": "^3.20.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@atproto/dev-env": "^0.3.5",
|
||||
"@atproto/dev-env": "^0.3.39",
|
||||
"@babel/core": "^7.23.2",
|
||||
"@babel/preset-env": "^7.20.0",
|
||||
"@babel/runtime": "^7.20.0",
|
||||
|
|
|
@ -1,28 +0,0 @@
|
|||
diff --git a/node_modules/@atproto/lexicon/dist/validators/complex.js b/node_modules/@atproto/lexicon/dist/validators/complex.js
|
||||
index 32d7798..9d688b7 100644
|
||||
--- a/node_modules/@atproto/lexicon/dist/validators/complex.js
|
||||
+++ b/node_modules/@atproto/lexicon/dist/validators/complex.js
|
||||
@@ -113,7 +113,22 @@ function object(lexicons, path, def, value) {
|
||||
if (value[key] === null && nullableProps.has(key)) {
|
||||
continue;
|
||||
}
|
||||
- const propDef = def.properties[key];
|
||||
+ const propDef = def.properties[key]
|
||||
+ if (typeof value[key] === 'undefined' && !requiredProps.has(key)) {
|
||||
+ // Fast path for non-required undefined props.
|
||||
+ if (
|
||||
+ propDef.type === 'integer' ||
|
||||
+ propDef.type === 'boolean' ||
|
||||
+ propDef.type === 'string'
|
||||
+ ) {
|
||||
+ if (typeof propDef.default === 'undefined') {
|
||||
+ continue
|
||||
+ }
|
||||
+ } else {
|
||||
+ // Other types have no defaults.
|
||||
+ continue
|
||||
+ }
|
||||
+ }
|
||||
const propPath = `${path}/${key}`;
|
||||
const validated = (0, util_1.validateOneOf)(lexicons, propPath, propDef, value[key]);
|
||||
const propValue = validated.success ? validated.value : value[key];
|
|
@ -1,85 +0,0 @@
|
|||
import RNFS from 'react-native-fs'
|
||||
import {BskyAgent, jsonToLex, stringifyLex} from '@atproto/api'
|
||||
|
||||
const GET_TIMEOUT = 15e3 // 15s
|
||||
const POST_TIMEOUT = 60e3 // 60s
|
||||
|
||||
export function doPolyfill() {
|
||||
BskyAgent.configure({fetch: fetchHandler})
|
||||
}
|
||||
|
||||
interface FetchHandlerResponse {
|
||||
status: number
|
||||
headers: Record<string, string>
|
||||
body: any
|
||||
}
|
||||
|
||||
async function fetchHandler(
|
||||
reqUri: string,
|
||||
reqMethod: string,
|
||||
reqHeaders: Record<string, string>,
|
||||
reqBody: any,
|
||||
): Promise<FetchHandlerResponse> {
|
||||
const reqMimeType = reqHeaders['Content-Type'] || reqHeaders['content-type']
|
||||
if (reqMimeType && reqMimeType.startsWith('application/json')) {
|
||||
reqBody = stringifyLex(reqBody)
|
||||
} else if (
|
||||
typeof reqBody === 'string' &&
|
||||
(reqBody.startsWith('/') || reqBody.startsWith('file:'))
|
||||
) {
|
||||
if (reqBody.endsWith('.jpeg') || reqBody.endsWith('.jpg')) {
|
||||
// HACK
|
||||
// React native has a bug that inflates the size of jpegs on upload
|
||||
// we get around that by renaming the file ext to .bin
|
||||
// see https://github.com/facebook/react-native/issues/27099
|
||||
// -prf
|
||||
const newPath = reqBody.replace(/\.jpe?g$/, '.bin')
|
||||
await RNFS.moveFile(reqBody, newPath)
|
||||
reqBody = newPath
|
||||
}
|
||||
// NOTE
|
||||
// React native treats bodies with {uri: string} as file uploads to pull from cache
|
||||
// -prf
|
||||
reqBody = {uri: reqBody}
|
||||
}
|
||||
|
||||
const controller = new AbortController()
|
||||
const to = setTimeout(
|
||||
() => controller.abort(),
|
||||
reqMethod === 'post' ? POST_TIMEOUT : GET_TIMEOUT,
|
||||
)
|
||||
|
||||
const res = await fetch(reqUri, {
|
||||
method: reqMethod,
|
||||
headers: reqHeaders,
|
||||
body: reqBody,
|
||||
signal: controller.signal,
|
||||
})
|
||||
|
||||
const resStatus = res.status
|
||||
const resHeaders: Record<string, string> = {}
|
||||
res.headers.forEach((value: string, key: string) => {
|
||||
resHeaders[key] = value
|
||||
})
|
||||
const resMimeType = resHeaders['Content-Type'] || resHeaders['content-type']
|
||||
let resBody
|
||||
if (resMimeType) {
|
||||
if (resMimeType.startsWith('application/json')) {
|
||||
resBody = jsonToLex(await res.json())
|
||||
} else if (resMimeType.startsWith('text/')) {
|
||||
resBody = await res.text()
|
||||
} else if (resMimeType === 'application/vnd.ipld.car') {
|
||||
resBody = await res.arrayBuffer()
|
||||
} else {
|
||||
throw new Error('Non-supported mime type')
|
||||
}
|
||||
}
|
||||
|
||||
clearTimeout(to)
|
||||
|
||||
return {
|
||||
status: resStatus,
|
||||
headers: resHeaders,
|
||||
body: resBody,
|
||||
}
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export function doPolyfill() {
|
||||
// no polyfill is needed on web
|
||||
}
|
|
@ -1,7 +1,6 @@
|
|||
import {
|
||||
AppBskyFeedDefs,
|
||||
AppBskyFeedGetFeed as GetCustomFeed,
|
||||
AtpAgent,
|
||||
BskyAgent,
|
||||
} from '@atproto/api'
|
||||
|
||||
|
@ -51,7 +50,7 @@ export class CustomFeedAPI implements FeedAPI {
|
|||
const agent = this.agent
|
||||
const isBlueskyOwned = isBlueskyOwnedFeed(this.params.feed)
|
||||
|
||||
const res = agent.session
|
||||
const res = agent.did
|
||||
? await this.agent.app.bsky.feed.getFeed(
|
||||
{
|
||||
...this.params,
|
||||
|
@ -106,34 +105,32 @@ async function loggedOutFetch({
|
|||
let contentLangs = getContentLanguages().join(',')
|
||||
|
||||
// manually construct fetch call so we can add the `lang` cache-busting param
|
||||
let res = await AtpAgent.fetch!(
|
||||
let res = await fetch(
|
||||
`https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
|
||||
cursor ? `&cursor=${cursor}` : ''
|
||||
}&limit=${limit}&lang=${contentLangs}`,
|
||||
'GET',
|
||||
{'Accept-Language': contentLangs},
|
||||
undefined,
|
||||
{method: 'GET', headers: {'Accept-Language': contentLangs}},
|
||||
)
|
||||
if (res.body?.feed?.length) {
|
||||
let data = res.ok ? await res.json() : null
|
||||
if (data?.feed?.length) {
|
||||
return {
|
||||
success: true,
|
||||
data: res.body,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
// no data, try again with language headers removed
|
||||
res = await AtpAgent.fetch!(
|
||||
res = await fetch(
|
||||
`https://api.bsky.app/xrpc/app.bsky.feed.getFeed?feed=${feed}${
|
||||
cursor ? `&cursor=${cursor}` : ''
|
||||
}&limit=${limit}`,
|
||||
'GET',
|
||||
{'Accept-Language': ''},
|
||||
undefined,
|
||||
{method: 'GET', headers: {'Accept-Language': ''}},
|
||||
)
|
||||
if (res.body?.feed?.length) {
|
||||
data = res.ok ? await res.json() : null
|
||||
if (data?.feed?.length) {
|
||||
return {
|
||||
success: true,
|
||||
data: res.body,
|
||||
data,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ import {
|
|||
AppBskyFeedThreadgate,
|
||||
BskyAgent,
|
||||
ComAtprotoLabelDefs,
|
||||
ComAtprotoRepoUploadBlob,
|
||||
RichText,
|
||||
} from '@atproto/api'
|
||||
import {AtUri} from '@atproto/api'
|
||||
|
@ -15,10 +14,13 @@ import {logger} from '#/logger'
|
|||
import {ThreadgateSetting} from '#/state/queries/threadgate'
|
||||
import {isNetworkError} from 'lib/strings/errors'
|
||||
import {shortenLinks, stripInvalidMentions} from 'lib/strings/rich-text-manip'
|
||||
import {isNative, isWeb} from 'platform/detection'
|
||||
import {isNative} from 'platform/detection'
|
||||
import {ImageModel} from 'state/models/media/image'
|
||||
import {LinkMeta} from '../link-meta/link-meta'
|
||||
import {safeDeleteAsync} from '../media/manip'
|
||||
import {uploadBlob} from './upload-blob'
|
||||
|
||||
export {uploadBlob}
|
||||
|
||||
export interface ExternalEmbedDraft {
|
||||
uri: string
|
||||
|
@ -28,25 +30,6 @@ export interface ExternalEmbedDraft {
|
|||
localThumb?: ImageModel
|
||||
}
|
||||
|
||||
export async function uploadBlob(
|
||||
agent: BskyAgent,
|
||||
blob: string,
|
||||
encoding: string,
|
||||
): Promise<ComAtprotoRepoUploadBlob.Response> {
|
||||
if (isWeb) {
|
||||
// `blob` should be a data uri
|
||||
return agent.uploadBlob(convertDataURIToUint8Array(blob), {
|
||||
encoding,
|
||||
})
|
||||
} else {
|
||||
// `blob` should be a path to a file in the local FS
|
||||
return agent.uploadBlob(
|
||||
blob, // this will be special-cased by the fetch monkeypatch in /src/state/lib/api.ts
|
||||
{encoding},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
interface PostOpts {
|
||||
rawText: string
|
||||
replyTo?: string
|
||||
|
@ -301,7 +284,7 @@ export async function createThreadgate(
|
|||
|
||||
const postUrip = new AtUri(postUri)
|
||||
await agent.api.com.atproto.repo.putRecord({
|
||||
repo: agent.session!.did,
|
||||
repo: agent.accountDid,
|
||||
collection: 'app.bsky.feed.threadgate',
|
||||
rkey: postUrip.rkey,
|
||||
record: {
|
||||
|
@ -312,15 +295,3 @@ export async function createThreadgate(
|
|||
},
|
||||
})
|
||||
}
|
||||
|
||||
// helpers
|
||||
// =
|
||||
|
||||
function convertDataURIToUint8Array(uri: string): Uint8Array {
|
||||
var raw = window.atob(uri.substring(uri.indexOf(';base64,') + 8))
|
||||
var binary = new Uint8Array(new ArrayBuffer(raw.length))
|
||||
for (let i = 0; i < raw.length; i++) {
|
||||
binary[i] = raw.charCodeAt(i)
|
||||
}
|
||||
return binary
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
import RNFS from 'react-native-fs'
|
||||
import {BskyAgent, ComAtprotoRepoUploadBlob} from '@atproto/api'
|
||||
|
||||
/**
|
||||
* @param encoding Allows overriding the blob's type
|
||||
*/
|
||||
export async function uploadBlob(
|
||||
agent: BskyAgent,
|
||||
input: string | Blob,
|
||||
encoding?: string,
|
||||
): Promise<ComAtprotoRepoUploadBlob.Response> {
|
||||
if (typeof input === 'string' && input.startsWith('file:')) {
|
||||
const blob = await asBlob(input)
|
||||
return agent.uploadBlob(blob, {encoding})
|
||||
}
|
||||
|
||||
if (typeof input === 'string' && input.startsWith('/')) {
|
||||
const blob = await asBlob(`file://${input}`)
|
||||
return agent.uploadBlob(blob, {encoding})
|
||||
}
|
||||
|
||||
if (typeof input === 'string' && input.startsWith('data:')) {
|
||||
const blob = await fetch(input).then(r => r.blob())
|
||||
return agent.uploadBlob(blob, {encoding})
|
||||
}
|
||||
|
||||
if (input instanceof Blob) {
|
||||
return agent.uploadBlob(input, {encoding})
|
||||
}
|
||||
|
||||
throw new TypeError(`Invalid uploadBlob input: ${typeof input}`)
|
||||
}
|
||||
|
||||
async function asBlob(uri: string): Promise<Blob> {
|
||||
return withSafeFile(uri, async safeUri => {
|
||||
// Note
|
||||
// Android does not support `fetch()` on `file://` URIs. for this reason, we
|
||||
// use XMLHttpRequest instead of simply calling:
|
||||
|
||||
// return fetch(safeUri.replace('file:///', 'file:/')).then(r => r.blob())
|
||||
|
||||
return await new Promise((resolve, reject) => {
|
||||
const xhr = new XMLHttpRequest()
|
||||
xhr.onload = () => resolve(xhr.response)
|
||||
xhr.onerror = () => reject(new Error('Failed to load blob'))
|
||||
xhr.responseType = 'blob'
|
||||
xhr.open('GET', safeUri, true)
|
||||
xhr.send(null)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// HACK
|
||||
// React native has a bug that inflates the size of jpegs on upload
|
||||
// we get around that by renaming the file ext to .bin
|
||||
// see https://github.com/facebook/react-native/issues/27099
|
||||
// -prf
|
||||
async function withSafeFile<T>(
|
||||
uri: string,
|
||||
fn: (path: string) => Promise<T>,
|
||||
): Promise<T> {
|
||||
if (uri.endsWith('.jpeg') || uri.endsWith('.jpg')) {
|
||||
// Since we don't "own" the file, we should avoid renaming or modifying it.
|
||||
// Instead, let's copy it to a temporary file and use that (then remove the
|
||||
// temporary file).
|
||||
const newPath = uri.replace(/\.jpe?g$/, '.bin')
|
||||
try {
|
||||
await RNFS.copyFile(uri, newPath)
|
||||
} catch {
|
||||
// Failed to copy the file, just use the original
|
||||
return await fn(uri)
|
||||
}
|
||||
try {
|
||||
return await fn(newPath)
|
||||
} finally {
|
||||
// Remove the temporary file
|
||||
await RNFS.unlink(newPath)
|
||||
}
|
||||
} else {
|
||||
return fn(uri)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
import {BskyAgent, ComAtprotoRepoUploadBlob} from '@atproto/api'
|
||||
|
||||
/**
|
||||
* @note It is recommended, on web, to use the `file` instance of the file
|
||||
* selector input element, rather than a `data:` URL, to avoid
|
||||
* loading the file into memory. `File` extends `Blob` "file" instances can
|
||||
* be passed directly to this function.
|
||||
*/
|
||||
export async function uploadBlob(
|
||||
agent: BskyAgent,
|
||||
input: string | Blob,
|
||||
encoding?: string,
|
||||
): Promise<ComAtprotoRepoUploadBlob.Response> {
|
||||
if (typeof input === 'string' && input.startsWith('data:')) {
|
||||
const blob = await fetch(input).then(r => r.blob())
|
||||
return agent.uploadBlob(blob, {encoding})
|
||||
}
|
||||
|
||||
if (input instanceof Blob) {
|
||||
return agent.uploadBlob(input, {
|
||||
encoding,
|
||||
})
|
||||
}
|
||||
|
||||
throw new TypeError(`Invalid uploadBlob input: ${typeof input}`)
|
||||
}
|
|
@ -218,13 +218,7 @@ export async function safeDeleteAsync(path: string) {
|
|||
// Normalize is necessary for Android, otherwise it doesn't delete.
|
||||
const normalizedPath = normalizePath(path)
|
||||
try {
|
||||
await Promise.allSettled([
|
||||
deleteAsync(normalizedPath, {idempotent: true}),
|
||||
// HACK: Try this one too. Might exist due to api-polyfill hack.
|
||||
deleteAsync(normalizedPath.replace(/\.jpe?g$/, '.bin'), {
|
||||
idempotent: true,
|
||||
}),
|
||||
])
|
||||
await deleteAsync(normalizedPath, {idempotent: true})
|
||||
} catch (e) {
|
||||
console.error('Failed to delete file', e)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export function SignupQueued() {
|
|||
const res = await agent.com.atproto.temp.checkSignupQueue()
|
||||
if (res.data.activated) {
|
||||
// ready to go, exchange the access token for a usable one and kick off onboarding
|
||||
await agent.refreshSession()
|
||||
await agent.sessionManager.refreshSession()
|
||||
if (!isSignupQueued(agent.session?.accessJwt)) {
|
||||
onboardingDispatch({type: 'start'})
|
||||
}
|
||||
|
|
|
@ -37,14 +37,14 @@ export function usePreferencesQuery() {
|
|||
refetchOnWindowFocus: true,
|
||||
queryKey: preferencesQueryKey,
|
||||
queryFn: async () => {
|
||||
if (agent.session?.did === undefined) {
|
||||
if (!agent.did) {
|
||||
return DEFAULT_LOGGED_OUT_PREFERENCES
|
||||
} else {
|
||||
const res = await agent.getPreferences()
|
||||
|
||||
// save to local storage to ensure there are labels on initial requests
|
||||
saveLabelers(
|
||||
agent.session.did,
|
||||
agent.did,
|
||||
res.moderationPrefs.labelers.map(l => l.did),
|
||||
)
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('session', () => {
|
|||
`)
|
||||
|
||||
const agent = new BskyAgent({service: 'https://alice.com'})
|
||||
agent.session = {
|
||||
agent.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -118,7 +118,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -166,7 +166,7 @@ describe('session', () => {
|
|||
`)
|
||||
|
||||
const agent2 = new BskyAgent({service: 'https://bob.com'})
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob.test',
|
||||
|
@ -230,7 +230,7 @@ describe('session', () => {
|
|||
`)
|
||||
|
||||
const agent3 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent3.session = {
|
||||
agent3.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -294,7 +294,7 @@ describe('session', () => {
|
|||
`)
|
||||
|
||||
const agent4 = new BskyAgent({service: 'https://jay.com'})
|
||||
agent4.session = {
|
||||
agent4.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'jay-did',
|
||||
handle: 'jay.test',
|
||||
|
@ -445,7 +445,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -502,7 +502,7 @@ describe('session', () => {
|
|||
`)
|
||||
|
||||
const agent2 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -553,7 +553,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -598,7 +598,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -606,7 +606,7 @@ describe('session', () => {
|
|||
refreshJwt: 'alice-refresh-jwt-1',
|
||||
}
|
||||
const agent2 = new BskyAgent({service: 'https://bob.com'})
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob.test',
|
||||
|
@ -678,7 +678,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -695,7 +695,7 @@ describe('session', () => {
|
|||
expect(state.accounts.length).toBe(1)
|
||||
expect(state.currentAgentState.did).toBe('alice-did')
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -748,7 +748,7 @@ describe('session', () => {
|
|||
}
|
||||
`)
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -801,7 +801,7 @@ describe('session', () => {
|
|||
}
|
||||
`)
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -859,7 +859,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -876,7 +876,7 @@ describe('session', () => {
|
|||
expect(state.accounts.length).toBe(1)
|
||||
expect(state.currentAgentState.did).toBe('alice-did')
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -907,7 +907,7 @@ describe('session', () => {
|
|||
])
|
||||
expect(lastState === state).toBe(true)
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -931,7 +931,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -940,7 +940,7 @@ describe('session', () => {
|
|||
}
|
||||
|
||||
const agent2 = new BskyAgent({service: 'https://bob.com'})
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob.test',
|
||||
|
@ -965,7 +965,7 @@ describe('session', () => {
|
|||
expect(state.accounts.length).toBe(2)
|
||||
expect(state.currentAgentState.did).toBe('bob-did')
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice-updated.test',
|
||||
|
@ -1032,7 +1032,7 @@ describe('session', () => {
|
|||
}
|
||||
`)
|
||||
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob-updated.test',
|
||||
|
@ -1099,7 +1099,7 @@ describe('session', () => {
|
|||
|
||||
// Ignore other events for inactive agent.
|
||||
const lastState = state
|
||||
agent1.session = undefined
|
||||
agent1.sessionManager.session = undefined
|
||||
state = run(state, [
|
||||
{
|
||||
type: 'received-agent-event',
|
||||
|
@ -1126,7 +1126,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -1135,7 +1135,7 @@ describe('session', () => {
|
|||
}
|
||||
|
||||
const agent2 = new BskyAgent({service: 'https://bob.com'})
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob.test',
|
||||
|
@ -1162,7 +1162,7 @@ describe('session', () => {
|
|||
expect(state.accounts.length).toBe(1)
|
||||
expect(state.currentAgentState.did).toBe('bob-did')
|
||||
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -1188,7 +1188,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -1206,7 +1206,7 @@ describe('session', () => {
|
|||
expect(state.accounts.length).toBe(1)
|
||||
expect(state.currentAgentState.did).toBe('alice-did')
|
||||
|
||||
agent1.session = undefined
|
||||
agent1.sessionManager.session = undefined
|
||||
state = run(state, [
|
||||
{
|
||||
type: 'received-agent-event',
|
||||
|
@ -1255,7 +1255,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -1273,7 +1273,7 @@ describe('session', () => {
|
|||
expect(state.accounts[0].accessJwt).toBe('alice-access-jwt-1')
|
||||
expect(state.currentAgentState.did).toBe('alice-did')
|
||||
|
||||
agent1.session = undefined
|
||||
agent1.sessionManager.session = undefined
|
||||
state = run(state, [
|
||||
{
|
||||
type: 'received-agent-event',
|
||||
|
@ -1320,7 +1320,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -1338,7 +1338,7 @@ describe('session', () => {
|
|||
expect(state.accounts[0].accessJwt).toBe('alice-access-jwt-1')
|
||||
expect(state.currentAgentState.did).toBe('alice-did')
|
||||
|
||||
agent1.session = undefined
|
||||
agent1.sessionManager.session = undefined
|
||||
state = run(state, [
|
||||
{
|
||||
type: 'received-agent-event',
|
||||
|
@ -1385,7 +1385,7 @@ describe('session', () => {
|
|||
let state = getInitialState([])
|
||||
|
||||
const agent1 = new BskyAgent({service: 'https://alice.com'})
|
||||
agent1.session = {
|
||||
agent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'alice-did',
|
||||
handle: 'alice.test',
|
||||
|
@ -1393,7 +1393,7 @@ describe('session', () => {
|
|||
refreshJwt: 'alice-refresh-jwt-1',
|
||||
}
|
||||
const agent2 = new BskyAgent({service: 'https://bob.com'})
|
||||
agent2.session = {
|
||||
agent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob.test',
|
||||
|
@ -1416,7 +1416,7 @@ describe('session', () => {
|
|||
expect(state.currentAgentState.did).toBe('bob-did')
|
||||
|
||||
const anotherTabAgent1 = new BskyAgent({service: 'https://jay.com'})
|
||||
anotherTabAgent1.session = {
|
||||
anotherTabAgent1.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'jay-did',
|
||||
handle: 'jay.test',
|
||||
|
@ -1424,7 +1424,7 @@ describe('session', () => {
|
|||
refreshJwt: 'jay-refresh-jwt-1',
|
||||
}
|
||||
const anotherTabAgent2 = new BskyAgent({service: 'https://alice.com'})
|
||||
anotherTabAgent2.session = {
|
||||
anotherTabAgent2.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'bob-did',
|
||||
handle: 'bob.test',
|
||||
|
@ -1492,7 +1492,7 @@ describe('session', () => {
|
|||
`)
|
||||
|
||||
const anotherTabAgent3 = new BskyAgent({service: 'https://clarence.com'})
|
||||
anotherTabAgent3.session = {
|
||||
anotherTabAgent3.sessionManager.session = {
|
||||
active: true,
|
||||
did: 'clarence-did',
|
||||
handle: 'clarence.test',
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
import {AtpSessionData, AtpSessionEvent, BskyAgent} from '@atproto/api'
|
||||
import {
|
||||
AtpPersistSessionHandler,
|
||||
AtpSessionData,
|
||||
AtpSessionEvent,
|
||||
BskyAgent,
|
||||
} from '@atproto/api'
|
||||
import {TID} from '@atproto/common-web'
|
||||
|
||||
import {networkRetry} from '#/lib/async/retry'
|
||||
|
@ -20,6 +25,8 @@ import {
|
|||
import {SessionAccount} from './types'
|
||||
import {isSessionExpired, isSignupQueued} from './util'
|
||||
|
||||
type SetPersistSessionHandler = (cb: AtpPersistSessionHandler) => void
|
||||
|
||||
export function createPublicAgent() {
|
||||
configureModerationForGuest() // Side effect but only relevant for tests
|
||||
return new BskyAgent({service: PUBLIC_BSKY_SERVICE})
|
||||
|
@ -32,10 +39,11 @@ export async function createAgentAndResume(
|
|||
did: string,
|
||||
event: AtpSessionEvent,
|
||||
) => void,
|
||||
setPersistSessionHandler: SetPersistSessionHandler,
|
||||
) {
|
||||
const agent = new BskyAgent({service: storedAccount.service})
|
||||
if (storedAccount.pdsUrl) {
|
||||
agent.pdsUrl = agent.api.xrpc.uri = new URL(storedAccount.pdsUrl)
|
||||
agent.sessionManager.pdsUrl = new URL(storedAccount.pdsUrl)
|
||||
}
|
||||
const gates = tryFetchGates(storedAccount.did, 'prefer-low-latency')
|
||||
const moderation = configureModerationForAccount(agent, storedAccount)
|
||||
|
@ -43,9 +51,8 @@ export async function createAgentAndResume(
|
|||
if (isSessionExpired(storedAccount)) {
|
||||
await networkRetry(1, () => agent.resumeSession(prevSession))
|
||||
} else {
|
||||
agent.session = prevSession
|
||||
agent.sessionManager.session = prevSession
|
||||
if (!storedAccount.signupQueued) {
|
||||
// Intentionally not awaited to unblock the UI:
|
||||
networkRetry(3, () => agent.resumeSession(prevSession)).catch(
|
||||
(e: any) => {
|
||||
logger.error(`networkRetry failed to resume session`, {
|
||||
|
@ -60,7 +67,13 @@ export async function createAgentAndResume(
|
|||
}
|
||||
}
|
||||
|
||||
return prepareAgent(agent, gates, moderation, onSessionChange)
|
||||
return prepareAgent(
|
||||
agent,
|
||||
gates,
|
||||
moderation,
|
||||
onSessionChange,
|
||||
setPersistSessionHandler,
|
||||
)
|
||||
}
|
||||
|
||||
export async function createAgentAndLogin(
|
||||
|
@ -80,6 +93,7 @@ export async function createAgentAndLogin(
|
|||
did: string,
|
||||
event: AtpSessionEvent,
|
||||
) => void,
|
||||
setPersistSessionHandler: SetPersistSessionHandler,
|
||||
) {
|
||||
const agent = new BskyAgent({service})
|
||||
await agent.login({identifier, password, authFactorToken})
|
||||
|
@ -87,7 +101,13 @@ export async function createAgentAndLogin(
|
|||
const account = agentToSessionAccountOrThrow(agent)
|
||||
const gates = tryFetchGates(account.did, 'prefer-fresh-gates')
|
||||
const moderation = configureModerationForAccount(agent, account)
|
||||
return prepareAgent(agent, moderation, gates, onSessionChange)
|
||||
return prepareAgent(
|
||||
agent,
|
||||
moderation,
|
||||
gates,
|
||||
onSessionChange,
|
||||
setPersistSessionHandler,
|
||||
)
|
||||
}
|
||||
|
||||
export async function createAgentAndCreateAccount(
|
||||
|
@ -115,6 +135,7 @@ export async function createAgentAndCreateAccount(
|
|||
did: string,
|
||||
event: AtpSessionEvent,
|
||||
) => void,
|
||||
setPersistSessionHandler: SetPersistSessionHandler,
|
||||
) {
|
||||
const agent = new BskyAgent({service})
|
||||
await agent.createAccount({
|
||||
|
@ -174,7 +195,13 @@ export async function createAgentAndCreateAccount(
|
|||
logger.error(e, {context: `session: failed snoozeEmailConfirmationPrompt`})
|
||||
}
|
||||
|
||||
return prepareAgent(agent, gates, moderation, onSessionChange)
|
||||
return prepareAgent(
|
||||
agent,
|
||||
gates,
|
||||
moderation,
|
||||
onSessionChange,
|
||||
setPersistSessionHandler,
|
||||
)
|
||||
}
|
||||
|
||||
async function prepareAgent(
|
||||
|
@ -187,13 +214,14 @@ async function prepareAgent(
|
|||
did: string,
|
||||
event: AtpSessionEvent,
|
||||
) => void,
|
||||
setPersistSessionHandler: (cb: AtpPersistSessionHandler) => void,
|
||||
) {
|
||||
// There's nothing else left to do, so block on them here.
|
||||
await Promise.all([gates, moderation])
|
||||
|
||||
// Now the agent is ready.
|
||||
const account = agentToSessionAccountOrThrow(agent)
|
||||
agent.setPersistSessionHandler(event => {
|
||||
setPersistSessionHandler(event => {
|
||||
onSessionChange(agent, account.did, event)
|
||||
if (event !== 'create' && event !== 'update') {
|
||||
addSessionErrorLog(account.did, event)
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import React from 'react'
|
||||
import {AtpSessionEvent, BskyAgent} from '@atproto/api'
|
||||
import {
|
||||
AtpPersistSessionHandler,
|
||||
AtpSessionEvent,
|
||||
BskyAgent,
|
||||
} from '@atproto/api'
|
||||
|
||||
import {track} from '#/lib/analytics/analytics'
|
||||
import {logEvent} from '#/lib/statsig/statsig'
|
||||
|
@ -47,6 +51,15 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||
return initialState
|
||||
})
|
||||
|
||||
const persistSessionHandler = React.useRef<
|
||||
AtpPersistSessionHandler | undefined
|
||||
>(undefined)
|
||||
const setPersistSessionHandler = (
|
||||
newHandler: AtpPersistSessionHandler | undefined,
|
||||
) => {
|
||||
persistSessionHandler.current = newHandler
|
||||
}
|
||||
|
||||
const onAgentSessionChange = React.useCallback(
|
||||
(agent: BskyAgent, accountDid: string, sessionEvent: AtpSessionEvent) => {
|
||||
const refreshedAccount = agentToSessionAccount(agent) // Mutable, so snapshot it right away.
|
||||
|
@ -73,6 +86,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||
const {agent, account} = await createAgentAndCreateAccount(
|
||||
params,
|
||||
onAgentSessionChange,
|
||||
setPersistSessionHandler,
|
||||
)
|
||||
|
||||
if (signal.aborted) {
|
||||
|
@ -97,6 +111,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||
const {agent, account} = await createAgentAndLogin(
|
||||
params,
|
||||
onAgentSessionChange,
|
||||
setPersistSessionHandler,
|
||||
)
|
||||
|
||||
if (signal.aborted) {
|
||||
|
@ -138,6 +153,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||
const {agent, account} = await createAgentAndResume(
|
||||
storedAccount,
|
||||
onAgentSessionChange,
|
||||
setPersistSessionHandler,
|
||||
)
|
||||
|
||||
if (signal.aborted) {
|
||||
|
@ -202,7 +218,7 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||
} else {
|
||||
const agent = state.currentAgentState.agent as BskyAgent
|
||||
const prevSession = agent.session
|
||||
agent.session = sessionAccountToSession(syncedAccount)
|
||||
agent.sessionManager.session = sessionAccountToSession(syncedAccount)
|
||||
addSessionDebugLog({
|
||||
type: 'agent:patch',
|
||||
agent,
|
||||
|
@ -249,8 +265,8 @@ export function Provider({children}: React.PropsWithChildren<{}>) {
|
|||
addSessionDebugLog({type: 'agent:switch', prevAgent, nextAgent: agent})
|
||||
// We never reuse agents so let's fully neutralize the previous one.
|
||||
// This ensures it won't try to consume any refresh tokens.
|
||||
prevAgent.session = undefined
|
||||
prevAgent.setPersistSessionHandler(undefined)
|
||||
prevAgent.sessionManager.session = undefined
|
||||
setPersistSessionHandler(undefined)
|
||||
}
|
||||
}, [agent])
|
||||
|
||||
|
|
|
@ -56,7 +56,7 @@ type Log =
|
|||
type: 'agent:patch'
|
||||
agent: object
|
||||
prevSession: AtpSessionData | undefined
|
||||
nextSession: AtpSessionData
|
||||
nextSession: AtpSessionData | undefined
|
||||
}
|
||||
|
||||
export function wrapSessionReducerForLogging(reducer: Reducer): Reducer {
|
||||
|
|
437
yarn.lock
437
yarn.lock
|
@ -34,39 +34,65 @@
|
|||
jsonpointer "^5.0.0"
|
||||
leven "^3.1.0"
|
||||
|
||||
"@atproto/api@0.12.29":
|
||||
version "0.12.29"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.29.tgz#95a19202c2f0eec4c955909685be11009ba9b9a1"
|
||||
integrity sha512-PyzPLjGWR0qNOMrmj3Nt3N5NuuANSgOk/33Bu3j+rFjjPrHvk9CI6iQPU6zuDaDCoyOTRJRafw8X/aMQw+ilgw==
|
||||
"@atproto-labs/fetch-node@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto-labs/fetch-node/-/fetch-node-0.1.0.tgz#692666d57ec24a7ba0813077a303baccf26108e0"
|
||||
integrity sha512-DUHgaGw8LBqiGg51pUDuWK/alMcmNbpcK7ALzlF2Gw//TNLTsgrj0qY9aEtK+np9rEC+x/o3bN4SGnuQEpgqIg==
|
||||
dependencies:
|
||||
"@atproto-labs/fetch" "0.1.0"
|
||||
"@atproto-labs/pipe" "0.1.0"
|
||||
ipaddr.js "^2.1.0"
|
||||
psl "^1.9.0"
|
||||
undici "^6.14.1"
|
||||
|
||||
"@atproto-labs/fetch@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto-labs/fetch/-/fetch-0.1.0.tgz#50a46943fd2f321dd748de28c73ba7cbfa493132"
|
||||
integrity sha512-uirja+uA/C4HNk7vayM+AJqsccxQn2wVziUHxbsjJGt/K6Q8ZOKDaEX2+GrcXvpUVcqUKh+94JFjuzH+CAEUlg==
|
||||
dependencies:
|
||||
"@atproto-labs/pipe" "0.1.0"
|
||||
optionalDependencies:
|
||||
zod "^3.23.8"
|
||||
|
||||
"@atproto-labs/pipe@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto-labs/pipe/-/pipe-0.1.0.tgz#c8d86923b6d8e900d39efe6fdcdf0d897c434086"
|
||||
integrity sha512-ghOqHFyJlQVFPESzlVHjKroP0tPzbmG5Jms0dNI9yLDEfL8xp4OFPWLX4f6T8mRq69wWs4nIDM3sSsFbFqLa1w==
|
||||
|
||||
"@atproto-labs/simple-store-memory@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@atproto-labs/simple-store-memory/-/simple-store-memory-0.1.1.tgz#54526a1f8ec978822be9fad75106ad8b78500dd3"
|
||||
integrity sha512-PCRqhnZ8NBNBvLku53O56T0lsVOtclfIrQU/rwLCc4+p45/SBPrRYNBi6YFq5rxZbK6Njos9MCmILV/KLQxrWA==
|
||||
dependencies:
|
||||
"@atproto-labs/simple-store" "0.1.1"
|
||||
lru-cache "^10.2.0"
|
||||
|
||||
"@atproto-labs/simple-store@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@atproto-labs/simple-store/-/simple-store-0.1.1.tgz#e743a2722b5d8732166f0a72aca8bd10e9bff106"
|
||||
integrity sha512-WKILW2b3QbAYKh+w5U2x6p5FqqLl0nAeLwGeDY+KjX01K4Dq3vQTR9b/qNp0jZm48CabPQVrqCv0PPU9LgRRRg==
|
||||
|
||||
"@atproto/api@0.13.0", "@atproto/api@^0.13.0":
|
||||
version "0.13.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.13.0.tgz#d1c65a407f1c3c6aba5be9425f4f739a01419bd8"
|
||||
integrity sha512-04kzIDkoEVSP7zMVOT5ezCVQcOrbXWjGYO2YBc3/tBvQ90V1pl9I+mLyz1uUHE+wRE1IRWKACcWhAz8SrYz3pA==
|
||||
dependencies:
|
||||
"@atproto/common-web" "^0.3.0"
|
||||
"@atproto/lexicon" "^0.4.0"
|
||||
"@atproto/lexicon" "^0.4.1"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
"@atproto/xrpc" "^0.5.0"
|
||||
"@atproto/xrpc" "^0.6.0"
|
||||
await-lock "^2.2.2"
|
||||
multiformats "^9.9.0"
|
||||
tlds "^1.234.0"
|
||||
|
||||
"@atproto/api@^0.12.3":
|
||||
version "0.12.3"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/api/-/api-0.12.3.tgz#5b7b1c7d4210ee9315961504900c8409395cbb17"
|
||||
integrity sha512-y/kGpIEo+mKGQ7VOphpqCAigTI0LZRmDThNChTfSzDKm9TzEobwiw0zUID0Yw6ot1iLLFx3nKURmuZAYlEuobw==
|
||||
"@atproto/aws@^0.2.2":
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/aws/-/aws-0.2.2.tgz#703e5e06f288bcf61c6d99a990738f1e7299e653"
|
||||
integrity sha512-j7eR7+sQumFsc66/5xyCDez9JtR6dlZc+fOdwdh85nCJD4zmQyU4r1CKrA48wQ3tkzze+ASEb1SgODuIQmIugA==
|
||||
dependencies:
|
||||
"@atproto/common-web" "^0.3.0"
|
||||
"@atproto/lexicon" "^0.4.0"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
"@atproto/xrpc" "^0.5.0"
|
||||
multiformats "^9.9.0"
|
||||
tlds "^1.234.0"
|
||||
|
||||
"@atproto/aws@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/aws/-/aws-0.2.0.tgz#17f3faf744824457cabd62f87be8bf08cacf8029"
|
||||
integrity sha512-F09SHiC9CX3ydfrvYZbkpfES48UGCQNnznNVgJ3QyKSN8ON+BoWmGCpAFtn3AWeEoU0w9h0hypNvUm5nORv+5g==
|
||||
dependencies:
|
||||
"@atproto/common" "^0.4.0"
|
||||
"@atproto/common" "^0.4.1"
|
||||
"@atproto/crypto" "^0.4.0"
|
||||
"@atproto/repo" "^0.4.0"
|
||||
"@atproto/repo" "^0.4.2"
|
||||
"@aws-sdk/client-cloudfront" "^3.261.0"
|
||||
"@aws-sdk/client-kms" "^3.196.0"
|
||||
"@aws-sdk/client-s3" "^3.224.0"
|
||||
|
@ -76,19 +102,19 @@
|
|||
multiformats "^9.9.0"
|
||||
uint8arrays "3.0.0"
|
||||
|
||||
"@atproto/bsky@^0.0.45":
|
||||
version "0.0.45"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/bsky/-/bsky-0.0.45.tgz#c3083d8038fe8c5ff921d9bcb0b5a043cc840827"
|
||||
integrity sha512-osWeigdYzQH2vZki+eszCR8ta9zdUB4om79aFmnE+zvxw7HFduwAAbcHf6kmmiLCfaOWvCsYb1wS2i3IC66TAg==
|
||||
"@atproto/bsky@^0.0.74":
|
||||
version "0.0.74"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/bsky/-/bsky-0.0.74.tgz#b735af6ded16778604378710a2e871350c29570a"
|
||||
integrity sha512-vyukmlBamoET0sZnDMOeTGAkQNV7KbHg65uIQ6OX4/QGynyaQP8SvSF0OsEBzBqOraxV1w9WT8AZrUbyl3uvIg==
|
||||
dependencies:
|
||||
"@atproto/api" "^0.12.3"
|
||||
"@atproto/common" "^0.4.0"
|
||||
"@atproto/api" "^0.13.0"
|
||||
"@atproto/common" "^0.4.1"
|
||||
"@atproto/crypto" "^0.4.0"
|
||||
"@atproto/identity" "^0.4.0"
|
||||
"@atproto/lexicon" "^0.4.0"
|
||||
"@atproto/repo" "^0.4.0"
|
||||
"@atproto/lexicon" "^0.4.1"
|
||||
"@atproto/repo" "^0.4.2"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
"@atproto/xrpc-server" "^0.5.1"
|
||||
"@atproto/xrpc-server" "^0.6.1"
|
||||
"@bufbuild/protobuf" "^1.5.0"
|
||||
"@connectrpc/connect" "^1.1.4"
|
||||
"@connectrpc/connect-express" "^1.1.4"
|
||||
|
@ -105,19 +131,20 @@
|
|||
multiformats "^9.9.0"
|
||||
p-queue "^6.6.2"
|
||||
pg "^8.10.0"
|
||||
pino "^8.15.0"
|
||||
pino "^8.21.0"
|
||||
pino-http "^8.2.1"
|
||||
sharp "^0.32.6"
|
||||
statsig-node "^5.23.1"
|
||||
structured-headers "^1.0.1"
|
||||
typed-emitter "^2.1.0"
|
||||
uint8arrays "3.0.0"
|
||||
|
||||
"@atproto/bsync@^0.0.3":
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/bsync/-/bsync-0.0.3.tgz#2b0b8ef3686cf177846a80088317f2e89d1bf88f"
|
||||
integrity sha512-tJRwNgXzfNV57lzgWPvjtb1OMlMJH9SpsMeYhIii16zcaFUWwsb474BicKpkGRT+iCvtYzBT6gWlZE2Ijnhf7w==
|
||||
"@atproto/bsync@^0.0.5":
|
||||
version "0.0.5"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/bsync/-/bsync-0.0.5.tgz#bf2fa45e4595fda12addcd6784314e4dbe409046"
|
||||
integrity sha512-xCCMHy14y4tQoXiGrfd0XjSnc4q7I9bUNqju9E8jrP95QTDedH1FQgybStbUIbHt0eEqY5v9E7iZBH3n7Kiz7A==
|
||||
dependencies:
|
||||
"@atproto/common" "^0.4.0"
|
||||
"@atproto/common" "^0.4.1"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
"@bufbuild/protobuf" "^1.5.0"
|
||||
"@connectrpc/connect" "^1.1.4"
|
||||
|
@ -158,17 +185,17 @@
|
|||
pino "^8.6.1"
|
||||
zod "^3.14.2"
|
||||
|
||||
"@atproto/common@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/common/-/common-0.4.0.tgz#d77696c7eb545426df727837d9ee333b429fe7ef"
|
||||
integrity sha512-yOXuPlCjT/OK9j+neIGYn9wkxx/AlxQSucysAF0xgwu0Ji8jAtKBf9Jv6R5ObYAjAD/kVUvEYumle+Yq/R9/7g==
|
||||
"@atproto/common@^0.4.1":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/common/-/common-0.4.1.tgz#ca6fce47001ce8d031acd3fb4942fbfd81f72c43"
|
||||
integrity sha512-uL7kQIcBTbvkBDNfxMXL6lBH4fO2DQpHd2BryJxMtbw/4iEPKe9xBYApwECHhEIk9+zhhpTRZ15FJ3gxTXN82Q==
|
||||
dependencies:
|
||||
"@atproto/common-web" "^0.3.0"
|
||||
"@ipld/dag-cbor" "^7.0.3"
|
||||
cbor-x "^1.5.1"
|
||||
iso-datestring-validator "^2.2.2"
|
||||
multiformats "^9.9.0"
|
||||
pino "^8.15.0"
|
||||
pino "^8.21.0"
|
||||
|
||||
"@atproto/crypto@0.1.0":
|
||||
version "0.1.0"
|
||||
|
@ -190,22 +217,22 @@
|
|||
"@noble/hashes" "^1.3.1"
|
||||
uint8arrays "3.0.0"
|
||||
|
||||
"@atproto/dev-env@^0.3.5":
|
||||
version "0.3.5"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/dev-env/-/dev-env-0.3.5.tgz#cd13313dbc52131731d039a1d22808ee8193505d"
|
||||
integrity sha512-dqRNihzX1xIHbWPHmfYsliUUXyZn5FFhCeButrGie5soQmHA4okQJTB1XWDly3mdHLjUM90g+5zjRSAKoui77Q==
|
||||
"@atproto/dev-env@^0.3.39":
|
||||
version "0.3.39"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/dev-env/-/dev-env-0.3.39.tgz#f498f087d4da43d5f86805c07d5f2b781e60fd6f"
|
||||
integrity sha512-rIeUO99DL8/gRKYEAkAFuTn77y8letEbKMXnfpsVX2YHD89VRdDyMxkYzRu2+31UjtGv62I+qTLLKQS4EcFItA==
|
||||
dependencies:
|
||||
"@atproto/api" "^0.12.3"
|
||||
"@atproto/bsky" "^0.0.45"
|
||||
"@atproto/bsync" "^0.0.3"
|
||||
"@atproto/api" "^0.13.0"
|
||||
"@atproto/bsky" "^0.0.74"
|
||||
"@atproto/bsync" "^0.0.5"
|
||||
"@atproto/common-web" "^0.3.0"
|
||||
"@atproto/crypto" "^0.4.0"
|
||||
"@atproto/identity" "^0.4.0"
|
||||
"@atproto/lexicon" "^0.4.0"
|
||||
"@atproto/ozone" "^0.1.7"
|
||||
"@atproto/pds" "^0.4.14"
|
||||
"@atproto/lexicon" "^0.4.1"
|
||||
"@atproto/ozone" "^0.1.36"
|
||||
"@atproto/pds" "^0.4.48"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
"@atproto/xrpc-server" "^0.5.1"
|
||||
"@atproto/xrpc-server" "^0.6.1"
|
||||
"@did-plc/lib" "^0.0.1"
|
||||
"@did-plc/server" "^0.0.1"
|
||||
axios "^0.27.2"
|
||||
|
@ -224,30 +251,79 @@
|
|||
"@atproto/crypto" "^0.4.0"
|
||||
axios "^0.27.2"
|
||||
|
||||
"@atproto/lexicon@^0.4.0":
|
||||
version "0.4.0"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.0.tgz#63e8829945d80c25524882caa8ed27b1151cc576"
|
||||
integrity sha512-RvCBKdSI4M8qWm5uTNz1z3R2yIvIhmOsMuleOj8YR6BwRD+QbtUBy3l+xQ7iXf4M5fdfJFxaUNa6Ty0iRwdKqQ==
|
||||
"@atproto/jwk-jose@0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/jwk-jose/-/jwk-jose-0.1.2.tgz#236eadb740b498689d9a912d1254aa9ff58890a1"
|
||||
integrity sha512-lDwc/6lLn2aZ/JpyyggyjLFsJPMntrVzryyGUx5aNpuTS8SIuc4Ky0REhxqfLopQXJJZCuRRjagHG3uP05/moQ==
|
||||
dependencies:
|
||||
"@atproto/jwk" "0.1.1"
|
||||
jose "^5.2.0"
|
||||
|
||||
"@atproto/jwk@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/jwk/-/jwk-0.1.1.tgz#15bcad4a1778eeb20c82108e0ec55fef45cd07b6"
|
||||
integrity sha512-6h/bj1APUk7QcV9t/oA6+9DB5NZx9SZru9x+/pV5oHFI9Xz4ZuM5+dq1PfsJV54pZyqdnZ6W6M717cxoC7q7og==
|
||||
dependencies:
|
||||
multiformats "^9.9.0"
|
||||
zod "^3.23.8"
|
||||
|
||||
"@atproto/lexicon@^0.4.1":
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/lexicon/-/lexicon-0.4.1.tgz#19155210570a2fafbcc7d4f655d9b813948e72a0"
|
||||
integrity sha512-bzyr+/VHXLQWbumViX5L7h1NKQObfs8Z+XZJl43OUK8nYFUI4e/sW1IZKRNfw7Wvi5YVNK+J+yP3DWIBZhkCYA==
|
||||
dependencies:
|
||||
"@atproto/common-web" "^0.3.0"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
iso-datestring-validator "^2.2.2"
|
||||
multiformats "^9.9.0"
|
||||
zod "^3.21.4"
|
||||
zod "^3.23.8"
|
||||
|
||||
"@atproto/ozone@^0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/ozone/-/ozone-0.1.7.tgz#248d88e1acfe56936651754975472d03d047d689"
|
||||
integrity sha512-vvaV0MFynOzZJcL8m8mEW21o1FFIkP+wHTXEC9LJrL3h03+PMaby8Ujmif6WX5eikhfxvr9xsU/Jxbi/iValuQ==
|
||||
"@atproto/oauth-provider@^0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/oauth-provider/-/oauth-provider-0.1.2.tgz#a576a4c7795c7938a994e76192c19a2e73ffcddf"
|
||||
integrity sha512-z1YKK0XLDfSDtLP5ntPCviEtajvUHbI4TwzYQ5X9CAL9PoXjqhQg0U/csg1wGDs8qkbphF9gni9M2stlpH7H0g==
|
||||
dependencies:
|
||||
"@atproto/api" "^0.12.3"
|
||||
"@atproto/common" "^0.4.0"
|
||||
"@atproto-labs/fetch" "0.1.0"
|
||||
"@atproto-labs/fetch-node" "0.1.0"
|
||||
"@atproto-labs/pipe" "0.1.0"
|
||||
"@atproto-labs/simple-store" "0.1.1"
|
||||
"@atproto-labs/simple-store-memory" "0.1.1"
|
||||
"@atproto/jwk" "0.1.1"
|
||||
"@atproto/jwk-jose" "0.1.2"
|
||||
"@atproto/oauth-types" "0.1.2"
|
||||
"@hapi/accept" "^6.0.3"
|
||||
"@hapi/bourne" "^3.0.0"
|
||||
cookie "^0.6.0"
|
||||
http-errors "^2.0.0"
|
||||
jose "^5.2.0"
|
||||
oidc-token-hash "^5.0.3"
|
||||
psl "^1.9.0"
|
||||
zod "^3.23.8"
|
||||
optionalDependencies:
|
||||
ioredis "^5.3.2"
|
||||
keygrip "^1.1.0"
|
||||
|
||||
"@atproto/oauth-types@0.1.2":
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/oauth-types/-/oauth-types-0.1.2.tgz#d6c497c8e5f88f1875c630adde4ed9c5d8a8b4f4"
|
||||
integrity sha512-yySPPTLxteFJ3O3xVWEhvBFx7rczgo4LK2nQNeqAPMZdYd5dpgvuZZ88nQQge074BfuOc0MWTnr0kPdxQMjjPw==
|
||||
dependencies:
|
||||
"@atproto/jwk" "0.1.1"
|
||||
zod "^3.23.8"
|
||||
|
||||
"@atproto/ozone@^0.1.36":
|
||||
version "0.1.36"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/ozone/-/ozone-0.1.36.tgz#6a1a71fdff3ff486c5951a9e491e954b51703d53"
|
||||
integrity sha512-BQThLU5RFG+/bZli/fj5YrFU8jW5rkium7aplfJX2eHkV6huJnBU5DcgracjH2paPGC5L/zjYtibz5spqatKAg==
|
||||
dependencies:
|
||||
"@atproto/api" "^0.13.0"
|
||||
"@atproto/common" "^0.4.1"
|
||||
"@atproto/crypto" "^0.4.0"
|
||||
"@atproto/identity" "^0.4.0"
|
||||
"@atproto/lexicon" "^0.4.0"
|
||||
"@atproto/lexicon" "^0.4.1"
|
||||
"@atproto/syntax" "^0.3.0"
|
||||
"@atproto/xrpc" "^0.5.0"
|
||||
"@atproto/xrpc-server" "^0.5.1"
|
||||
"@atproto/xrpc" "^0.6.0"
|
||||
"@atproto/xrpc-server" "^0.6.1"
|
||||
"@did-plc/lib" "^0.0.1"
|
||||
axios "^1.6.7"
|
||||
compression "^1.7.4"
|
||||
|
@ -255,30 +331,34 @@
|
|||
express "^4.17.2"
|
||||
http-terminator "^3.2.0"
|
||||
kysely "^0.22.0"
|
||||
lande "^1.0.10"
|
||||
multiformats "^9.9.0"
|
||||
p-queue "^6.6.2"
|
||||
pg "^8.10.0"
|
||||
pino-http "^8.2.1"
|
||||
structured-headers "^1.0.1"
|
||||
typed-emitter "^2.1.0"
|
||||
uint8arrays "3.0.0"
|
||||
|
||||
"@atproto/pds@^0.4.14":
|
||||
version "0.4.14"
|
||||
resolved "https://registry.yarnpkg.com/@atproto/pds/-/pds-0.4. |