Replace mock-api with real api

zio/stable
Paul Frazee 2022-09-22 19:28:25 -05:00
parent 5193a5b48e
commit aabde2b401
110 changed files with 16045 additions and 3742 deletions

View File

@ -220,11 +220,11 @@ PODS:
- React-jsinspector (0.68.2) - React-jsinspector (0.68.2)
- React-logger (0.68.2): - React-logger (0.68.2):
- glog - glog
- react-native-safe-area-context (4.3.1): - react-native-safe-area-context (4.3.4):
- RCT-Folly - RCT-Folly
- RCTRequired - RCTRequired
- RCTTypeSafety - RCTTypeSafety
- React - React-Core
- ReactCommon/turbomodule/core - ReactCommon/turbomodule/core
- React-perflogger (0.68.2) - React-perflogger (0.68.2)
- React-RCTActionSheet (0.68.2): - React-RCTActionSheet (0.68.2):
@ -291,15 +291,17 @@ PODS:
- React-jsi (= 0.68.2) - React-jsi (= 0.68.2)
- React-logger (= 0.68.2) - React-logger (= 0.68.2)
- React-perflogger (= 0.68.2) - React-perflogger (= 0.68.2)
- RNCAsyncStorage (1.17.6): - rn-fetch-blob (0.12.0):
- React-Core - React-Core
- RNCClipboard (1.10.0): - RNCAsyncStorage (1.17.10):
- React-Core - React-Core
- RNGestureHandler (2.5.0): - RNCClipboard (1.11.1):
- React-Core - React-Core
- RNInAppBrowser (3.6.3): - RNGestureHandler (2.6.1):
- React-Core - React-Core
- RNReanimated (2.9.1): - RNInAppBrowser (3.7.0):
- React-Core
- RNReanimated (2.10.0):
- DoubleConversion - DoubleConversion
- FBLazyVector - FBLazyVector
- FBReactNativeSpec - FBReactNativeSpec
@ -326,10 +328,10 @@ PODS:
- React-RCTText - React-RCTText
- ReactCommon/turbomodule/core - ReactCommon/turbomodule/core
- Yoga - Yoga
- RNScreens (3.13.1): - RNScreens (3.17.0):
- React-Core - React-Core
- React-RCTImage - React-RCTImage
- RNSVG (12.4.0): - RNSVG (12.4.4):
- React-Core - React-Core
- Yoga (1.14.0) - Yoga (1.14.0)
@ -368,6 +370,7 @@ DEPENDENCIES:
- React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`) - React-RCTVibration (from `../node_modules/react-native/Libraries/Vibration`)
- React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`) - React-runtimeexecutor (from `../node_modules/react-native/ReactCommon/runtimeexecutor`)
- ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`) - ReactCommon/turbomodule/core (from `../node_modules/react-native/ReactCommon`)
- rn-fetch-blob (from `../node_modules/rn-fetch-blob`)
- "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)" - "RNCAsyncStorage (from `../node_modules/@react-native-async-storage/async-storage`)"
- "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)" - "RNCClipboard (from `../node_modules/@react-native-clipboard/clipboard`)"
- RNGestureHandler (from `../node_modules/react-native-gesture-handler`) - RNGestureHandler (from `../node_modules/react-native-gesture-handler`)
@ -446,6 +449,8 @@ EXTERNAL SOURCES:
:path: "../node_modules/react-native/ReactCommon/runtimeexecutor" :path: "../node_modules/react-native/ReactCommon/runtimeexecutor"
ReactCommon: ReactCommon:
:path: "../node_modules/react-native/ReactCommon" :path: "../node_modules/react-native/ReactCommon"
rn-fetch-blob:
:path: "../node_modules/rn-fetch-blob"
RNCAsyncStorage: RNCAsyncStorage:
:path: "../node_modules/@react-native-async-storage/async-storage" :path: "../node_modules/@react-native-async-storage/async-storage"
RNCClipboard: RNCClipboard:
@ -484,7 +489,7 @@ SPEC CHECKSUMS:
React-jsiexecutor: b7b553412f2ec768fe6c8f27cd6bafdb9d8719e6 React-jsiexecutor: b7b553412f2ec768fe6c8f27cd6bafdb9d8719e6
React-jsinspector: c5989c77cb89ae6a69561095a61cce56a44ae8e8 React-jsinspector: c5989c77cb89ae6a69561095a61cce56a44ae8e8
React-logger: a0833912d93b36b791b7a521672d8ee89107aff1 React-logger: a0833912d93b36b791b7a521672d8ee89107aff1
react-native-safe-area-context: 6c12e3859b6f27b25de4fee8201cfb858432d8de react-native-safe-area-context: dfe5aa13bee37a0c7e8059d14f72ffc076d120e9
React-perflogger: a18b4f0bd933b8b24ecf9f3c54f9bf65180f3fe6 React-perflogger: a18b4f0bd933b8b24ecf9f3c54f9bf65180f3fe6
React-RCTActionSheet: 547fe42fdb4b6089598d79f8e1d855d7c23e2162 React-RCTActionSheet: 547fe42fdb4b6089598d79f8e1d855d7c23e2162
React-RCTAnimation: bc9440a1c37b06ae9ebbb532d244f607805c6034 React-RCTAnimation: bc9440a1c37b06ae9ebbb532d244f607805c6034
@ -497,13 +502,14 @@ SPEC CHECKSUMS:
React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374 React-RCTVibration: 79040b92bfa9c3c2d2cb4f57e981164ec7ab9374
React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23 React-runtimeexecutor: b960b687d2dfef0d3761fbb187e01812ebab8b23
ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2 ReactCommon: 095366164a276d91ea704ce53cb03825c487a3f2
RNCAsyncStorage: 466b9df1a14bccda91da86e0b7d9a345d78e1673 rn-fetch-blob: f065bb7ab7fb48dd002629f8bdcb0336602d3cba
RNCClipboard: f1736c75ab85b627a4d57587edb4b60999c4dd80 RNCAsyncStorage: 0c357f3156fcb16c8589ede67cc036330b6698ca
RNGestureHandler: bad495418bcbd3ab47017a38d93d290ebd406f50 RNCClipboard: 2834e1c4af68697089cdd455ee4a4cdd198fa7dd
RNInAppBrowser: 3ff3a3b8f458aaf25aaee879d057352862edf357 RNGestureHandler: 28ad20bf02257791f7f137b31beef34b9549f54b
RNReanimated: 5c8c17e26787fd8984cd5accdc70fef2ca70aafd RNInAppBrowser: e36d6935517101ccba0e875bac8ad7b0cb655364
RNScreens: 40a2cb40a02a609938137a1e0acfbf8fc9eebf19 RNReanimated: 5bdcbcc3a72aedeee7bb099604262403aa75a1e5
RNSVG: 3dd44d99d1c18e1342aee4bfa53ab3f6a8c4865f RNScreens: 0df01424e9e0ed7827200d6ed1087ddd06c493f9
RNSVG: ecd661f380a07ba690c9c5929c475a44f432d674
Yoga: 99652481fcd320aefa4a7ef90095b95acd181952 Yoga: 99652481fcd320aefa4a7ef90095b95acd181952
PODFILE CHECKSUM: cf94853ebcb0d8e0d027dca9ab7a4ede886a8f20 PODFILE CHECKSUM: cf94853ebcb0d8e0d027dca9ab7a4ede886a8f20

View File

@ -4,18 +4,14 @@
"private": true, "private": true,
"scripts": { "scripts": {
"android": "react-native run-android", "android": "react-native run-android",
"ios": "react-native run-ios", "ios": "react-native run-ios --simulator=\"iPhone 14\"",
"web": "react-scripts start", "web": "react-scripts start",
"start": "react-native start", "start": "react-native start",
"dev-pds": "node ./scripts/testing-server.mjs", "dev-env": "dev-env",
"dev-wallet": "cd node_modules/\\@adxp/auth-lobby && npm run start:authed",
"test": "jest", "test": "jest",
"lint": "eslint . --ext .js,.jsx,.ts,.tsx" "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
}, },
"dependencies": { "dependencies": {
"@adxp/auth": "*",
"@adxp/common": "*",
"@adxp/mock-api": "git+ssh://git@github.com:bluesky-social/adx-mock-api.git#e6f9ecd510fd54fbc5af32e319342634d9446a07",
"@fortawesome/fontawesome-svg-core": "^6.1.1", "@fortawesome/fontawesome-svg-core": "^6.1.1",
"@fortawesome/free-regular-svg-icons": "^6.1.1", "@fortawesome/free-regular-svg-icons": "^6.1.1",
"@fortawesome/free-solid-svg-icons": "^6.1.1", "@fortawesome/free-solid-svg-icons": "^6.1.1",
@ -44,12 +40,10 @@
"react-native-svg": "^12.4.0", "react-native-svg": "^12.4.0",
"react-native-url-polyfill": "^1.3.0", "react-native-url-polyfill": "^1.3.0",
"react-native-web": "^0.17.7", "react-native-web": "^0.17.7",
"rn-fetch-blob": "^0.12.0",
"ucans": "0.9.1" "ucans": "0.9.1"
}, },
"devDependencies": { "devDependencies": {
"@adxp/auth-lobby": "*",
"@adxp/server": "*",
"@adxp/ws-relay": "*",
"@babel/core": "^7.12.9", "@babel/core": "^7.12.9",
"@babel/runtime": "^7.12.5", "@babel/runtime": "^7.12.5",
"@react-native-community/eslint-config": "^2.0.0", "@react-native-community/eslint-config": "^2.0.0",

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -1,36 +0,0 @@
import {IpldStore} from '@adxp/common'
import PDSServer from '@adxp/server/dist/server.js'
import PDSDatabase from '@adxp/server/dist/db/index.js'
import WSRelayServer from '@adxp/ws-relay/dist/index.js'
import AuthLobbyServer from '@adxp/auth-lobby'
const PDS_PORT = 2583
const AUTH_LOBBY1_PORT = 3001
const AUTH_LOBBY2_PORT = 3002
const WSR_PORT = 3005
async function start() {
console.log('Initializing...')
const db = PDSDatabase.memory()
const serverBlockstore = IpldStore.createInMemory()
await db.dropTables()
await db.createTables()
PDSServer(serverBlockstore, db, PDS_PORT)
init(AuthLobbyServer, AUTH_LOBBY1_PORT, 'Auth lobby')
if (process.argv.includes('--relay')) {
init(AuthLobbyServer, AUTH_LOBBY2_PORT, 'Auth lobby 2')
init(WSRelayServer, WSR_PORT, 'Relay server')
} else {
console.log('Include --relay to start the WS Relay and second auth lobby')
}
}
start()
function init(fn, port, name) {
const s = fn(port)
s.on('listening', () => console.log(`${name} running on port ${port}`))
s.on('error', e => console.log(`${name} failed to start:`, e))
}

View File

@ -1,5 +1,5 @@
import {autorun} from 'mobx' import {autorun} from 'mobx'
import {AdxClient, blueskywebSchemas} from '@adxp/mock-api' import AdxApi from '../third-party/api'
import {RootStoreModel} from './models/root-store' import {RootStoreModel} from './models/root-store'
import * as libapi from './lib/api' import * as libapi from './lib/api'
import * as storage from './lib/storage' import * as storage from './lib/storage'
@ -13,10 +13,7 @@ export async function setupState() {
let rootStore: RootStoreModel let rootStore: RootStoreModel
let data: any let data: any
const api = new AdxClient({ const api = AdxApi.service(`http://localhost:2583`)
pds: 'http://localhost',
schemas: blueskywebSchemas,
})
await libapi.setup(api) await libapi.setup(api)
rootStore = new RootStoreModel(api) rootStore = new RootStoreModel(api)
try { try {

View File

@ -3,33 +3,18 @@
* models live. They are made available to every model via dependency injection. * models live. They are made available to every model via dependency injection.
*/ */
import RNFetchBlob from 'rn-fetch-blob'
// import {ReactNativeStore} from './auth' // import {ReactNativeStore} from './auth'
import { import AdxApi, {ServiceClient} from '../../third-party/api'
AdxClient, import {AdxUri} from '../../third-party/uri'
AdxRepoClient,
AdxRepoCollectionClient,
AdxUri,
bsky,
SchemaOpt,
ListRecordsResponseValidated,
GetRecordResponseValidated,
} from '@adxp/mock-api'
import * as storage from './storage' import * as storage from './storage'
import {postTexts} from './mock-data/post-texts'
import {replyTexts} from './mock-data/reply-texts'
export async function setup(adx: AdxClient) { export async function setup(adx: ServiceClient) {
await adx.setupMock( AdxApi.xrpc.fetch = fetchHandler
() => storage.load('mock-root'),
async root => {
await storage.save('mock-root', root)
},
() => generateMockData(adx),
)
} }
export async function post( export async function post(
adx: AdxClient, adx: ServiceClient,
user: string, user: string,
text: string, text: string,
replyToUri?: string, replyToUri?: string,
@ -37,10 +22,10 @@ export async function post(
let reply let reply
if (replyToUri) { if (replyToUri) {
const replyToUrip = new AdxUri(replyToUri) const replyToUrip = new AdxUri(replyToUri)
const parentPost = await adx const parentPost = await adx.todo.social.post.get({
.repo(replyToUrip.host, false) nameOrDid: replyToUrip.host,
.collection(replyToUrip.collection) tid: replyToUrip.recordKey,
.get('Post', replyToUrip.recordKey) })
if (parentPost) { if (parentPost) {
reply = { reply = {
root: parentPost.value.reply?.root || parentPost.uri, root: parentPost.value.reply?.root || parentPost.uri,
@ -48,94 +33,126 @@ export async function post(
} }
} }
} }
return await adx return await adx.todo.social.post.create(
.repo(user, true) {did: user},
.collection('blueskyweb.xyz:Posts') {
.create('Post', {
$type: 'blueskyweb.xyz:Post',
text, text,
reply, reply,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}) },
)
} }
export async function like(adx: AdxClient, user: string, uri: string) { export async function like(adx: ServiceClient, user: string, uri: string) {
return await adx return await adx.todo.social.like.create(
.repo(user, true) {did: user},
.collection('blueskyweb.xyz:Likes') {
.create('Like', {
$type: 'blueskyweb.xyz:Like',
subject: uri, subject: uri,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}) },
)
} }
export async function unlike(adx: AdxClient, user: string, uri: string) { export async function unlike(adx: ServiceClient, user: string, uri: string) {
const coll = adx.repo(user, true).collection('blueskyweb.xyz:Likes') throw new Error('TODO')
const numDels = await deleteWhere(coll, 'Like', record => {
return record.value.subject === uri
})
return numDels > 0
} }
export async function repost(adx: AdxClient, user: string, uri: string) { export async function repost(adx: ServiceClient, user: string, uri: string) {
return await adx return await adx.todo.social.repost.create(
.repo(user, true) {did: user},
.collection('blueskyweb.xyz:Posts') {
.create('Repost', {
$type: 'blueskyweb.xyz:Repost',
subject: uri, subject: uri,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}) },
)
} }
export async function unrepost(adx: AdxClient, user: string, uri: string) { export async function unrepost(adx: ServiceClient, user: string, uri: string) {
const coll = adx.repo(user, true).collection('blueskyweb.xyz:Posts') throw new Error('TODO')
const numDels = await deleteWhere(coll, 'Repost', record => {
return record.value.subject === uri
})
return numDels > 0
} }
export async function follow( export async function follow(
adx: AdxClient, adx: ServiceClient,
user: string, user: string,
subject: {did: string; name: string}, subject: string,
) { ) {
return await adx return await adx.todo.social.follow.create(
.repo(user, true) {did: user},
.collection('blueskyweb.xyz:Follows') {
.create('Follow', {
$type: 'blueskyweb.xyz:Follow',
subject, subject,
createdAt: new Date().toISOString(), createdAt: new Date().toISOString(),
}) },
)
} }
export async function unfollow( export async function unfollow(
adx: AdxClient, adx: ServiceClient,
user: string, user: string,
subject: {did: string}, subject: {did: string},
) { ) {
const coll = adx.repo(user, true).collection('blueskyweb.xyz:Follows') throw new Error('TODO')
const numDels = await deleteWhere(coll, 'Follow', record => {
return record.value.subject.did === subject.did
})
return numDels > 0
} }
export async function updateProfile( export async function updateProfile(
adx: AdxClient, adx: ServiceClient,
user: string, user: string,
profile: bsky.Profile.Record, profile: bsky.Profile.Record,
) { ) {
return await adx throw new Error('TODO')
.repo(user, true)
.collection('blueskyweb.xyz:Profiles')
.put('Profile', 'profile', {$type: 'blueskyweb.xyz:Profile', ...profile})
} }
type WherePred = (_record: GetRecordResponseValidated) => Boolean interface FetchHandlerResponse {
status: number
headers: Record<string, string>
body: ArrayBuffer | undefined
}
async function fetchHandler(
httpUri: string,
httpMethod: string,
httpHeaders: Record<string, string>,
httpReqBody: any,
): Promise<FetchHandlerResponse> {
httpHeaders['Authorization'] = 'did:test:alice' // DEBUG
const res = await RNFetchBlob.fetch(
/** @ts-ignore method coersion, it's fine -prf */
httpMethod,
httpUri,
httpHeaders,
httpReqBody,
)
const status = res.info().status
const headers = (res.info().headers || {}) as Record<string, string>
const mimeType = headers['Content-Type'] || headers['content-type']
let resBody
if (mimeType) {
if (mimeType.startsWith('application/json')) {
resBody = res.json()
} else if (mimeType.startsWith('text/')) {
resBody = res.text()
} else {
resBody = res.base64()
}
}
return {
status,
headers,
body: resBody,
}
// const res = await fetch(httpUri, {
// method: httpMethod,
// headers: httpHeaders,
// body: encodeMethodCallBody(httpHeaders, httpReqBody),
// })
// const resBody = await res.arrayBuffer()
// return {
// status: res.status,
// headers: Object.fromEntries(res.headers.entries()),
// body: httpResponseBodyParse(res.headers.get('content-type'), resBody),
// }
}
/*type WherePred = (_record: GetRecordResponseValidated) => Boolean
async function deleteWhere( async function deleteWhere(
coll: AdxRepoCollectionClient, coll: AdxRepoCollectionClient,
schema: SchemaOpt, schema: SchemaOpt,
@ -170,177 +187,4 @@ async function iterateAll(
} }
} }
} while (res.records.length === 100) } while (res.records.length === 100)
} }*/
// TEMPORARY
// mock api config
// =======
function* dateGen() {
let start = 1657846031914
while (true) {
yield new Date(start).toISOString()
start += 1e3
}
}
const date = dateGen()
function repo(adx: AdxClient, didOrName: string) {
const userDb = adx.mockDb.getUser(didOrName)
if (!userDb) throw new Error(`User not found: ${didOrName}`)
return adx.mainPds.repo(userDb.did, userDb.writable)
}
export async function generateMockData(adx: AdxClient) {
const rand = (n: number) => Math.floor(Math.random() * n)
const picka = <T>(arr: Array<T>): T => {
if (arr.length) {
return arr[rand(arr.length)] || arr[0]
}
throw new Error('Not found')
}
await adx.mockDb.addUser({name: 'alice.com', writable: true})
await adx.mockDb.addUser({name: 'bob.com', writable: true})
await adx.mockDb.addUser({name: 'carla.com', writable: true})
const alice = repo(adx, 'alice.com')
const bob = repo(adx, 'bob.com')
const carla = repo(adx, 'carla.com')
const repos = [alice, bob, carla]
await alice.collection('blueskyweb.xyz:Profiles').put('Profile', 'profile', {
$type: 'blueskyweb.xyz:Profile',
displayName: 'Alice',
description: 'Test user 1',
})
await bob.collection('blueskyweb.xyz:Profiles').put('Profile', 'profile', {
$type: 'blueskyweb.xyz:Profile',
displayName: 'Bob',
description: 'Test user 2',
})
await carla.collection('blueskyweb.xyz:Profiles').put('Profile', 'profile', {
$type: 'blueskyweb.xyz:Profile',
displayName: 'Carla',
description: 'Test user 3',
})
// everybody follows everybody
const follow = async (who: AdxRepoClient, subjectName: string) => {
const subjectDb = adx.mockDb.getUser(subjectName)
return who.collection('blueskyweb.xyz:Follows').create('Follow', {
$type: 'blueskyweb.xyz:Follow',
subject: {
did: subjectDb?.did,
name: subjectDb?.name,
},
createdAt: date.next().value,
})
}
await follow(alice, 'bob.com')
await follow(alice, 'carla.com')
await follow(bob, 'alice.com')
await follow(bob, 'carla.com')
await follow(carla, 'alice.com')
await follow(carla, 'bob.com')
// a set of posts and reposts
const posts: {uri: string}[] = []
for (let i = 0; i < postTexts.length; i++) {
const author = picka(repos)
posts.push(
await author.collection('blueskyweb.xyz:Posts').create('Post', {
$type: 'blueskyweb.xyz:Post',
text: postTexts[i],
createdAt: date.next().value,
}),
)
if (rand(10) === 0) {
await picka(repos)
.collection('blueskyweb.xyz:Posts')
.create('Repost', {
$type: 'blueskyweb.xyz:Repost',
subject: picka(posts).uri,
createdAt: date.next().value,
})
}
}
// a set of replies
for (let i = 0; i < 100; i++) {
const targetUri = picka(posts).uri
const urip = new AdxUri(targetUri)
const target = await adx.mainPds
.repo(urip.host, true)
.collection(urip.collection)
.get('Post', urip.recordKey)
const targetRecord = target.value as bsky.Post.Record
const author = picka(repos)
posts.push(
await author.collection('blueskyweb.xyz:Posts').create('Post', {
$type: 'blueskyweb.xyz:Post',
text: picka(replyTexts),
reply: {
root: targetRecord.reply ? targetRecord.reply.root : target.uri,
parent: target.uri,
},
createdAt: date.next().value,
}),
)
}
// a set of likes
for (const post of posts) {
for (const repo of repos) {
if (rand(3) === 0) {
await repo.collection('blueskyweb.xyz:Likes').create('Like', {
$type: 'blueskyweb.xyz:Like',
subject: post.uri,
createdAt: date.next().value,
})
}
}
}
// give alice 3 badges, 2 from bob and 2 from carla, with one ignored
const inviteBadge = await bob
.collection('blueskyweb.xyz:Badges')
.create('Badge', {
$type: 'blueskyweb.xyz:Badge',
subject: {did: alice.did, name: 'alice.com'},
assertion: {type: 'invite'},
createdAt: date.next().value,
})
const techTagBadge1 = await bob
.collection('blueskyweb.xyz:Badges')
.create('Badge', {
$type: 'blueskyweb.xyz:Badge',
subject: {did: alice.did, name: 'alice.com'},
assertion: {type: 'tag', tag: 'tech'},
createdAt: date.next().value,
})
const techTagBadge2 = await carla
.collection('blueskyweb.xyz:Badges')
.create('Badge', {
$type: 'blueskyweb.xyz:Badge',
subject: {did: alice.did, name: 'alice.com'},
assertion: {type: 'tag', tag: 'tech'},
createdAt: date.next().value,
})
await bob.collection('blueskyweb.xyz:Badges').create('Badge', {
$type: 'blueskyweb.xyz:Badge',
subject: {did: alice.did, name: 'alice.com'},
assertion: {type: 'employee'},
createdAt: date.next().value,
})
await alice.collection('blueskyweb.xyz:Profiles').put('Profile', 'profile', {
$type: 'blueskyweb.xyz:Profile',
displayName: 'Alice',
description: 'Test user 1',
badges: [
{uri: inviteBadge.uri},
{uri: techTagBadge1.uri},
{uri: techTagBadge2.uri},
],
})
}

View File

@ -1,4 +1,5 @@
import * as auth from '@adxp/auth' export {} // TODO
/*import * as auth from '@adxp/auth'
import * as ucan from 'ucans' import * as ucan from 'ucans'
import { import {
getInitialURL, getInitialURL,
@ -114,3 +115,4 @@ export class ReactNativeStore extends auth.AuthStore {
this.ucanStore = await ucan.Store.fromTokens([]) this.ucanStore = await ucan.Store.fromTokens([])
} }
} }
*/

View File

@ -1,147 +0,0 @@
// I just scraped some of my twitter timeline into here
// hope nobody minds
// -prf
export const postTexts = [
'last call! share your most offbeat home idea and you could get $100,000 USD to build it. applications to the OMG! fund are open until july 22. for rules and how to apply→ http://airbnb.com/omgfund?twclid=2-6f25jsvulsw1bpglil5jvkku0',
'Great to get some quality time with @DavidJWest #Agile2022',
'vive la sybil résistance',
'Where does one mint on @tezos these days?',
'Tame the day with the soothing and luxurious all-new 2022 INFINITI QX60.',
"In case you're wondering how it's going in the UK, here's the person most likely to be our next PM:",
'Really thought I was watching an SNL clip',
'Mediocrity is like a magnet pulling organizations toward it. You can only avoid it by constant effort.',
'Nobody in the replies talking about RegCF, DAOs, etc…\n' +
'\n' +
'The innovation is non, perhaps contra-hierarchical.',
'There are times when I think DevOps is just group therapy for system administrators.',
'Is DevOps still relevant?\n' +
'\n' +
'Join me tomorrow, at 11:00 AM PDT, to discuss the state of DevOps with @nathenharvey, as we attempt to answer that question. https://twitter.com/i/spaces/1dRKZlMPbWaJB…',
'trash is love. trash is life.',
'I want you guys to know Ive done it. Ive killed the legendary Michael Myers with a series of good stabs. No one could survive it. Hell, I even checked to be sure he was dead. Anyone got weekend plans?',
'Orgs that performed timely server upgrades averaged 19% revenue growth.',
'Seeing all of the @ mention mint scams of late…',
"For fuck's sake, Gary.",
'And another',
'Ah go on, one more',
"Wait, so there's no way to test microphone settings for Twitter Spaces without creating a Twitter Space, going 'live', and having it notify everyone? Amazing.",
'gidge day',
'British Defense Intelligence Ukraine Update, July 20, 2022\n' +
'#RussiaUkraineWar',
' Were launching a brand new template soon on @tailwindui Im really excited about this one! \n' +
'\n' +
'Here is a preview:',
'Are you looking for a pediatrician near your home or work? ARC has pediatricians in 23 locations around Central Texas. \n' +
'\n' +
'Our pediatricians are ready to partner with you in the growth and development of your child and family, no matter where you live.',
'And well be making undici-fetch happen. H/t @matteocollina',
"It's Wednesday, you know what that means....\n" +
'\n' +
' Office Hours - 9:30AM PDT / 12:30PM EDT / 4:30PM (16:30) GMT \n' +
'\n' +
' Maker Hour - 1:00PM PDT / 4:00PM EDT / 8:00PM (20:00) GMT\n' +
'\n' +
'Join us in @discord',
"Europe's bleak Russian winter, made stark: \n" +
'\n' +
"Brussels proposes Europe cuts its gas usage by 15 per cent between now and April next year if governments literally want to keep the lights on and people's homes warm.",
'Tips for using TypeScript via JSDoc comments',
'My talk is today come say hi!',
'Im giving a talk on private smart contract using homomorphic encryption on Wednesday at 2:20pm. Come say hi! #fhe #web3 #privacy #ethereum',
'We have just showcased the new build and discussed our future plans to support developers Recording coming soon! If you are in Paris drop us a line to grab a coffee ',
'TFW you forget to buy milk for your morning coffee and now have to get dressed and go outside at 6:30am.',
'seeing an awful lot of articles referring to the "European heatwave" in the past tense. first of all:',
'Is there a way to fix this issue this when using TypeScript via JSDoc comments? (Reply to the quoted tweet.)',
'For instance in this code I dont know how to tell TS that, no, the `res` will not be `string`. (`api` is an instance of the `got` npm package).',
'In the latest magazine, bob kindly invited me to write about techniques for ensuring convergence in distributed systems. Article is now up!',
"This is a reboot of the “Research for Practice” column that @alice.com used to run. The idea is to distill some key ideas from recent CS research and to make them accessible to folks in industry who don't normally have time for reading papers.",
"This is cool: post a video to @whimful's REVERSE CONFERENCE @ DWeb so you can maximize your human connecting time at camp ",
'New blog post: How to speed up the Rust compiler in July 2022\n' +
'\n' +
'https://nnethercote.github.io/2022/07/20/how-to-speed-up-the-rust-compiler-in-july-2022.html…\n' +
'\n' +
'PGO on Windows, MIR inlining, better derived code for builtin traits, and much more!',
'my new favorite past time is watching older couples at the airport \n' +
'\n' +
'Wife: “Put your mask on. I dont want you sick for your birthday.”\n' +
'Husband: “Can you leave me alone for one goddamn minute?”',
"We're all gonna die",
'Builders building, this month at @NativeHostels on 4th Street.\n' +
'- Coworking & coffee on Tuesdays 11am-3pm \n' +
'- HAPPY HOUR HANGOUTS on Thursdays 7:30-10pm \n' +
'RSVP: https://ATXDAO-Native-HH.eventbrite.com',
'crypto meetings IRL are my favorite.\n' +
'\n' +
'@ATXDAO\n' +
'@HopeCampaign\n' +
'@NativeHostels\n' +
'@wagmiyall \n' +
'@evrydayresearch \n' +
'@zcreativemedia \n' +
'@CrystalGravy2\n' +
'@NickCPlusPlus\n' +
'@_ElaineAlonzo',
'I recommend @Scroll_ZKP create and hire for a developer advocate position to deliver world class developer experience.',
'Intelligent Tracking Prevention identifies trackers and helps prevent them from profiling or following you across the web.',
"Big story in Norway this summer is a walrus we've named Freya has made it to our shores and is touring the country, laying around and sinking boats",
'"the other fellows at the CIA were unequivocally against assassinating three of the greatest musicians of their generation, but I went in there and held my convictions and said my piece."',
'hls is annoying technology',
'This summer, prey for survival. Experience #BeastMovie only in theaters August 19.',
"got the new twitter update. i don't like it",
'Might just set this as a daily reminder.',
'Gm. Today, ask yourself:\n' +
'\n' +
'Is my Web3/NFT/DeFi/crypto making a better life for someone other than myself?',
'every time I add a piece to my native #webgl engine I end up crying and appreciating even more the work @mrdoob and the @threejs team is doing. yall have no idea',
'i dont like having 2 plagues and no healthcare. i should have 0 plagues and 2 healthcare',
'this is the only lotr behind the scenes pic that matters actually',
'Photographer took pictures of a baby hippo scared of birds',
'lol',
"VC's explaining web3.",
'Cyberattacks cost banks $18.3 million annually per company. We ensure that youre not part of that statistic.#stayrelentless.',
'In SF, you can choose kind of weather you want',
'a day in earth 2.0 should be 26 hours',
'who wants to start a religion',
'We just launched our code-hosting platform!\n' +
'\n' +
"It's like Github, but has hyperlinked syntax-highlighted code and docs from day one \n" +
'\n' +
"I can't overemphasize how nice it feels to push code and immediately see it there, published, highlighted, and linked up!",
'Now that youve seen them do the universe, its time for them to do a new series. Mike Judges Beavis and Butt-Head is coming to #ParamountPlus on August 4th. #beavisandbutthead',
'Organized a nice crypto research dinner with @protocollabs and @zama_fhe - very vibrant community with a lot of open problems :)\n' +
'\n' +
'Planning to organize more going forward - reach out if this is your vibe!',
"Houston drivers are crazy. Been here two days and have had multiple vehicles charging up and tailing me, then switching lanes, roaring past, and weaving through traffic. While I'm going 75mph, keeping with the flow of traffic. WTF??",
`LIVE NOW: a mix of projects coming to #DWebCamp2022! @gvelez17 of @dsocialcommons is planning "Dogfooding Decentralization" a user-testing lab at DWeb Camp. You can sign up to present your tools. We'll send you the link tomorrow! 1/n`,
`Fabiola of @guardianproject is bringing "Butter Box" "Inspiration Beans" & more. (They must love ) Butter Box is raspberry pi-based hotspot w/ encrypted chat. It's opensource & offline first. Come onboard & connect with others offline. (8/n)`,
"Up Now: @guardianproject's Jack Fox Keen w/ tools to verify the authencity++ of data. They are leading a Cryptographically Verified Scavenger Hunt (9/n)",
'Translating VC Language',
'What would Sherlock Holmes do? Listen to true crime podcasts early on Amazon Music. #TrueCrimeonAmazonMusic',
'How to deal with a hung Linux system',
'ALRIGHT PELOTON HAPPY MONDAY I WANNA FEEL THAT ENERGY COMING THROUGH THE SCREEN AS WE START GETTING OUR AMAZING BODIES WARMED UP. THIS FIRST TRACK IS CALLED "DONALD DUCK GETTING A BLOWJOB" RESISTANCE 30 CADENCE 80',
"Thank you to all who joined us at @pbailis' executive roundtable lunch at @VentureBeat's #VBTransform!\n" +
'\n' +
'#ICYMI, stop by the Sisu table today to meet the team & learn how to supercharge your analytics workflow with decision intelligence.',
'Prescribing Info: http://bit.ly/2cTmItE?twclid=2-1jogj2v7zxu2rw1zmzyms8jpg \n' +
'Med Guide: http://bit.ly/2yon94P?twclid=2-1jogj2v7zxu2rw1zmzyms8jpg\n' +
'\n' +
'Discover a treatment for certain patients with kidney cancer (RCC).',
'Want to learn how to write E2EE P2P apps without even trying? Check out the new application sandbox and api in Peergos!',
'Ageism was always a reality in tech. \n' +
'\n' +
'The “in-office” only crowd have found a way to make their ageism more respectable.\n' +
'\n' +
'PS - most startups would rather hire the 32 yo Senior FAANG engineer than a 20 something grad who needs a ton of mentorship.',
"I don't mind jumping on a call at work. I think that should be the last resort, not the first one.",
'If you missed attending #MSInspire, we missed you too. You can still find plenty of on-demand content available at your convenience. Take advantage of the ongoing opportunity to enrich your business prospects.',
"TODAY AT 4 PM PT: Join for the DWeb Meetup where we'll see some of the workshops coming to DWeb Camp 2022:\n" +
'@metagov_project\n' +
' @ameliawb\n' +
' @guardianproject\n' +
' @gvelez17\n' +
' @infrared_ether\n' +
'@LauBenedict\n' +
' @guardianproject\n' +
'@byUnfinished\n' +
' Come be inspired:',
]

View File

@ -1,24 +0,0 @@
export const replyTexts = [
'Wow, so true!',
'Haha ikr',
'lol',
'What does this mean for democrats in the midterms?',
'What does this mean for republicans in the midterms?',
'What does this mean for pet owners in the midterms?',
'is it cool if I DM?',
"This is sort of accurate, but honestly it misses a huge part of the issue at hand. There are just so many factors and I don't think a vibe is enough to cover it.",
'Wen token',
'This is disgusting and you should take it down',
'fire',
'a/s/l?',
'this is so much better than twitter',
'this is so much better than tiktok',
'this is so much better than gab',
'this is so much better than truth social',
'finally! decentralization!',
'ugh when will hashtags get supported in vibe',
'ted cruz is the deep state!',
'aoc is the deep state!',
'donald trump is the deep state!',
'taco tuesdays is the deep state!',
]

View File

@ -1,30 +1,30 @@
import {makeAutoObservable, runInAction} from 'mobx' import {makeAutoObservable, runInAction} from 'mobx'
import {bsky} from '@adxp/mock-api' import * as GetFeedView from '../../third-party/api/src/types/todo/social/getFeed'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
import * as apilib from '../lib/api' import * as apilib from '../lib/api'
export class FeedViewItemMyStateModel { export class FeedViewItemMyStateModel {
hasLiked: boolean = false repost?: string
hasReposted: boolean = false like?: string
constructor() { constructor() {
makeAutoObservable(this) makeAutoObservable(this)
} }
} }
export class FeedViewItemModel implements bsky.FeedView.FeedItem { export class FeedViewItemModel implements GetFeedView.FeedItem {
// ui state // ui state
_reactKey: string = '' _reactKey: string = ''
// data // data
uri: string = '' uri: string = ''
author: bsky.FeedView.User = {did: '', name: '', displayName: ''} author: GetFeedView.User = {did: '', name: '', displayName: ''}
repostedBy?: bsky.FeedView.User repostedBy?: GetFeedView.User
record: Record<string, unknown> = {} record: Record<string, unknown> = {}
embed?: embed?:
| bsky.FeedView.RecordEmbed | GetFeedView.RecordEmbed
| bsky.FeedView.ExternalEmbed | GetFeedView.ExternalEmbed
| bsky.FeedView.UnknownEmbed | GetFeedView.UnknownEmbed
replyCount: number = 0 replyCount: number = 0
repostCount: number = 0 repostCount: number = 0
likeCount: number = 0 likeCount: number = 0
@ -34,14 +34,14 @@ export class FeedViewItemModel implements bsky.FeedView.FeedItem {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
reactKey: string, reactKey: string,
v: bsky.FeedView.FeedItem, v: GetFeedView.FeedItem,
) { ) {
makeAutoObservable(this, {rootStore: false}) makeAutoObservable(this, {rootStore: false})
this._reactKey = reactKey this._reactKey = reactKey
this.copy(v) this.copy(v)
} }
copy(v: bsky.FeedView.FeedItem) { copy(v: GetFeedView.FeedItem) {
this.uri = v.uri this.uri = v.uri
this.author = v.author this.author = v.author
this.repostedBy = v.repostedBy this.repostedBy = v.repostedBy
@ -52,52 +52,56 @@ export class FeedViewItemModel implements bsky.FeedView.FeedItem {
this.likeCount = v.likeCount this.likeCount = v.likeCount
this.indexedAt = v.indexedAt this.indexedAt = v.indexedAt
if (v.myState) { if (v.myState) {
this.myState.hasLiked = v.myState.hasLiked this.myState.like = v.myState.like
this.myState.hasReposted = v.myState.hasReposted this.myState.repost = v.myState.repost
} }
} }
async toggleLike() { async toggleLike() {
if (this.myState.hasLiked) { if (this.myState.like) {
await apilib.unlike(this.rootStore.api, 'alice.com', this.uri) await apilib.unlike(this.rootStore.api, 'alice.test', this.uri)
runInAction(() => { runInAction(() => {
this.likeCount-- this.likeCount--
this.myState.hasLiked = false this.myState.like = undefined
}) })
} else { } else {
await apilib.like(this.rootStore.api, 'alice.com', this.uri) const res = await apilib.like(this.rootStore.api, 'alice.test', this.uri)
runInAction(() => { runInAction(() => {
this.likeCount++ this.likeCount++
this.myState.hasLiked = true this.myState.like = res.uri
}) })
} }
} }
async toggleRepost() { async toggleRepost() {
if (this.myState.hasReposted) { if (this.myState.repost) {
await apilib.unrepost(this.rootStore.api, 'alice.com', this.uri) await apilib.unrepost(this.rootStore.api, 'alice.test', this.uri)
runInAction(() => { runInAction(() => {
this.repostCount-- this.repostCount--
this.myState.hasReposted = false this.myState.repost = undefined
}) })
} else { } else {
await apilib.repost(this.rootStore.api, 'alice.com', this.uri) const res = await apilib.repost(
this.rootStore.api,
'alice.test',
this.uri,
)
runInAction(() => { runInAction(() => {
this.repostCount++ this.repostCount++
this.myState.hasReposted = true this.myState.repost = res.uri
}) })
} }
} }
} }
export class FeedViewModel implements bsky.FeedView.Response { export class FeedViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
hasReachedEnd = false hasReachedEnd = false
error = '' error = ''
params: bsky.FeedView.Params params: GetFeedView.QueryParams
_loadPromise: Promise<void> | undefined _loadPromise: Promise<void> | undefined
_loadMorePromise: Promise<void> | undefined _loadMorePromise: Promise<void> | undefined
_updatePromise: Promise<void> | undefined _updatePromise: Promise<void> | undefined
@ -105,7 +109,10 @@ export class FeedViewModel implements bsky.FeedView.Response {
// data // data
feed: FeedViewItemModel[] = [] feed: FeedViewItemModel[] = []
constructor(public rootStore: RootStoreModel, params: bsky.FeedView.Params) { constructor(
public rootStore: RootStoreModel,
params: GetFeedView.QueryParams,
) {
makeAutoObservable( makeAutoObservable(
this, this,
{ {
@ -223,10 +230,7 @@ export class FeedViewModel implements bsky.FeedView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getFeed(this.params)
'blueskyweb.xyz:FeedView',
this.params,
)) as bsky.FeedView.Response
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -241,11 +245,8 @@ export class FeedViewModel implements bsky.FeedView.Response {
const params = Object.assign({}, this.params, { const params = Object.assign({}, this.params, {
before: this.loadMoreCursor, before: this.loadMoreCursor,
}) })
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getFeed(params)
'blueskyweb.xyz:FeedView', if (res.data.feed.length === 0) {
params,
)) as bsky.FeedView.Response
if (res.feed.length === 0) {
runInAction(() => { runInAction(() => {
this.hasReachedEnd = true this.hasReachedEnd = true
}) })
@ -265,20 +266,18 @@ export class FeedViewModel implements bsky.FeedView.Response {
let cursor = undefined let cursor = undefined
try { try {
do { do {
const res = (await this.rootStore.api.mainPds.view( const res: GetFeedView.Response =
'blueskyweb.xyz:FeedView', await this.rootStore.api.todo.social.getFeed({
{
before: cursor, before: cursor,
limit: Math.min(numToFetch, 100), limit: Math.min(numToFetch, 100),
}, })
)) as bsky.FeedView.Response if (res.data.feed.length === 0) {
if (res.feed.length === 0) {
break // sanity check break // sanity check
} }
this._updateAll(res) this._updateAll(res)
numToFetch -= res.feed.length numToFetch -= res.data.feed.length
cursor = this.feed[res.feed.length - 1].indexedAt cursor = this.feed[res.data.feed.length - 1].indexedAt
console.log(numToFetch, cursor, res.feed.length) console.log(numToFetch, cursor, res.data.feed.length)
} while (numToFetch > 0) } while (numToFetch > 0)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -286,26 +285,26 @@ export class FeedViewModel implements bsky.FeedView.Response {
} }
} }
private _replaceAll(res: bsky.FeedView.Response) { private _replaceAll(res: GetFeedView.Response) {
this.feed.length = 0 this.feed.length = 0
this.hasReachedEnd = false this.hasReachedEnd = false
this._appendAll(res) this._appendAll(res)
} }
private _appendAll(res: bsky.FeedView.Response) { private _appendAll(res: GetFeedView.Response) {
let counter = this.feed.length let counter = this.feed.length
for (const item of res.feed) { for (const item of res.data.feed) {
this._append(counter++, item) this._append(counter++, item)
} }
} }
private _append(keyId: number, item: bsky.FeedView.FeedItem) { private _append(keyId: number, item: GetFeedView.FeedItem) {
// TODO: validate .record // TODO: validate .record
this.feed.push(new FeedViewItemModel(this.rootStore, `item-${keyId}`, item)) this.feed.push(new FeedViewItemModel(this.rootStore, `item-${keyId}`, item))
} }
private _updateAll(res: bsky.FeedView.Response) { private _updateAll(res: GetFeedView.Response) {
for (const item of res.feed) { for (const item of res.data.feed) {
const existingItem = this.feed.find( const existingItem = this.feed.find(
// this find function has a key subtley- the indexedAt comparison // this find function has a key subtley- the indexedAt comparison
// the reason for this is reposts: they set the URI of the original post, not of the repost record // the reason for this is reposts: they set the URI of the original post, not of the repost record

View File

@ -1,8 +1,9 @@
import {makeAutoObservable, runInAction} from 'mobx' import {makeAutoObservable, runInAction} from 'mobx'
import {bsky, AdxUri} from '@adxp/mock-api' import {AdxUri} from '../../third-party/uri'
import * as GetLikedBy from '../../third-party/api/src/types/todo/social/getLikedBy'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
type LikedByItem = bsky.LikedByView.Response['likedBy'][number] type LikedByItem = GetLikedBy.OutputSchema['likedBy'][number]
export class LikedByViewItemModel implements LikedByItem { export class LikedByViewItemModel implements LikedByItem {
// ui state // ui state
@ -22,14 +23,14 @@ export class LikedByViewItemModel implements LikedByItem {
} }
} }
export class LikedByViewModel implements bsky.LikedByView.Response { export class LikedByViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
error = '' error = ''
resolvedUri = '' resolvedUri = ''
params: bsky.LikedByView.Params params: GetLikedBy.QueryParams
// data // data
uri: string = '' uri: string = ''
@ -37,7 +38,7 @@ export class LikedByViewModel implements bsky.LikedByView.Response {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.LikedByView.Params, params: GetLikedBy.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -113,10 +114,9 @@ export class LikedByViewModel implements bsky.LikedByView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getLikedBy(
'blueskyweb.xyz:LikedByView',
Object.assign({}, this.params, {uri: this.resolvedUri}), Object.assign({}, this.params, {uri: this.resolvedUri}),
)) as bsky.LikedByView.Response )
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -124,10 +124,10 @@ export class LikedByViewModel implements bsky.LikedByView.Response {
} }
} }
private _replaceAll(res: bsky.LikedByView.Response) { private _replaceAll(res: GetLikedBy.Response) {
this.likedBy.length = 0 this.likedBy.length = 0
let counter = 0 let counter = 0
for (const item of res.likedBy) { for (const item of res.data.likedBy) {
this._append(counter++, item) this._append(counter++, item)
} }
} }

View File

@ -14,18 +14,16 @@ export class MeModel {
async load() { async load() {
const sess = this.rootStore.session const sess = this.rootStore.session
if (sess.isAuthed) { if (sess.isAuthed) {
const userDb = this.rootStore.api.mockDb.mainUser // TODO
this.did = userDb.did this.did = 'did:test:alice'
this.name = userDb.name this.name = 'alice.todo'
const profile = await this.rootStore.api const profile = await this.rootStore.api.todo.social.getProfile({
.repo(this.did, true) user: this.did,
.collection('blueskyweb.xyz:Profiles') })
.get('Profile', 'profile')
.catch(_ => undefined)
runInAction(() => { runInAction(() => {
if (profile?.valid) { if (profile?.data) {
this.displayName = profile.value.displayName this.displayName = profile.data.displayName
this.description = profile.value.description this.description = profile.data.description
} else { } else {
this.displayName = '' this.displayName = ''
this.description = '' this.description = ''

View File

@ -231,8 +231,9 @@ export class NavigationModel {
} }
hydrate(v: unknown) { hydrate(v: unknown) {
this.tabs.length = 0 // this.tabs.length = 0
this.tabIndex = 0 // this.tabIndex = 0
return // DEBUG
if (isObj(v)) { if (isObj(v)) {
if (hasProp(v, 'tabs') && Array.isArray(v.tabs)) { if (hasProp(v, 'tabs') && Array.isArray(v.tabs)) {
for (const tab of v.tabs) { for (const tab of v.tabs) {

View File

@ -1,10 +1,10 @@
import {makeAutoObservable, runInAction} from 'mobx' import {makeAutoObservable} from 'mobx'
import {bsky} from '@adxp/mock-api' import * as GetNotifications from '../../third-party/api/src/types/todo/social/getNotifications'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
import {hasProp} from '../lib/type-guards' import {hasProp} from '../lib/type-guards'
export class NotificationsViewItemModel export class NotificationsViewItemModel
implements bsky.NotificationsView.Notification implements GetNotifications.Notification
{ {
// ui state // ui state
_reactKey: string = '' _reactKey: string = ''
@ -23,14 +23,14 @@ export class NotificationsViewItemModel
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
reactKey: string, reactKey: string,
v: bsky.NotificationsView.Notification, v: GetNotifications.Notification,
) { ) {
makeAutoObservable(this, {rootStore: false}) makeAutoObservable(this, {rootStore: false})
this._reactKey = reactKey this._reactKey = reactKey
this.copy(v) this.copy(v)
} }
copy(v: bsky.NotificationsView.Notification) { copy(v: GetNotifications.Notification) {
this.uri = v.uri this.uri = v.uri
this.author = v.author this.author = v.author
this.record = v.record this.record = v.record
@ -77,13 +77,13 @@ export class NotificationsViewItemModel
} }
} }
export class NotificationsViewModel implements bsky.NotificationsView.Response { export class NotificationsViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
error = '' error = ''
params: bsky.NotificationsView.Params params: GetNotifications.QueryParams
_loadPromise: Promise<void> | undefined _loadPromise: Promise<void> | undefined
_loadMorePromise: Promise<void> | undefined _loadMorePromise: Promise<void> | undefined
_updatePromise: Promise<void> | undefined _updatePromise: Promise<void> | undefined
@ -93,7 +93,7 @@ export class NotificationsViewModel implements bsky.NotificationsView.Response {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.NotificationsView.Params, params: GetNotifications.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -212,10 +212,9 @@ export class NotificationsViewModel implements bsky.NotificationsView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getNotifications(
'blueskyweb.xyz:NotificationsView',
this.params, this.params,
)) as bsky.NotificationsView.Response )
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -230,10 +229,7 @@ export class NotificationsViewModel implements bsky.NotificationsView.Response {
const params = Object.assign({}, this.params, { const params = Object.assign({}, this.params, {
before: this.loadMoreCursor, before: this.loadMoreCursor,
}) })
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getNotifications(params)
'blueskyweb.xyz:NotificationsView',
params,
)) as bsky.NotificationsView.Response
this._appendAll(res) this._appendAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -248,20 +244,18 @@ export class NotificationsViewModel implements bsky.NotificationsView.Response {
let cursor = undefined let cursor = undefined
try { try {
do { do {
const res = (await this.rootStore.api.mainPds.view( const res: GetNotifications.Response =
'blueskyweb.xyz:NotificationsView', await this.rootStore.api.todo.social.getNotifications({
{
before: cursor, before: cursor,
limit: Math.min(numToFetch, 100), limit: Math.min(numToFetch, 100),
}, })
)) as bsky.NotificationsView.Response if (res.data.notifications.length === 0) {
if (res.notifications.length === 0) {
break // sanity check break // sanity check
} }
this._updateAll(res) this._updateAll(res)
numToFetch -= res.notifications.length numToFetch -= res.data.notifications.length
cursor = this.notifications[res.notifications.length - 1].indexedAt cursor = this.notifications[res.data.notifications.length - 1].indexedAt
console.log(numToFetch, cursor, res.notifications.length) console.log(numToFetch, cursor, res.data.notifications.length)
} while (numToFetch > 0) } while (numToFetch > 0)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -269,27 +263,27 @@ export class NotificationsViewModel implements bsky.NotificationsView.Response {
} }
} }
private _replaceAll(res: bsky.NotificationsView.Response) { private _replaceAll(res: GetNotifications.Response) {
this.notifications.length = 0 this.notifications.length = 0
this._appendAll(res) this._appendAll(res)
} }
private _appendAll(res: bsky.NotificationsView.Response) { private _appendAll(res: GetNotifications.Response) {
let counter = this.notifications.length let counter = this.notifications.length
for (const item of res.notifications) { for (const item of res.data.notifications) {
this._append(counter++, item) this._append(counter++, item)
} }
} }
private _append(keyId: number, item: bsky.NotificationsView.Notification) { private _append(keyId: number, item: GetNotifications.Notification) {
// TODO: validate .record // TODO: validate .record
this.notifications.push( this.notifications.push(
new NotificationsViewItemModel(this.rootStore, `item-${keyId}`, item), new NotificationsViewItemModel(this.rootStore, `item-${keyId}`, item),
) )
} }
private _updateAll(res: bsky.NotificationsView.Response) { private _updateAll(res: GetNotifications.Response) {
for (const item of res.notifications) { for (const item of res.data.notifications) {
const existingItem = this.notifications.find( const existingItem = this.notifications.find(
// this find function has a key subtley- the indexedAt comparison // this find function has a key subtley- the indexedAt comparison
// the reason for this is reposts: they set the URI of the original post, not of the repost record // the reason for this is reposts: they set the URI of the original post, not of the repost record

View File

@ -1,5 +1,6 @@
import {makeAutoObservable, runInAction} from 'mobx' import {makeAutoObservable, runInAction} from 'mobx'
import {bsky, AdxUri} from '@adxp/mock-api' import * as GetPostThread from '../../third-party/api/src/types/todo/social/getPostThread'
import {AdxUri} from '../../third-party/uri'
import _omit from 'lodash.omit' import _omit from 'lodash.omit'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
import * as apilib from '../lib/api' import * as apilib from '../lib/api'
@ -12,15 +13,15 @@ function* reactKeyGenerator(): Generator<string> {
} }
export class PostThreadViewPostMyStateModel { export class PostThreadViewPostMyStateModel {
hasLiked: boolean = false like?: string
hasReposted: boolean = false repost?: string
constructor() { constructor() {
makeAutoObservable(this) makeAutoObservable(this)
} }
} }
export class PostThreadViewPostModel implements bsky.PostThreadView.Post { export class PostThreadViewPostModel implements GetPostThread.Post {
// ui state // ui state
_reactKey: string = '' _reactKey: string = ''
_depth = 0 _depth = 0
@ -28,12 +29,12 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
// data // data
uri: string = '' uri: string = ''
author: bsky.PostThreadView.User = {did: '', name: '', displayName: ''} author: GetPostThread.User = {did: '', name: '', displayName: ''}
record: Record<string, unknown> = {} record: Record<string, unknown> = {}
embed?: embed?:
| bsky.PostThreadView.RecordEmbed | GetPostThread.RecordEmbed
| bsky.PostThreadView.ExternalEmbed | GetPostThread.ExternalEmbed
| bsky.PostThreadView.UnknownEmbed | GetPostThread.UnknownEmbed
parent?: PostThreadViewPostModel parent?: PostThreadViewPostModel
replyCount: number = 0 replyCount: number = 0
replies?: PostThreadViewPostModel[] replies?: PostThreadViewPostModel[]
@ -45,7 +46,7 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
reactKey: string, reactKey: string,
v?: bsky.PostThreadView.Post, v?: GetPostThread.Post,
) { ) {
makeAutoObservable(this, {rootStore: false}) makeAutoObservable(this, {rootStore: false})
this._reactKey = reactKey this._reactKey = reactKey
@ -57,7 +58,7 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
} }
} }
assignTreeModels(keyGen: Generator<string>, v: bsky.PostThreadView.Post) { assignTreeModels(keyGen: Generator<string>, v: GetPostThread.Post) {
// parents // parents
if (v.parent) { if (v.parent) {
// TODO: validate .record // TODO: validate .record
@ -93,33 +94,37 @@ export class PostThreadViewPostModel implements bsky.PostThreadView.Post {
} }
async toggleLike() { async toggleLike() {
if (this.myState.hasLiked) { if (this.myState.like) {
await apilib.unlike(this.rootStore.api, 'alice.com', this.uri) await apilib.unlike(this.rootStore.api, 'alice.test', this.uri)
runInAction(() => { runInAction(() => {
this.likeCount-- this.likeCount--
this.myState.hasLiked = false this.myState.like = undefined
}) })
} else { } else {
await apilib.like(this.rootStore.api, 'alice.com', this.uri) const res = await apilib.like(this.rootStore.api, 'alice.test', this.uri)
runInAction(() => { runInAction(() => {
this.likeCount++ this.likeCount++
this.myState.hasLiked = true this.myState.like = res.uri
}) })
} }
} }
async toggleRepost() { async toggleRepost() {
if (this.myState.hasReposted) { if (this.myState.repost) {
await apilib.unrepost(this.rootStore.api, 'alice.com', this.uri) await apilib.unrepost(this.rootStore.api, 'alice.test', this.uri)
runInAction(() => { runInAction(() => {
this.repostCount-- this.repostCount--
this.myState.hasReposted = false this.myState.repost = undefined
}) })
} else { } else {
await apilib.repost(this.rootStore.api, 'alice.com', this.uri) const res = await apilib.repost(
this.rootStore.api,
'alice.test',
this.uri,
)
runInAction(() => { runInAction(() => {
this.repostCount++ this.repostCount++
this.myState.hasReposted = true this.myState.repost = res.uri
}) })
} }
} }
@ -132,14 +137,14 @@ export class PostThreadViewModel {
hasLoaded = false hasLoaded = false
error = '' error = ''
resolvedUri = '' resolvedUri = ''
params: bsky.PostThreadView.Params params: GetPostThread.QueryParams
// data // data
thread?: PostThreadViewPostModel thread?: PostThreadViewPostModel
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.PostThreadView.Params, params: GetPostThread.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -226,10 +231,9 @@ export class PostThreadViewModel {
private async _load(isRefreshing = false) { private async _load(isRefreshing = false) {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getPostThread(
'blueskyweb.xyz:PostThreadView',
Object.assign({}, this.params, {uri: this.resolvedUri}), Object.assign({}, this.params, {uri: this.resolvedUri}),
)) as bsky.PostThreadView.Response )
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -237,16 +241,16 @@ export class PostThreadViewModel {
} }
} }
private _replaceAll(res: bsky.PostThreadView.Response) { private _replaceAll(res: GetPostThread.Response) {
// TODO: validate .record // TODO: validate .record
const keyGen = reactKeyGenerator() const keyGen = reactKeyGenerator()
const thread = new PostThreadViewPostModel( const thread = new PostThreadViewPostModel(
this.rootStore, this.rootStore,
keyGen.next().value, keyGen.next().value,
res.thread, res.data.thread,
) )
thread._isHighlightedPost = true thread._isHighlightedPost = true
thread.assignTreeModels(keyGen, res.thread) thread.assignTreeModels(keyGen, res.data.thread)
this.thread = thread this.thread = thread
} }
} }

View File

@ -1,10 +1,18 @@
import {makeAutoObservable} from 'mobx' import {makeAutoObservable} from 'mobx'
import {bsky, AdxUri} from '@adxp/mock-api' import * as Post from '../../third-party/api/src/types/todo/social/post'
import {AdxUri} from '../../third-party/uri'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
export type PostEntities = bsky.Post.Record['entities'] export type PostEntities = Post.Record['entities']
export type PostReply = bsky.Post.Record['reply'] export type PostReply = Post.Record['reply']
export class PostModel implements bsky.Post.Record { type RemoveIndex<T> = {
[P in keyof T as string extends P
? never
: number extends P
? never
: P]: T[P]
}
export class PostModel implements RemoveIndex<Post.Record> {
// state // state
isLoading = false isLoading = false
hasLoaded = false hasLoaded = false
@ -70,13 +78,14 @@ export class PostModel implements bsky.Post.Record {
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const urip = new AdxUri(this.uri) const urip = new AdxUri(this.uri)
const res = await this.rootStore.api.mainPds const res = await this.rootStore.api.todo.social.post.get({
.repo(urip.host, false) nameOrDid: urip.host,
.collection(urip.collection) tid: urip.recordKey,
.get('Post', urip.recordKey) })
if (!res.valid) { // TODO
throw new Error(res.error) // if (!res.valid) {
} // throw new Error(res.error)
// }
this._replaceAll(res.value) this._replaceAll(res.value)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -84,7 +93,7 @@ export class PostModel implements bsky.Post.Record {
} }
} }
private _replaceAll(res: bsky.Post.Record) { private _replaceAll(res: Post.Record) {
this.text = res.text this.text = res.text
this.entities = res.entities this.entities = res.entities
this.reply = res.reply this.reply = res.reply

View File

@ -1,38 +1,39 @@
import {makeAutoObservable, runInAction} from 'mobx' import {makeAutoObservable, runInAction} from 'mobx'
import {bsky} from '@adxp/mock-api' import * as GetProfile from '../../third-party/api/src/types/todo/social/getProfile'
import * as Profile from '../../third-party/api/src/types/todo/social/profile'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
import * as apilib from '../lib/api' import * as apilib from '../lib/api'
export class ProfileViewMyStateModel { export class ProfileViewMyStateModel {
hasFollowed: boolean = false follow?: string
constructor() { constructor() {
makeAutoObservable(this) makeAutoObservable(this)
} }
} }
export class ProfileViewModel implements bsky.ProfileView.Response { export class ProfileViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
error = '' error = ''
params: bsky.ProfileView.Params params: GetProfile.QueryParams
// data // data
did: string = '' did: string = ''
name: string = '' name: string = ''
displayName: string = '' displayName?: string
description: string = '' description?: string
followersCount: number = 0 followersCount: number = 0
followsCount: number = 0 followsCount: number = 0
postsCount: number = 0 postsCount: number = 0
badges: bsky.ProfileView.Badge[] = [] badges: GetProfile.Badge[] = []
myState = new ProfileViewMyStateModel() myState = new ProfileViewMyStateModel()
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.ProfileView.Params, params: GetProfile.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -69,27 +70,31 @@ export class ProfileViewModel implements bsky.ProfileView.Response {
} }
async toggleFollowing() { async toggleFollowing() {
if (this.myState.hasFollowed) { if (!this.rootStore.me.did) {
await apilib.unfollow(this.rootStore.api, 'alice.com', { throw new Error('Not logged in')
}
if (this.myState.follow) {
await apilib.unfollow(this.rootStore.api, this.rootStore.me.did, {
did: this.did, did: this.did,
}) })
runInAction(() => { runInAction(() => {
this.followersCount-- this.followersCount--
this.myState.hasFollowed = false this.myState.follow = undefined
}) })
} else { } else {
await apilib.follow(this.rootStore.api, 'alice.com', { const res = await apilib.follow(
did: this.did, this.rootStore.api,
name: this.name, this.rootStore.me.did,
}) this.did,
)
runInAction(() => { runInAction(() => {
this.followersCount++ this.followersCount++
this.myState.hasFollowed = true this.myState.follow = res.uri
}) })
} }
} }
async updateProfile(profile: bsky.Profile.Record) { async updateProfile(profile: Profile.Record) {
if (this.did !== this.rootStore.me.did) { if (this.did !== this.rootStore.me.did) {
throw new Error('Not your profile!') throw new Error('Not your profile!')
} }
@ -120,10 +125,7 @@ export class ProfileViewModel implements bsky.ProfileView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getProfile(this.params)
'blueskyweb.xyz:ProfileView',
this.params,
)) as bsky.ProfileView.Response
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -131,17 +133,17 @@ export class ProfileViewModel implements bsky.ProfileView.Response {
} }
} }
private _replaceAll(res: bsky.ProfileView.Response) { private _replaceAll(res: GetProfile.Response) {
this.did = res.did this.did = res.data.did
this.name = res.name this.name = res.data.name
this.displayName = res.displayName this.displayName = res.data.displayName
this.description = res.description this.description = res.data.description
this.followersCount = res.followersCount this.followersCount = res.data.followersCount
this.followsCount = res.followsCount this.followsCount = res.data.followsCount
this.postsCount = res.postsCount this.postsCount = res.data.postsCount
this.badges = res.badges this.badges = res.data.badges
if (res.myState) { if (res.data.myState) {
Object.assign(this.myState, res.myState) Object.assign(this.myState, res.data.myState)
} }
} }
} }

View File

@ -1,8 +1,9 @@
import {makeAutoObservable, runInAction} from 'mobx' import {makeAutoObservable, runInAction} from 'mobx'
import {bsky, AdxUri} from '@adxp/mock-api' import {AdxUri} from '../../third-party/uri'
import * as GetRepostedBy from '../../third-party/api/src/types/todo/social/getRepostedBy'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
type RepostedByItem = bsky.RepostedByView.Response['repostedBy'][number] type RepostedByItem = GetRepostedBy.OutputSchema['repostedBy'][number]
export class RepostedByViewItemModel implements RepostedByItem { export class RepostedByViewItemModel implements RepostedByItem {
// ui state // ui state
@ -22,14 +23,14 @@ export class RepostedByViewItemModel implements RepostedByItem {
} }
} }
export class RepostedByViewModel implements bsky.RepostedByView.Response { export class RepostedByViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
error = '' error = ''
resolvedUri = '' resolvedUri = ''
params: bsky.RepostedByView.Params params: GetRepostedBy.QueryParams
// data // data
uri: string = '' uri: string = ''
@ -37,7 +38,7 @@ export class RepostedByViewModel implements bsky.RepostedByView.Response {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.RepostedByView.Params, params: GetRepostedBy.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -113,10 +114,9 @@ export class RepostedByViewModel implements bsky.RepostedByView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getRepostedBy(
'blueskyweb.xyz:RepostedByView',
Object.assign({}, this.params, {uri: this.resolvedUri}), Object.assign({}, this.params, {uri: this.resolvedUri}),
)) as bsky.RepostedByView.Response )
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -131,10 +131,10 @@ export class RepostedByViewModel implements bsky.RepostedByView.Response {
this._xIdle() this._xIdle()
} }
private _replaceAll(res: bsky.RepostedByView.Response) { private _replaceAll(res: GetRepostedBy.Response) {
this.repostedBy.length = 0 this.repostedBy.length = 0
let counter = 0 let counter = 0
for (const item of res.repostedBy) { for (const item of res.data.repostedBy) {
this._append(counter++, item) this._append(counter++, item)
} }
} }

View File

@ -3,7 +3,7 @@
*/ */
import {makeAutoObservable} from 'mobx' import {makeAutoObservable} from 'mobx'
import {adx, AdxClient} from '@adxp/mock-api' import AdxApi, {ServiceClient} from '../../third-party/api'
import {createContext, useContext} from 'react' import {createContext, useContext} from 'react'
import {isObj, hasProp} from '../lib/type-guards' import {isObj, hasProp} from '../lib/type-guards'
import {SessionModel} from './session' import {SessionModel} from './session'
@ -17,7 +17,7 @@ export class RootStoreModel {
shell = new ShellModel() shell = new ShellModel()
me = new MeModel(this) me = new MeModel(this)
constructor(public api: AdxClient) { constructor(public api: ServiceClient) {
makeAutoObservable(this, { makeAutoObservable(this, {
api: false, api: false,
resolveName: false, resolveName: false,
@ -27,9 +27,11 @@ export class RootStoreModel {
} }
async resolveName(didOrName: string) { async resolveName(didOrName: string) {
const userDb = this.api.mockDb.getUser(didOrName) throw new Error('TODO')
if (!userDb) throw new Error(`User not found: ${didOrName}`) return ''
return userDb.did // const userDb = this.api.mockDb.getUser(didOrName)
// if (!userDb) throw new Error(`User not found: ${didOrName}`)
// return userDb.did
} }
serialize(): unknown { serialize(): unknown {
@ -51,7 +53,7 @@ export class RootStoreModel {
} }
} }
const throwawayInst = new RootStoreModel(adx) // this will be replaced by the loader const throwawayInst = new RootStoreModel(AdxApi.service('http://localhost')) // this will be replaced by the loader
const RootStoreContext = createContext<RootStoreModel>(throwawayInst) const RootStoreContext = createContext<RootStoreModel>(throwawayInst)
export const RootStoreProvider = RootStoreContext.Provider export const RootStoreProvider = RootStoreContext.Provider
export const useStores = () => useContext(RootStoreContext) export const useStores = () => useContext(RootStoreContext)

View File

@ -1,18 +1,18 @@
import {makeAutoObservable} from 'mobx' import {makeAutoObservable} from 'mobx'
import {bsky} from '@adxp/mock-api' import * as GetUserFollowers from '../../third-party/api/src/types/todo/social/getUserFollowers'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
type Subject = bsky.UserFollowersView.Response['subject'] type Subject = GetUserFollowers.OutputSchema['subject']
export type FollowerItem = export type FollowerItem =
bsky.UserFollowersView.Response['followers'][number] & {_reactKey: string} GetUserFollowers.OutputSchema['followers'][number] & {_reactKey: string}
export class UserFollowersViewModel implements bsky.UserFollowersView.Response { export class UserFollowersViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
error = '' error = ''
params: bsky.UserFollowersView.Params params: GetUserFollowers.QueryParams
// data // data
subject: Subject = {did: '', name: '', displayName: ''} subject: Subject = {did: '', name: '', displayName: ''}
@ -20,7 +20,7 @@ export class UserFollowersViewModel implements bsky.UserFollowersView.Response {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.UserFollowersView.Params, params: GetUserFollowers.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -83,10 +83,9 @@ export class UserFollowersViewModel implements bsky.UserFollowersView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getUserFollowers(
'blueskyweb.xyz:UserFollowersView',
this.params, this.params,
)) as bsky.UserFollowersView.Response )
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -94,13 +93,13 @@ export class UserFollowersViewModel implements bsky.UserFollowersView.Response {
} }
} }
private _replaceAll(res: bsky.UserFollowersView.Response) { private _replaceAll(res: GetUserFollowers.Response) {
this.subject.did = res.subject.did this.subject.did = res.data.subject.did
this.subject.name = res.subject.name this.subject.name = res.data.subject.name
this.subject.displayName = res.subject.displayName this.subject.displayName = res.data.subject.displayName
this.followers.length = 0 this.followers.length = 0
let counter = 0 let counter = 0
for (const item of res.followers) { for (const item of res.data.followers) {
this._append({_reactKey: `item-${counter++}`, ...item}) this._append({_reactKey: `item-${counter++}`, ...item})
} }
} }

View File

@ -1,19 +1,19 @@
import {makeAutoObservable} from 'mobx' import {makeAutoObservable} from 'mobx'
import {bsky} from '@adxp/mock-api' import * as GetUserFollows from '../../third-party/api/src/types/todo/social/getUserFollows'
import {RootStoreModel} from './root-store' import {RootStoreModel} from './root-store'
type Subject = bsky.UserFollowsView.Response['subject'] type Subject = GetUserFollows.OutputSchema['subject']
export type FollowItem = bsky.UserFollowsView.Response['follows'][number] & { export type FollowItem = GetUserFollows.OutputSchema['follows'][number] & {
_reactKey: string _reactKey: string
} }
export class UserFollowsViewModel implements bsky.UserFollowsView.Response { export class UserFollowsViewModel {
// state // state
isLoading = false isLoading = false
isRefreshing = false isRefreshing = false
hasLoaded = false hasLoaded = false
error = '' error = ''
params: bsky.UserFollowsView.Params params: GetUserFollows.QueryParams
// data // data
subject: Subject = {did: '', name: '', displayName: ''} subject: Subject = {did: '', name: '', displayName: ''}
@ -21,7 +21,7 @@ export class UserFollowsViewModel implements bsky.UserFollowsView.Response {
constructor( constructor(
public rootStore: RootStoreModel, public rootStore: RootStoreModel,
params: bsky.UserFollowsView.Params, params: GetUserFollows.QueryParams,
) { ) {
makeAutoObservable( makeAutoObservable(
this, this,
@ -84,10 +84,9 @@ export class UserFollowsViewModel implements bsky.UserFollowsView.Response {
this._xLoading(isRefreshing) this._xLoading(isRefreshing)
await new Promise(r => setTimeout(r, 250)) // DEBUG await new Promise(r => setTimeout(r, 250)) // DEBUG
try { try {
const res = (await this.rootStore.api.mainPds.view( const res = await this.rootStore.api.todo.social.getUserFollows(
'blueskyweb.xyz:UserFollowsView',
this.params, this.params,
)) as bsky.UserFollowsView.Response )
this._replaceAll(res) this._replaceAll(res)
this._xIdle() this._xIdle()
} catch (e: any) { } catch (e: any) {
@ -95,13 +94,13 @@ export class UserFollowsViewModel implements bsky.UserFollowsView.Response {
} }
} }
private _replaceAll(res: bsky.UserFollowsView.Response) { private _replaceAll(res: GetUserFollows.Response) {
this.subject.did = res.subject.did this.subject.did = res.data.subject.did
this.subject.name = res.subject.name this.subject.name = res.data.subject.name
this.subject.displayName = res.subject.displayName this.subject.displayName = res.data.subject.displayName
this.follows.length = 0 this.follows.length = 0
let counter = 0 let counter = 0
for (const item of res.follows) { for (const item of res.data.follows) {
this._append({_reactKey: `item-${counter++}`, ...item}) this._append({_reactKey: `item-${counter++}`, ...item})
} }
} }

12002
src/third-party/api/index.js vendored 100644

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,24 @@
export declare enum ErrorCode {
NetworkError = "NetworkError",
DidResolutionFailed = "DidResolutionFailed",
NameResolutionFailed = "NameResolutionFailed"
}
export declare class NameResolutionFailed extends Error {
code: ErrorCode;
constructor(name: string);
}
export declare class DidResolutionFailed extends Error {
code: ErrorCode;
constructor(did: string);
}
export declare class WritePermissionError extends Error {
constructor();
}
export declare class APIResponseError extends Error {
httpStatusCode: number;
httpStatusText: string;
httpHeaders?: Record<string, string> | undefined;
httpResponseBody?: any;
constructor(httpStatusCode: number, httpStatusText: string, httpHeaders?: Record<string, string> | undefined, httpResponseBody?: any);
get code(): ErrorCode;
}

View File

@ -0,0 +1,180 @@
import { z } from 'zod';
export declare const getRepoRequest: z.ZodObject<{
did: z.ZodString;
from: z.ZodOptional<z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, import("multiformats/cid").CID, string>>;
}, "strip", z.ZodTypeAny, {
from?: import("multiformats/cid").CID | undefined;
did: string;
}, {
from?: string | undefined;
did: string;
}>;
export declare type GetRepoRequest = z.infer<typeof getRepoRequest>;
export declare const postRepoRequest: z.ZodObject<{
did: z.ZodString;
}, "strip", z.ZodTypeAny, {
did: string;
}, {
did: string;
}>;
export declare type PostRepoRequest = z.infer<typeof postRepoRequest>;
export declare const describeRepoParams: z.ZodObject<{
confirmName: z.ZodOptional<z.ZodBoolean>;
}, "strip", z.ZodTypeAny, {
confirmName?: boolean | undefined;
}, {
confirmName?: boolean | undefined;
}>;
export declare type DescribeRepoParams = z.infer<typeof describeRepoParams>;
export declare const describeRepoResponse: z.ZodObject<{
name: z.ZodString;
did: z.ZodString;
didDoc: z.ZodAny;
collections: z.ZodArray<z.ZodString, "many">;
nameIsCorrect: z.ZodOptional<z.ZodBoolean>;
}, "strip", z.ZodTypeAny, {
didDoc?: any;
nameIsCorrect?: boolean | undefined;
name: string;
did: string;
collections: string[];
}, {
didDoc?: any;
nameIsCorrect?: boolean | undefined;
name: string;
did: string;
collections: string[];
}>;
export declare type DescribeRepoResponse = z.infer<typeof describeRepoResponse>;
export declare const listRecordsParams: z.ZodObject<{
limit: z.ZodOptional<z.ZodUnion<[z.ZodNumber, z.ZodEffects<z.ZodEffects<z.ZodString, string, string>, number, string>]>>;
before: z.ZodOptional<z.ZodString>;
after: z.ZodOptional<z.ZodString>;
reverse: z.ZodOptional<z.ZodEffects<z.ZodString, boolean, string>>;
}, "strip", z.ZodTypeAny, {
reverse?: boolean | undefined;
limit?: number | undefined;
before?: string | undefined;
after?: string | undefined;
}, {
reverse?: string | undefined;
limit?: string | number | undefined;
before?: string | undefined;
after?: string | undefined;
}>;
export declare type ListRecordsParams = z.infer<typeof listRecordsParams>;
export declare const listRecordsResponse: z.ZodObject<{
records: z.ZodArray<z.ZodObject<{
uri: z.ZodString;
value: z.ZodAny;
}, "strip", z.ZodTypeAny, {
value?: any;
uri: string;
}, {
value?: any;
uri: string;
}>, "many">;
}, "strip", z.ZodTypeAny, {
records: {
value?: any;
uri: string;
}[];
}, {
records: {
value?: any;
uri: string;
}[];
}>;
export declare type ListRecordsResponse = z.infer<typeof listRecordsResponse>;
export declare const getRecordResponse: z.ZodObject<{
uri: z.ZodString;
value: z.ZodAny;
}, "strip", z.ZodTypeAny, {
value?: any;
uri: string;
}, {
value?: any;
uri: string;
}>;
export declare type GetRecordResponse = z.infer<typeof getRecordResponse>;
export declare const batchWriteParams: z.ZodObject<{
writes: z.ZodArray<z.ZodUnion<[z.ZodObject<{
action: z.ZodLiteral<"create">;
collection: z.ZodString;
value: z.ZodAny;
}, "strip", z.ZodTypeAny, {
value?: any;
action: "create";
collection: string;
}, {
value?: any;
action: "create";
collection: string;
}>, z.ZodObject<{
action: z.ZodLiteral<"update">;
collection: z.ZodString;
tid: z.ZodString;
value: z.ZodAny;
}, "strip", z.ZodTypeAny, {
value?: any;
action: "update";
collection: string;
tid: string;
}, {
value?: any;
action: "update";
collection: string;
tid: string;
}>, z.ZodObject<{
action: z.ZodLiteral<"delete">;
collection: z.ZodString;
tid: z.ZodString;
}, "strip", z.ZodTypeAny, {
action: "delete";
collection: string;
tid: string;
}, {
action: "delete";
collection: string;
tid: string;
}>]>, "many">;
}, "strip", z.ZodTypeAny, {
writes: ({
value?: any;
action: "create";
collection: string;
} | {
value?: any;
action: "update";
collection: string;
tid: string;
} | {
action: "delete";
collection: string;
tid: string;
})[];
}, {
writes: ({
value?: any;
action: "create";
collection: string;
} | {
value?: any;
action: "update";
collection: string;
tid: string;
} | {
action: "delete";
collection: string;
tid: string;
})[];
}>;
export declare type BatchWriteParams = z.infer<typeof batchWriteParams>;
export declare const createRecordResponse: z.ZodObject<{
uri: z.ZodString;
}, "strip", z.ZodTypeAny, {
uri: string;
}, {
uri: string;
}>;
export declare type CreateRecordResponse = z.infer<typeof createRecordResponse>;

View File

@ -0,0 +1,239 @@
import { Client as XrpcClient, ServiceClient as XrpcServiceClient } from '@adxp/xrpc';
import * as TodoAdxCreateAccount from './types/todo/adx/createAccount';
import * as TodoAdxCreateSession from './types/todo/adx/createSession';
import * as TodoAdxDeleteAccount from './types/todo/adx/deleteAccount';
import * as TodoAdxDeleteSession from './types/todo/adx/deleteSession';
import * as TodoAdxGetAccount from './types/todo/adx/getAccount';
import * as TodoAdxGetSession from './types/todo/adx/getSession';
import * as TodoAdxRepoBatchWrite from './types/todo/adx/repoBatchWrite';
import * as TodoAdxRepoCreateRecord from './types/todo/adx/repoCreateRecord';
import * as TodoAdxRepoDeleteRecord from './types/todo/adx/repoDeleteRecord';
import * as TodoAdxRepoDescribe from './types/todo/adx/repoDescribe';
import * as TodoAdxRepoGetRecord from './types/todo/adx/repoGetRecord';
import * as TodoAdxRepoListRecords from './types/todo/adx/repoListRecords';
import * as TodoAdxRepoPutRecord from './types/todo/adx/repoPutRecord';
import * as TodoAdxResolveName from './types/todo/adx/resolveName';
import * as TodoAdxSyncGetRepo from './types/todo/adx/syncGetRepo';
import * as TodoAdxSyncGetRoot from './types/todo/adx/syncGetRoot';
import * as TodoAdxSyncUpdateRepo from './types/todo/adx/syncUpdateRepo';
import * as TodoSocialBadge from './types/todo/social/badge';
import * as TodoSocialFollow from './types/todo/social/follow';
import * as TodoSocialGetFeed from './types/todo/social/getFeed';
import * as TodoSocialGetLikedBy from './types/todo/social/getLikedBy';
import * as TodoSocialGetNotifications from './types/todo/social/getNotifications';
import * as TodoSocialGetPostThread from './types/todo/social/getPostThread';
import * as TodoSocialGetProfile from './types/todo/social/getProfile';
import * as TodoSocialGetRepostedBy from './types/todo/social/getRepostedBy';
import * as TodoSocialGetUserFollowers from './types/todo/social/getUserFollowers';
import * as TodoSocialGetUserFollows from './types/todo/social/getUserFollows';
import * as TodoSocialLike from './types/todo/social/like';
import * as TodoSocialMediaEmbed from './types/todo/social/mediaEmbed';
import * as TodoSocialPost from './types/todo/social/post';
import * as TodoSocialProfile from './types/todo/social/profile';
import * as TodoSocialRepost from './types/todo/social/repost';
export declare class Client {
xrpc: XrpcClient;
constructor();
service(serviceUri: string | URL): ServiceClient;
}
declare const defaultInst: Client;
export default defaultInst;
export declare class ServiceClient {
_baseClient: Client;
xrpc: XrpcServiceClient;
todo: TodoNS;
constructor(baseClient: Client, xrpcService: XrpcServiceClient);
}
export declare class TodoNS {
_service: ServiceClient;
adx: AdxNS;
social: SocialNS;
constructor(service: ServiceClient);
}
export declare class AdxNS {
_service: ServiceClient;
constructor(service: ServiceClient);
createAccount(params: TodoAdxCreateAccount.QueryParams, data?: TodoAdxCreateAccount.InputSchema, opts?: TodoAdxCreateAccount.CallOptions): Promise<TodoAdxCreateAccount.Response>;
createSession(params: TodoAdxCreateSession.QueryParams, data?: TodoAdxCreateSession.InputSchema, opts?: TodoAdxCreateSession.CallOptions): Promise<TodoAdxCreateSession.Response>;
deleteAccount(params: TodoAdxDeleteAccount.QueryParams, data?: TodoAdxDeleteAccount.InputSchema, opts?: TodoAdxDeleteAccount.CallOptions): Promise<TodoAdxDeleteAccount.Response>;
deleteSession(params: TodoAdxDeleteSession.QueryParams, data?: TodoAdxDeleteSession.InputSchema, opts?: TodoAdxDeleteSession.CallOptions): Promise<TodoAdxDeleteSession.Response>;
getAccount(params: TodoAdxGetAccount.QueryParams, data?: TodoAdxGetAccount.InputSchema, opts?: TodoAdxGetAccount.CallOptions): Promise<TodoAdxGetAccount.Response>;
getSession(params: TodoAdxGetSession.QueryParams, data?: TodoAdxGetSession.InputSchema, opts?: TodoAdxGetSession.CallOptions): Promise<TodoAdxGetSession.Response>;
repoBatchWrite(params: TodoAdxRepoBatchWrite.QueryParams, data?: TodoAdxRepoBatchWrite.InputSchema, opts?: TodoAdxRepoBatchWrite.CallOptions): Promise<TodoAdxRepoBatchWrite.Response>;
repoCreateRecord(params: TodoAdxRepoCreateRecord.QueryParams, data?: TodoAdxRepoCreateRecord.InputSchema, opts?: TodoAdxRepoCreateRecord.CallOptions): Promise<TodoAdxRepoCreateRecord.Response>;
repoDeleteRecord(params: TodoAdxRepoDeleteRecord.QueryParams, data?: TodoAdxRepoDeleteRecord.InputSchema, opts?: TodoAdxRepoDeleteRecord.CallOptions): Promise<TodoAdxRepoDeleteRecord.Response>;
repoDescribe(params: TodoAdxRepoDescribe.QueryParams, data?: TodoAdxRepoDescribe.InputSchema, opts?: TodoAdxRepoDescribe.CallOptions): Promise<TodoAdxRepoDescribe.Response>;
repoGetRecord(params: TodoAdxRepoGetRecord.QueryParams, data?: TodoAdxRepoGetRecord.InputSchema, opts?: TodoAdxRepoGetRecord.CallOptions): Promise<TodoAdxRepoGetRecord.Response>;
repoListRecords(params: TodoAdxRepoListRecords.QueryParams, data?: TodoAdxRepoListRecords.InputSchema, opts?: TodoAdxRepoListRecords.CallOptions): Promise<TodoAdxRepoListRecords.Response>;
repoPutRecord(params: TodoAdxRepoPutRecord.QueryParams, data?: TodoAdxRepoPutRecord.InputSchema, opts?: TodoAdxRepoPutRecord.CallOptions): Promise<TodoAdxRepoPutRecord.Response>;
resolveName(params: TodoAdxResolveName.QueryParams, data?: TodoAdxResolveName.InputSchema, opts?: TodoAdxResolveName.CallOptions): Promise<TodoAdxResolveName.Response>;
syncGetRepo(params: TodoAdxSyncGetRepo.QueryParams, data?: TodoAdxSyncGetRepo.InputSchema, opts?: TodoAdxSyncGetRepo.CallOptions): Promise<TodoAdxSyncGetRepo.Response>;
syncGetRoot(params: TodoAdxSyncGetRoot.QueryParams, data?: TodoAdxSyncGetRoot.InputSchema, opts?: TodoAdxSyncGetRoot.CallOptions): Promise<TodoAdxSyncGetRoot.Response>;
syncUpdateRepo(params: TodoAdxSyncUpdateRepo.QueryParams, data?: TodoAdxSyncUpdateRepo.InputSchema, opts?: TodoAdxSyncUpdateRepo.CallOptions): Promise<TodoAdxSyncUpdateRepo.Response>;
}
export declare class SocialNS {
_service: ServiceClient;
badge: BadgeRecord;
follow: FollowRecord;
like: LikeRecord;
mediaEmbed: MediaEmbedRecord;
post: PostRecord;
profile: ProfileRecord;
repost: RepostRecord;
constructor(service: ServiceClient);
getFeed(params: TodoSocialGetFeed.QueryParams, data?: TodoSocialGetFeed.InputSchema, opts?: TodoSocialGetFeed.CallOptions): Promise<TodoSocialGetFeed.Response>;
getLikedBy(params: TodoSocialGetLikedBy.QueryParams, data?: TodoSocialGetLikedBy.InputSchema, opts?: TodoSocialGetLikedBy.CallOptions): Promise<TodoSocialGetLikedBy.Response>;
getNotifications(params: TodoSocialGetNotifications.QueryParams, data?: TodoSocialGetNotifications.InputSchema, opts?: TodoSocialGetNotifications.CallOptions): Promise<TodoSocialGetNotifications.Response>;
getPostThread(params: TodoSocialGetPostThread.QueryParams, data?: TodoSocialGetPostThread.InputSchema, opts?: TodoSocialGetPostThread.CallOptions): Promise<TodoSocialGetPostThread.Response>;
getProfile(params: TodoSocialGetProfile.QueryParams, data?: TodoSocialGetProfile.InputSchema, opts?: TodoSocialGetProfile.CallOptions): Promise<TodoSocialGetProfile.Response>;
getRepostedBy(params: TodoSocialGetRepostedBy.QueryParams, data?: TodoSocialGetRepostedBy.InputSchema, opts?: TodoSocialGetRepostedBy.CallOptions): Promise<TodoSocialGetRepostedBy.Response>;
getUserFollowers(params: TodoSocialGetUserFollowers.QueryParams, data?: TodoSocialGetUserFollowers.InputSchema, opts?: TodoSocialGetUserFollowers.CallOptions): Promise<TodoSocialGetUserFollowers.Response>;
getUserFollows(params: TodoSocialGetUserFollows.QueryParams, data?: TodoSocialGetUserFollows.InputSchema, opts?: TodoSocialGetUserFollows.CallOptions): Promise<TodoSocialGetUserFollows.Response>;
}
export declare class BadgeRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialBadge.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialBadge.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialBadge.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialBadge.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}
export declare class FollowRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialFollow.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialFollow.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialFollow.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialFollow.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}
export declare class LikeRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialLike.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialLike.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialLike.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialLike.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}
export declare class MediaEmbedRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialMediaEmbed.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialMediaEmbed.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialMediaEmbed.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialMediaEmbed.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}
export declare class PostRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialPost.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialPost.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialPost.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialPost.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}
export declare class ProfileRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialProfile.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialProfile.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialProfile.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialProfile.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}
export declare class RepostRecord {
_service: ServiceClient;
constructor(service: ServiceClient);
list(params: Omit<TodoAdxRepoListRecords.QueryParams, 'type'>): Promise<{
records: {
uri: string;
value: TodoSocialRepost.Record;
}[];
}>;
get(params: Omit<TodoAdxRepoGetRecord.QueryParams, 'type'>): Promise<{
uri: string;
value: TodoSocialRepost.Record;
}>;
create(params: Omit<TodoAdxRepoCreateRecord.QueryParams, 'type'>, record: TodoSocialRepost.Record): Promise<{
uri: string;
}>;
put(params: Omit<TodoAdxRepoPutRecord.QueryParams, 'type'>, record: TodoSocialRepost.Record): Promise<{
uri: string;
}>;
delete(params: Omit<TodoAdxRepoDeleteRecord.QueryParams, 'type'>): Promise<void>;
}

View File

@ -0,0 +1,3 @@
import { MethodSchema, RecordSchema } from '@adxp/lexicon';
export declare const methodSchemas: MethodSchema[];
export declare const recordSchemas: RecordSchema[];

View File

@ -0,0 +1,28 @@
import { AdxRecordValidator, AdxRecordValidatorDescription } from '@adxp/schemas';
import { GetRecordResponse } from './http-types.js';
export declare type SchemaOpt = string | string[] | AdxRecordValidator | AdxRecordValidatorDescription | '*';
export interface AdxClientOpts {
pds?: string;
locale?: string;
schemas?: any[];
}
export interface RegisterRepoParams {
did: string;
username: string;
}
export interface GetRecordResponseValidated extends GetRecordResponse {
valid?: boolean;
fullySupported?: boolean;
compatible?: boolean;
error?: string | undefined;
fallbacks?: string[] | undefined;
}
export interface ListRecordsResponseValidated {
records: GetRecordResponseValidated[];
}
export interface BatchWrite {
action: 'create' | 'put' | 'del';
collection: string;
key?: string;
value?: any;
}

View File

@ -0,0 +1,17 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
data: InputSchema;
}
export interface InputSchema {
username: string;
did: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,35 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
validate?: boolean;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
data: InputSchema;
}
export interface InputSchema {
writes: ({
action: 'create';
collection: string;
value: unknown;
} | {
action: 'update';
collection: string;
tid: string;
value: unknown;
} | {
action: 'delete';
collection: string;
tid: string;
})[];
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,23 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
type: string;
validate?: boolean;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
uri: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,14 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
type: string;
tid: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
nameOrDid: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
name: string;
did: string;
didDoc: {};
collections: string[];
nameIsCorrect: boolean;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,19 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
nameOrDid: string;
type: string;
tid: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
uri: string;
value: {};
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,24 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
nameOrDid: string;
type: string;
limit?: number;
before?: string;
after?: string;
reverse?: boolean;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
records: {
uri: string;
value: {};
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,24 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
type: string;
tid: string;
validate?: boolean;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
data: InputSchema;
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
uri: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,16 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
name: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
did: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,14 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
from?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: Uint8Array;
}

View File

@ -0,0 +1,16 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
root: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,14 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/cbor';
data: Uint8Array;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
}

View File

@ -0,0 +1,16 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
}
export interface InputSchema {
username: string;
did: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
}

View File

@ -0,0 +1,19 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,19 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,19 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,19 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,19 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
}
export interface CallOptions {
headers?: Headers;
encoding: '';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,34 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
validate?: boolean;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
}
export interface InputSchema {
writes: ({
action: 'create';
collection: string;
value: unknown;
} | {
action: 'update';
collection: string;
tid: string;
value: unknown;
} | {
action: 'delete';
collection: string;
tid: string;
})[];
}
export interface OutputSchema {
[k: string]: unknown;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,22 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
type: string;
validate?: boolean;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
uri: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,15 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
type: string;
tid: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
}

View File

@ -0,0 +1,21 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
nameOrDid: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
name: string;
did: string;
didDoc: {};
collections: string[];
nameIsCorrect: boolean;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,20 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
nameOrDid: string;
type: string;
tid: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
uri: string;
value: {};
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,25 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
nameOrDid: string;
type: string;
limit?: number;
before?: string;
after?: string;
reverse?: boolean;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
records: {
uri: string;
value: {};
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,23 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
type: string;
tid: string;
validate?: boolean;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/json';
}
export interface InputSchema {
[k: string]: unknown;
}
export interface OutputSchema {
uri: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,17 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
name?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
did: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,15 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
from?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: Uint8Array;
}

View File

@ -0,0 +1,17 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
root: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,14 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
did: string;
}
export interface CallOptions {
headers?: Headers;
encoding: 'application/cbor';
}
export declare type InputSchema = string | Uint8Array;
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
}

View File

@ -0,0 +1,23 @@
export interface Record {
assertion: InviteAssertion | EmployeeAssertion | TagAssertion | UnknownAssertion;
subject: string;
createdAt: string;
[k: string]: unknown;
}
export interface InviteAssertion {
type: 'invite';
[k: string]: unknown;
}
export interface EmployeeAssertion {
type: 'employee';
[k: string]: unknown;
}
export interface TagAssertion {
type: 'tag';
tag: string;
[k: string]: unknown;
}
export interface UnknownAssertion {
type: string;
[k: string]: unknown;
}

View File

@ -0,0 +1,5 @@
export interface Record {
subject: string;
createdAt: string;
[k: string]: unknown;
}

View File

@ -0,0 +1,54 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
author?: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
feed: FeedItem[];
}
export interface FeedItem {
uri: string;
author: User;
repostedBy?: User;
record: {};
embed?: RecordEmbed | ExternalEmbed | UnknownEmbed;
replyCount: number;
repostCount: number;
likeCount: number;
indexedAt: string;
myState?: {
repost?: string;
like?: string;
};
}
export interface User {
did: string;
name: string;
displayName?: string;
}
export interface RecordEmbed {
type: 'record';
author: User;
record: {};
}
export interface ExternalEmbed {
type: 'external';
uri: string;
title: string;
description: string;
imageUri: string;
}
export interface UnknownEmbed {
type: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,15 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
author?: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: Uint8Array;
}

View File

@ -0,0 +1,26 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
uri: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
uri: string;
likedBy: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,25 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
uri: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
uri: string;
likedBy: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,29 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
notifications: Notification[];
}
export interface Notification {
uri: string;
author: {
did: string;
name: string;
displayName: string;
};
record: {};
isRead: boolean;
indexedAt: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,28 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
notifications: Notification[];
}
export interface Notification {
uri: string;
author: {
did: string;
name: string;
displayName: string;
};
record: {};
isRead: boolean;
indexedAt: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,54 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
uri: string;
depth?: number;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
thread: Post;
}
export interface Post {
uri: string;
author: User;
record: {};
embed?: RecordEmbed | ExternalEmbed | UnknownEmbed;
parent?: Post;
replyCount: number;
replies?: Post[];
likeCount: number;
repostCount: number;
indexedAt: string;
myState?: {
repost?: string;
like?: string;
};
}
export interface User {
did: string;
name: string;
displayName?: string;
}
export interface RecordEmbed {
type: 'record';
author: User;
record: {};
}
export interface ExternalEmbed {
type: 'external';
uri: string;
title: string;
description: string;
imageUri: string;
}
export interface UnknownEmbed {
type: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,53 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
uri: string;
depth?: number;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
thread: Post;
}
export interface Post {
uri: string;
author: User;
record: {};
embed?: RecordEmbed | ExternalEmbed | UnknownEmbed;
parent?: Post;
replyCount: number;
replies?: Post[];
likeCount: number;
repostCount: number;
indexedAt: string;
myState?: {
repost?: string;
like?: string;
};
}
export interface User {
did: string;
name: string;
displayName?: string;
}
export interface RecordEmbed {
type: 'record';
author: User;
record: {};
}
export interface ExternalEmbed {
type: 'external';
uri: string;
title: string;
description: string;
imageUri: string;
}
export interface UnknownEmbed {
type: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,40 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
user: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
did: string;
name: string;
displayName?: string;
description?: string;
followersCount: number;
followsCount: number;
postsCount: number;
badges: Badge[];
myState?: {
follow?: string;
};
}
export interface Badge {
uri: string;
error?: string;
issuer?: {
did: string;
name: string;
displayName: string;
};
assertion?: {
type: string;
};
createdAt?: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,39 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
user: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
did: string;
name: string;
displayName?: string;
description?: string;
followersCount: number;
followsCount: number;
postsCount: number;
badges: Badge[];
myState?: {
follow?: string;
};
}
export interface Badge {
uri: string;
error?: string;
issuer?: {
did: string;
name: string;
displayName: string;
};
assertion?: {
type: string;
};
createdAt?: string;
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,26 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
uri: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
uri: string;
repostedBy: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,25 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
uri: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
uri: string;
repostedBy: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,30 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
user: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
subject: {
did: string;
name: string;
displayName?: string;
};
followers: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,29 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
user: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
subject: {
did: string;
name: string;
displayName?: string;
};
followers: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,30 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
user: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export declare type InputSchema = undefined;
export interface OutputSchema {
subject: {
did: string;
name: string;
displayName?: string;
};
follows: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,29 @@
import { Headers } from '@adxp/xrpc';
export interface QueryParams {
user: string;
limit?: number;
before?: string;
}
export interface CallOptions {
headers?: Headers;
}
export interface OutputSchema {
subject: {
did: string;
name: string;
displayName?: string;
};
follows: {
did: string;
name: string;
displayName?: string;
createdAt?: string;
indexedAt: string;
}[];
}
export interface Response {
success: boolean;
error: boolean;
headers: Headers;
data: OutputSchema;
}

View File

@ -0,0 +1,5 @@
export interface Record {
subject: string;
createdAt: string;
[k: string]: unknown;
}

View File

@ -0,0 +1,15 @@
export interface Record {
media: MediaEmbed[];
[k: string]: unknown;
}
export interface MediaEmbed {
alt?: string;
thumb?: MediaEmbedBlob;
original: MediaEmbedBlob;
[k: string]: unknown;
}
export interface MediaEmbedBlob {
mimeType: string;
blobId: string;
[k: string]: unknown;
}

View File

@ -0,0 +1,18 @@
export declare type TextSlice = [number, number];
export declare type Entity = {
index: TextSlice;
type: string;
value: string;
[k: string]: unknown;
}[];
export interface Record {
text: string;
entities?: Entity;
reply?: {
root: string;
parent?: string;
[k: string]: unknown;
};
createdAt: string;
[k: string]: unknown;
}

View File

@ -0,0 +1,10 @@
export interface Record {
displayName: string;
description?: string;
badges?: BadgeRef[];
[k: string]: unknown;
}
export interface BadgeRef {
uri: string;
[k: string]: unknown;
}

View File

@ -0,0 +1,5 @@
export interface Record {
subject: string;
createdAt: string;
[k: string]: unknown;
}

File diff suppressed because one or more lines are too long

136
src/third-party/uri/index.js vendored 100644
View File

@ -0,0 +1,136 @@
"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
// src/index.ts
var src_exports = {};
__export(src_exports, {
ADX_URI_REGEX: () => ADX_URI_REGEX,
AdxUri: () => AdxUri
});
module.exports = __toCommonJS(src_exports);
var ADX_URI_REGEX = /^(adx:\/\/)?((?:did:[a-z0-9:%-]+)|(?:[a-z][a-z0-9.:-]*))(\/[^?#\s]*)?(\?[^#\s]+)?(#[^\s]+)?$/i;
var RELATIVE_REGEX = /^(\/[^?#\s]*)?(\?[^#\s]+)?(#[^\s]+)?$/i;
var AdxUri = class {
constructor(uri, base) {
let parsed;
if (base) {
parsed = parse(base);
if (!parsed) {
throw new Error(`Invalid adx uri: ${base}`);
}
const relativep = parseRelative(uri);
if (!relativep) {
throw new Error(`Invalid path: ${uri}`);
}
Object.assign(parsed, relativep);
} else {
parsed = parse(uri);
if (!parsed) {
throw new Error(`Invalid adx uri: ${uri}`);
}
}
this.hash = parsed.hash;
this.host = parsed.host;
this.pathname = parsed.pathname;
this.searchParams = parsed.searchParams;
}
get protocol() {
return "adx:";
}
get origin() {
return `adx://${this.host}`;
}
get hostname() {
return this.host;
}
set hostname(v) {
this.host = v;
}
get search() {
return this.searchParams.toString();
}
set search(v) {
this.searchParams = new URLSearchParams(v);
}
get collection() {
return this.pathname.split("/").filter(Boolean)[0] || "";
}
set collection(v) {
const parts = this.pathname.split("/").filter(Boolean);
parts[0] = v;
this.pathname = parts.join("/");
}
get recordKey() {
return this.pathname.split("/").filter(Boolean)[1] || "";
}
set recordKey(v) {
const parts = this.pathname.split("/").filter(Boolean);
if (!parts[0])
parts[0] = "undefined";
parts[1] = v;
this.pathname = parts.join("/");
}
get href() {
return this.toString();
}
toString() {
let path = this.pathname || "/";
if (!path.startsWith("/")) {
path = `/${path}`;
}
let qs = this.searchParams.toString();
if (qs && !qs.startsWith("?")) {
qs = `?${qs}`;
}
let hash = this.hash;
if (hash && !hash.startsWith("#")) {
hash = `#${hash}`;
}
return `adx://${this.host}${path}${qs}${hash}`;
}
};
function parse(str) {
const match = ADX_URI_REGEX.exec(str);
if (match) {
return {
hash: match[5] || "",
host: match[2] || "",
pathname: match[3] || "",
searchParams: new URLSearchParams(match[4] || "")
};
}
return void 0;
}
function parseRelative(str) {
const match = RELATIVE_REGEX.exec(str);
if (match) {
return {
hash: match[3] || "",
pathname: match[1] || "",
searchParams: new URLSearchParams(match[2] || "")
};
}
return void 0;
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
ADX_URI_REGEX,
AdxUri
});
//# sourceMappingURL=index.js.map

View File

@ -0,0 +1,7 @@
{
"version": 3,
"sources": ["../src/index.ts"],
"sourcesContent": ["export const ADX_URI_REGEX =\n // protocol- --did-------------- --name------------- --path---- --query-- --hash--\n /^(adx:\\/\\/)?((?:did:[a-z0-9:%-]+)|(?:[a-z][a-z0-9.:-]*))(\\/[^?#\\s]*)?(\\?[^#\\s]+)?(#[^\\s]+)?$/i\n// --path----- --query-- --hash--\nconst RELATIVE_REGEX = /^(\\/[^?#\\s]*)?(\\?[^#\\s]+)?(#[^\\s]+)?$/i\n\nexport class AdxUri {\n hash: string\n host: string\n pathname: string\n searchParams: URLSearchParams\n\n constructor(uri: string, base?: string) {\n let parsed\n if (base) {\n parsed = parse(base)\n if (!parsed) {\n throw new Error(`Invalid adx uri: ${base}`)\n }\n const relativep = parseRelative(uri)\n if (!relativep) {\n throw new Error(`Invalid path: ${uri}`)\n }\n Object.assign(parsed, relativep)\n } else {\n parsed = parse(uri)\n if (!parsed) {\n throw new Error(`Invalid adx uri: ${uri}`)\n }\n }\n\n this.hash = parsed.hash\n this.host = parsed.host\n this.pathname = parsed.pathname\n this.searchParams = parsed.searchParams\n }\n\n get protocol() {\n return 'adx:'\n }\n\n get origin() {\n return `adx://${this.host}`\n }\n\n get hostname() {\n return this.host\n }\n\n set hostname(v: string) {\n this.host = v\n }\n\n get search() {\n return this.searchParams.toString()\n }\n\n set search(v: string) {\n this.searchParams = new URLSearchParams(v)\n }\n\n get collection() {\n return this.pathname.split('/').filter(Boolean)[0] || ''\n }\n\n set collection(v: string) {\n const parts = this.pathname.split('/').filter(Boolean)\n parts[0] = v\n this.pathname = parts.join('/')\n }\n\n get recordKey() {\n return this.pathname.split('/').filter(Boolean)[1] || ''\n }\n\n set recordKey(v: string) {\n const parts = this.pathname.split('/').filter(Boolean)\n if (!parts[0]) parts[0] = 'undefined'\n parts[1] = v\n this.pathname = parts.join('/')\n }\n\n get href() {\n return this.toString()\n }\n\n toString() {\n let path = this.pathname || '/'\n if (!path.startsWith('/')) {\n path = `/${path}`\n }\n let qs = this.searchParams.toString()\n if (qs && !qs.startsWith('?')) {\n qs = `?${qs}`\n }\n let hash = this.hash\n if (hash && !hash.startsWith('#')) {\n hash = `#${hash}`\n }\n return `adx://${this.host}${path}${qs}${hash}`\n }\n}\n\nfunction parse(str: string) {\n const match = ADX_URI_REGEX.exec(str)\n if (match) {\n return {\n hash: match[5] || '',\n host: match[2] || '',\n pathname: match[3] || '',\n searchParams: new URLSearchParams(match[4] || ''),\n }\n }\n return undefined\n}\n\nfunction parseRelative(str: string) {\n const match = RELATIVE_REGEX.exec(str)\n if (match) {\n return {\n hash: match[3] || '',\n pathname: match[1] || '',\n searchParams: new URLSearchParams(match[2] || ''),\n }\n }\n return undefined\n}\n"],
"mappings": ";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAO,IAAM,gBAEX;AAEF,IAAM,iBAAiB;AAEhB,IAAM,SAAN,MAAa;AAAA,EAMlB,YAAY,KAAa,MAAe;AACtC,QAAI;AACJ,QAAI,MAAM;AACR,eAAS,MAAM,IAAI;AACnB,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,oBAAoB,MAAM;AAAA,MAC5C;AACA,YAAM,YAAY,cAAc,GAAG;AACnC,UAAI,CAAC,WAAW;AACd,cAAM,IAAI,MAAM,iBAAiB,KAAK;AAAA,MACxC;AACA,aAAO,OAAO,QAAQ,SAAS;AAAA,IACjC,OAAO;AACL,eAAS,MAAM,GAAG;AAClB,UAAI,CAAC,QAAQ;AACX,cAAM,IAAI,MAAM,oBAAoB,KAAK;AAAA,MAC3C;AAAA,IACF;AAEA,SAAK,OAAO,OAAO;AACnB,SAAK,OAAO,OAAO;AACnB,SAAK,WAAW,OAAO;AACvB,SAAK,eAAe,OAAO;AAAA,EAC7B;AAAA,EAEA,IAAI,WAAW;AACb,WAAO;AAAA,EACT;AAAA,EAEA,IAAI,SAAS;AACX,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA,EAEA,IAAI,WAAW;AACb,WAAO,KAAK;AAAA,EACd;AAAA,EAEA,IAAI,SAAS,GAAW;AACtB,SAAK,OAAO;AAAA,EACd;AAAA,EAEA,IAAI,SAAS;AACX,WAAO,KAAK,aAAa,SAAS;AAAA,EACpC;AAAA,EAEA,IAAI,OAAO,GAAW;AACpB,SAAK,eAAe,IAAI,gBAAgB,CAAC;AAAA,EAC3C;AAAA,EAEA,IAAI,aAAa;AACf,WAAO,KAAK,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,MAAM;AAAA,EACxD;AAAA,EAEA,IAAI,WAAW,GAAW;AACxB,UAAM,QAAQ,KAAK,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACrD,UAAM,KAAK;AACX,SAAK,WAAW,MAAM,KAAK,GAAG;AAAA,EAChC;AAAA,EAEA,IAAI,YAAY;AACd,WAAO,KAAK,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO,EAAE,MAAM;AAAA,EACxD;AAAA,EAEA,IAAI,UAAU,GAAW;AACvB,UAAM,QAAQ,KAAK,SAAS,MAAM,GAAG,EAAE,OAAO,OAAO;AACrD,QAAI,CAAC,MAAM;AAAI,YAAM,KAAK;AAC1B,UAAM,KAAK;AACX,SAAK,WAAW,MAAM,KAAK,GAAG;AAAA,EAChC;AAAA,EAEA,IAAI,OAAO;AACT,WAAO,KAAK,SAAS;AAAA,EACvB;AAAA,EAEA,WAAW;AACT,QAAI,OAAO,KAAK,YAAY;AAC5B,QAAI,CAAC,KAAK,WAAW,GAAG,GAAG;AACzB,aAAO,IAAI;AAAA,IACb;AACA,QAAI,KAAK,KAAK,aAAa,SAAS;AACpC,QAAI,MAAM,CAAC,GAAG,WAAW,GAAG,GAAG;AAC7B,WAAK,IAAI;AAAA,IACX;AACA,QAAI,OAAO,KAAK;AAChB,QAAI,QAAQ,CAAC,KAAK,WAAW,GAAG,GAAG;AACjC,aAAO,IAAI;AAAA,IACb;AACA,WAAO,SAAS,KAAK,OAAO,OAAO,KAAK;AAAA,EAC1C;AACF;AAEA,SAAS,MAAM,KAAa;AAC1B,QAAM,QAAQ,cAAc,KAAK,GAAG;AACpC,MAAI,OAAO;AACT,WAAO;AAAA,MACL,MAAM,MAAM,MAAM;AAAA,MAClB,MAAM,MAAM,MAAM;AAAA,MAClB,UAAU,MAAM,MAAM;AAAA,MACtB,cAAc,IAAI,gBAAgB,MAAM,MAAM,EAAE;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;AAEA,SAAS,cAAc,KAAa;AAClC,QAAM,QAAQ,eAAe,KAAK,GAAG;AACrC,MAAI,OAAO;AACT,WAAO;AAAA,MACL,MAAM,MAAM,MAAM;AAAA,MAClB,UAAU,MAAM,MAAM;AAAA,MACtB,cAAc,IAAI,gBAAgB,MAAM,MAAM,EAAE;AAAA,IAClD;AAAA,EACF;AACA,SAAO;AACT;",
"names": []
}

View File

@ -0,0 +1,20 @@
export declare const ADX_URI_REGEX: RegExp;
export declare class AdxUri {
hash: string;
host: string;
pathname: string;
searchParams: URLSearchParams;
constructor(uri: string, base?: string);
get protocol(): string;
get origin(): string;
get hostname(): string;
set hostname(v: string);
get search(): string;
set search(v: string);
get collection(): string;
set collection(v: string);
get recordKey(): string;
set recordKey(v: string);
get href(): string;
toString(): string;
}

File diff suppressed because one or more lines are too long

View File

@ -15,7 +15,7 @@ const WARNING_TEXT_LENGTH = 200
const DANGER_TEXT_LENGTH = 255 const DANGER_TEXT_LENGTH = 255
export const snapPoints = ['100%'] export const snapPoints = ['100%']
const DEBUG_USERNAMES = ['alice.com', 'bob.com', 'carla.com'] const DEBUG_USERNAMES = ['alice.test', 'bob.test', 'carol.test']
export function Component({replyTo}: {replyTo?: string}) { export function Component({replyTo}: {replyTo?: string}) {
const store = useStores() const store = useStores()
@ -48,7 +48,7 @@ export function Component({replyTo}: {replyTo?: string}) {
return false return false
} }
try { try {
await apilib.post(store.api, 'alice.com', text, replyTo) await apilib.post(store.api, 'alice.test', text, replyTo)
} catch (e: any) { } catch (e: any) {
console.error(`Failed to create post: ${e.toString()}`) console.error(`Failed to create post: ${e.toString()}`)
setError( setError(

View File

@ -1,7 +1,7 @@
import React, {useMemo} from 'react' import React, {useMemo} from 'react'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {Image, StyleSheet, Text, View} from 'react-native'
import {AdxUri} from '@adxp/mock-api' import {AdxUri} from '../../../third-party/uri'
import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon, Props} from '@fortawesome/react-native-fontawesome'
import {NotificationsViewItemModel} from '../../../state/models/notifications-view' import {NotificationsViewItemModel} from '../../../state/models/notifications-view'
import {s, colors} from '../../lib/styles' import {s, colors} from '../../lib/styles'
@ -64,7 +64,7 @@ export const FeedItem = observer(function FeedItem({
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}> <Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.author.name] || AVIS['alice.com']} source={AVIS[item.author.name] || AVIS['alice.test']}
/> />
</Link> </Link>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>

View File

@ -80,7 +80,7 @@ const LikedByItem = ({item}: {item: LikedByViewItemModel}) => {
<View style={styles.layoutAvi}> <View style={styles.layoutAvi}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.name] || AVIS['alice.com']} source={AVIS[item.name] || AVIS['alice.test']}
/> />
</View> </View>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>

View File

@ -86,7 +86,7 @@ const RepostedByItem = ({item}: {item: RepostedByViewItemModel}) => {
<View style={styles.layoutAvi}> <View style={styles.layoutAvi}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.name] || AVIS['alice.com']} source={AVIS[item.name] || AVIS['alice.test']}
/> />
</View> </View>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>

View File

@ -1,7 +1,8 @@
import React, {useMemo} from 'react' import React, {useMemo} from 'react'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {bsky, AdxUri} from '@adxp/mock-api' import {AdxUri} from '../../../third-party/uri'
import * as PostType from '../../../third-party/api/src/types/todo/social/post'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {PostThreadViewPostModel} from '../../../state/models/post-thread-view' import {PostThreadViewPostModel} from '../../../state/models/post-thread-view'
import {ComposePostModel} from '../../../state/models/shell' import {ComposePostModel} from '../../../state/models/shell'
@ -20,7 +21,7 @@ export const PostThreadItem = observer(function PostThreadItem({
onPressShare: (_uri: string) => void onPressShare: (_uri: string) => void
}) { }) {
const store = useStores() const store = useStores()
const record = item.record as unknown as bsky.Post.Record const record = item.record as unknown as PostType.Record
const hasEngagement = item.likeCount || item.repostCount const hasEngagement = item.likeCount || item.repostCount
const itemHref = useMemo(() => { const itemHref = useMemo(() => {
@ -68,23 +69,22 @@ export const PostThreadItem = observer(function PostThreadItem({
<TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}> <TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}>
<FontAwesomeIcon <FontAwesomeIcon
style={ style={
item.myState.hasReposted ? styles.ctrlIconReposted : styles.ctrlIcon item.myState.repost ? styles.ctrlIconReposted : styles.ctrlIcon
} }
icon="retweet" icon="retweet"
size={18} size={18}
/> />
<Text <Text style={item.myState.repost ? [s.bold, s.green3, s.f13] : s.f13}>
style={item.myState.hasReposted ? [s.bold, s.green3, s.f13] : s.f13}>
{item.repostCount} {item.repostCount}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}> <TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}>
<FontAwesomeIcon <FontAwesomeIcon
style={item.myState.hasLiked ? styles.ctrlIconLiked : styles.ctrlIcon} style={item.myState.like ? styles.ctrlIconLiked : styles.ctrlIcon}
icon={[item.myState.hasLiked ? 'fas' : 'far', 'heart']} icon={[item.myState.like ? 'fas' : 'far', 'heart']}
size={14} size={14}
/> />
<Text style={item.myState.hasLiked ? [s.bold, s.red3, s.f13] : s.f13}> <Text style={item.myState.like ? [s.bold, s.red3, s.f13] : s.f13}>
{item.likeCount} {item.likeCount}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
@ -107,7 +107,7 @@ export const PostThreadItem = observer(function PostThreadItem({
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}> <Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.author.name] || AVIS['alice.com']} source={AVIS[item.author.name] || AVIS['alice.test']}
/> />
</Link> </Link>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>
@ -192,7 +192,7 @@ export const PostThreadItem = observer(function PostThreadItem({
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}> <Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.author.name] || AVIS['alice.com']} source={AVIS[item.author.name] || AVIS['alice.test']}
/> />
</Link> </Link>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>

View File

@ -1,6 +1,7 @@
import React, {useState, useEffect} from 'react' import React, {useState, useEffect, useMemo} from 'react'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import {bsky, AdxUri} from '@adxp/mock-api' import {AdxUri} from '../../../third-party/uri'
import * as PostType from '../../../third-party/api/src/types/todo/social/post'
import { import {
ActivityIndicator, ActivityIndicator,
Image, Image,
@ -54,7 +55,7 @@ export const Post = observer(function Post({uri}: {uri: string}) {
// loaded // loaded
// = // =
const item = view.thread const item = view.thread
const record = view.thread?.record as unknown as bsky.Post.Record const record = view.thread?.record as unknown as PostType.Record
const itemHref = useMemo(() => { const itemHref = useMemo(() => {
const urip = new AdxUri(item.uri) const urip = new AdxUri(item.uri)
@ -83,7 +84,7 @@ export const Post = observer(function Post({uri}: {uri: string}) {
<Link style={styles.layoutAvi} href={authorHref} title={authorTitle}> <Link style={styles.layoutAvi} href={authorHref} title={authorTitle}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.author.name] || AVIS['alice.com']} source={AVIS[item.author.name] || AVIS['alice.test']}
/> />
</Link> </Link>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>
@ -112,7 +113,7 @@ export const Post = observer(function Post({uri}: {uri: string}) {
<TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}> <TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}>
<FontAwesomeIcon <FontAwesomeIcon
style={ style={
item.myState.hasReposted item.myState.repost
? styles.ctrlIconReposted ? styles.ctrlIconReposted
: styles.ctrlIcon : styles.ctrlIcon
} }
@ -120,21 +121,18 @@ export const Post = observer(function Post({uri}: {uri: string}) {
size={22} size={22}
/> />
<Text <Text
style={ style={item.myState.repost ? [s.bold, s.green3] : undefined}>
item.myState.hasReposted ? [s.bold, s.green3] : undefined
}>
{item.repostCount} {item.repostCount}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}> <TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}>
<FontAwesomeIcon <FontAwesomeIcon
style={ style={
item.myState.hasLiked ? styles.ctrlIconLiked : styles.ctrlIcon item.myState.like ? styles.ctrlIconLiked : styles.ctrlIcon
} }
icon={[item.myState.hasLiked ? 'fas' : 'far', 'heart']} icon={[item.myState.like ? 'fas' : 'far', 'heart']}
/> />
<Text <Text style={item.myState.like ? [s.bold, s.red3] : undefined}>
style={item.myState.hasLiked ? [s.bold, s.red3] : undefined}>
{item.likeCount} {item.likeCount}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>

View File

@ -26,7 +26,7 @@ export const Feed = observer(function Feed({feed}: {feed: FeedViewModel}) {
{feed.isLoading && !feed.isRefreshing && !feed.hasContent && ( {feed.isLoading && !feed.isRefreshing && !feed.hasContent && (
<Text>Loading...</Text> <Text>Loading...</Text>
)} )}
{feed.hasError && <Text>{feed.error}</Text>} {feed.hasError && <Text>{feed.errorStr}</Text>}
{feed.hasContent && ( {feed.hasContent && (
<FlatList <FlatList
data={feed.feed.slice()} data={feed.feed.slice()}

View File

@ -1,7 +1,8 @@
import React, {useMemo} from 'react' import React, {useMemo} from 'react'
import {observer} from 'mobx-react-lite' import {observer} from 'mobx-react-lite'
import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native' import {Image, StyleSheet, Text, TouchableOpacity, View} from 'react-native'
import {bsky, AdxUri} from '@adxp/mock-api' import {AdxUri} from '../../../third-party/uri'
import * as PostType from '../../../third-party/api/src/types/todo/social/post'
import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome' import {FontAwesomeIcon} from '@fortawesome/react-native-fontawesome'
import {FeedViewItemModel} from '../../../state/models/feed-view' import {FeedViewItemModel} from '../../../state/models/feed-view'
import {ComposePostModel, SharePostModel} from '../../../state/models/shell' import {ComposePostModel, SharePostModel} from '../../../state/models/shell'
@ -18,7 +19,7 @@ export const FeedItem = observer(function FeedItem({
item: FeedViewItemModel item: FeedViewItemModel
}) { }) {
const store = useStores() const store = useStores()
const record = item.record as unknown as bsky.Post.Record const record = item.record as unknown as PostType.Record
const itemHref = useMemo(() => { const itemHref = useMemo(() => {
const urip = new AdxUri(item.uri) const urip = new AdxUri(item.uri)
return `/profile/${item.author.name}/post/${urip.recordKey}` return `/profile/${item.author.name}/post/${urip.recordKey}`
@ -60,7 +61,7 @@ export const FeedItem = observer(function FeedItem({
title={item.author.name}> title={item.author.name}>
<Image <Image
style={styles.avi} style={styles.avi}
source={AVIS[item.author.name] || AVIS['alice.com']} source={AVIS[item.author.name] || AVIS['alice.test']}
/> />
</Link> </Link>
<View style={styles.layoutContent}> <View style={styles.layoutContent}>
@ -107,7 +108,7 @@ export const FeedItem = observer(function FeedItem({
<TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}> <TouchableOpacity style={styles.ctrl} onPress={onPressToggleRepost}>
<FontAwesomeIcon <FontAwesomeIcon
style={ style={
item.myState.hasReposted item.myState.repost
? styles.ctrlIconReposted ? styles.ctrlIconReposted
: styles.ctrlIcon : styles.ctrlIcon
} }
@ -115,22 +116,19 @@ export const FeedItem = observer(function FeedItem({
size={18} size={18}
/> />
<Text <Text
style={ style={item.myState.repost ? [s.bold, s.green3, s.f13] : s.f13}>
item.myState.hasReposted ? [s.bold, s.green3, s.f13] : s.f13
}>
{item.repostCount} {item.repostCount}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>
<TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}> <TouchableOpacity style={styles.ctrl} onPress={onPressToggleLike}>
<FontAwesomeIcon <FontAwesomeIcon
style={ style={
item.myState.hasLiked ? styles.ctrlIconLiked : styles.ctrlIcon item.myState.like ? styles.ctrlIconLiked : styles.ctrlIcon
} }
icon={[item.myState.hasLiked ? 'fas' : 'far', 'heart']} icon={[item.myState.like ? 'fas' : 'far', 'heart']}
size={14} size={14}
/> />
<Text <Text style={item.myState.like ? [s.bold, s.red3, s.f13] : s.f13}>
style={item.myState.hasLiked ? [s.bold, s.red3, s.f13] : s.f13}>
{item.likeCount} {item.likeCount}
</Text> </Text>
</TouchableOpacity> </TouchableOpacity>

Some files were not shown because too many files have changed in this diff Show More