Add mock API and reorg code for clarity
This commit is contained in:
parent
de87ec17d1
commit
1d00f3b984
29 changed files with 356 additions and 168 deletions
223
src/state/env.ts
223
src/state/env.ts
|
@ -4,22 +4,35 @@
|
|||
*/
|
||||
|
||||
import {getEnv, IStateTreeNode} from 'mobx-state-tree'
|
||||
import {ReactNativeStore} from './auth'
|
||||
import {API} from '../api'
|
||||
// import {ReactNativeStore} from './auth'
|
||||
import {AdxClient, blueskywebSchemas, AdxRepoClient} from '@adxp/mock-api'
|
||||
import * as storage from './lib/storage'
|
||||
|
||||
export const adx = new AdxClient({
|
||||
pds: 'http://localhost',
|
||||
schemas: blueskywebSchemas,
|
||||
})
|
||||
|
||||
export class Environment {
|
||||
api = new API()
|
||||
authStore?: ReactNativeStore
|
||||
adx = adx
|
||||
// authStore?: ReactNativeStore
|
||||
|
||||
constructor() {}
|
||||
|
||||
async setup() {
|
||||
this.authStore = await ReactNativeStore.load()
|
||||
await adx.setupMock(
|
||||
() => storage.load('mock-root'),
|
||||
async root => {
|
||||
await storage.save('mock-root', root)
|
||||
},
|
||||
generateMockData,
|
||||
)
|
||||
// this.authStore = await ReactNativeStore.load()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extension to the MST models that adds the environment property.
|
||||
* Extension to the MST models that adds the env property.
|
||||
* Usage:
|
||||
*
|
||||
* .extend(withEnvironment)
|
||||
|
@ -27,8 +40,204 @@ export class Environment {
|
|||
*/
|
||||
export const withEnvironment = (self: IStateTreeNode) => ({
|
||||
views: {
|
||||
get environment() {
|
||||
get env() {
|
||||
return getEnv<Environment>(self)
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// TEMPORARY
|
||||
// mock api config
|
||||
// =======
|
||||
|
||||
function* dateGen() {
|
||||
let start = 1657846031914
|
||||
while (true) {
|
||||
yield new Date(start).toISOString()
|
||||
start += 1e3
|
||||
}
|
||||
}
|
||||
const date = dateGen()
|
||||
|
||||
function repo(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() {
|
||||
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('alice.com')
|
||||
const bob = repo('bob.com')
|
||||
const carla = repo('carla.com')
|
||||
|
||||
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')
|
||||
|
||||
// 2 posts on each user
|
||||
const alicePosts: {uri: string}[] = []
|
||||
for (let i = 0; i < 2; i++) {
|
||||
alicePosts.push(
|
||||
await alice.collection('blueskyweb.xyz:Posts').create('Post', {
|
||||
$type: 'blueskyweb.xyz:Post',
|
||||
text: `Alice post ${i + 1}`,
|
||||
createdAt: date.next().value,
|
||||
}),
|
||||
)
|
||||
await bob.collection('blueskyweb.xyz:Posts').create('Post', {
|
||||
$type: 'blueskyweb.xyz:Post',
|
||||
text: `Bob post ${i + 1}`,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
await carla.collection('blueskyweb.xyz:Posts').create('Post', {
|
||||
$type: 'blueskyweb.xyz:Post',
|
||||
text: `Carla post ${i + 1}`,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
}
|
||||
|
||||
// small thread of replies on alice's first post
|
||||
const bobReply1 = await bob
|
||||
.collection('blueskyweb.xyz:Posts')
|
||||
.create('Post', {
|
||||
$type: 'blueskyweb.xyz:Post',
|
||||
text: 'Bob reply',
|
||||
reply: {root: alicePosts[0].uri, parent: alicePosts[0].uri},
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
const carlaReply1 = await carla
|
||||
.collection('blueskyweb.xyz:Posts')
|
||||
.create('Post', {
|
||||
$type: 'blueskyweb.xyz:Post',
|
||||
text: 'Carla reply',
|
||||
reply: {root: alicePosts[0].uri, parent: alicePosts[0].uri},
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
const aliceReply1 = await alice
|
||||
.collection('blueskyweb.xyz:Posts')
|
||||
.create('Post', {
|
||||
$type: 'blueskyweb.xyz:Post',
|
||||
text: 'Alice reply',
|
||||
reply: {root: alicePosts[0].uri, parent: bobReply1.uri},
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
|
||||
// bob and carla repost alice's first post
|
||||
await bob.collection('blueskyweb.xyz:Posts').create('Repost', {
|
||||
$type: 'blueskyweb.xyz:Repost',
|
||||
subject: alicePosts[0].uri,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
await carla.collection('blueskyweb.xyz:Posts').create('Repost', {
|
||||
$type: 'blueskyweb.xyz:Repost',
|
||||
subject: alicePosts[0].uri,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
|
||||
// bob likes all of alice's posts
|
||||
for (let i = 0; i < 2; i++) {
|
||||
await bob.collection('blueskyweb.xyz:Likes').create('Like', {
|
||||
$type: 'blueskyweb.xyz:Like',
|
||||
subject: alicePosts[i].uri,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
}
|
||||
|
||||
// carla likes all of alice's posts and everybody's replies
|
||||
for (let i = 0; i < 2; i++) {
|
||||
await carla.collection('blueskyweb.xyz:Likes').create('Like', {
|
||||
$type: 'blueskyweb.xyz:Like',
|
||||
subject: alicePosts[i].uri,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
}
|
||||
await carla.collection('blueskyweb.xyz:Likes').create('Like', {
|
||||
$type: 'blueskyweb.xyz:Like',
|
||||
subject: aliceReply1.uri,
|
||||
createdAt: date.next().value,
|
||||
})
|
||||
await carla.collection('blueskyweb.xyz:Likes').create('Like', {
|
||||
$type: 'blueskyweb.xyz:Like',
|
||||
subject: bobReply1.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,
|
||||
})
|
||||
const employeeBadge = 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},
|
||||
],
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,8 +5,8 @@ import {
|
|||
createDefaultRootStore,
|
||||
} from './models/root-store'
|
||||
import {Environment} from './env'
|
||||
import * as storage from './storage'
|
||||
import * as auth from './auth'
|
||||
import * as storage from './lib/storage'
|
||||
// import * as auth from './auth' TODO
|
||||
|
||||
const ROOT_STATE_STORAGE_KEY = 'root'
|
||||
|
||||
|
@ -29,15 +29,19 @@ export async function setupState() {
|
|||
storage.save(ROOT_STATE_STORAGE_KEY, snapshot),
|
||||
)
|
||||
|
||||
if (env.authStore) {
|
||||
const isAuthed = await auth.isAuthed(env.authStore)
|
||||
rootStore.session.setAuthed(isAuthed)
|
||||
// TODO
|
||||
rootStore.session.setAuthed(true)
|
||||
// if (env.authStore) {
|
||||
// const isAuthed = await auth.isAuthed(env.authStore)
|
||||
// rootStore.session.setAuthed(isAuthed)
|
||||
|
||||
// handle redirect from auth
|
||||
if (await auth.initialLoadUcanCheck(env.authStore)) {
|
||||
rootStore.session.setAuthed(true)
|
||||
}
|
||||
}
|
||||
// // handle redirect from auth
|
||||
// if (await auth.initialLoadUcanCheck(env.authStore)) {
|
||||
// rootStore.session.setAuthed(true)
|
||||
// }
|
||||
// }
|
||||
await rootStore.me.load()
|
||||
console.log(rootStore.me)
|
||||
|
||||
return rootStore
|
||||
}
|
||||
|
|
|
@ -1,7 +1,11 @@
|
|||
import * as auth from '@adxp/auth'
|
||||
import * as ucan from 'ucans'
|
||||
import {getInitialURL, extractHashFragment, clearHash} from '../platform/urls'
|
||||
import * as authFlow from '../platform/auth-flow'
|
||||
import {
|
||||
getInitialURL,
|
||||
extractHashFragment,
|
||||
clearHash,
|
||||
} from '../../platform/urls'
|
||||
import * as authFlow from '../../platform/auth-flow'
|
||||
import * as storage from './storage'
|
||||
|
||||
const SCOPE = auth.writeCap(
|
48
src/state/models/me.ts
Normal file
48
src/state/models/me.ts
Normal file
|
@ -0,0 +1,48 @@
|
|||
import {Instance, SnapshotOut, types, flow, getRoot} from 'mobx-state-tree'
|
||||
import {RootStore} from './root-store'
|
||||
import {withEnvironment} from '../env'
|
||||
|
||||
export const MeModel = types
|
||||
.model('Me')
|
||||
.props({
|
||||
did: types.maybe(types.string),
|
||||
name: types.maybe(types.string),
|
||||
displayName: types.maybe(types.string),
|
||||
description: types.maybe(types.string),
|
||||
})
|
||||
.extend(withEnvironment)
|
||||
.actions(self => ({
|
||||
load: flow(function* () {
|
||||
const sess = (getRoot(self) as RootStore).session
|
||||
if (sess.isAuthed) {
|
||||
// TODO temporary
|
||||
const userDb = self.env.adx.mockDb.mainUser
|
||||
self.did = userDb.did
|
||||
self.name = userDb.name
|
||||
const profile = yield self.env.adx
|
||||
.repo(self.did, true)
|
||||
.collection('blueskyweb.xyz:Profiles')
|
||||
.get('Profile', 'profile')
|
||||
.catch(_ => undefined)
|
||||
if (profile?.valid) {
|
||||
self.displayName = profile.value.displayName
|
||||
self.description = profile.value.description
|
||||
} else {
|
||||
self.displayName = ''
|
||||
self.description = ''
|
||||
}
|
||||
} else {
|
||||
self.did = undefined
|
||||
self.name = undefined
|
||||
self.displayName = undefined
|
||||
self.description = undefined
|
||||
}
|
||||
}),
|
||||
}))
|
||||
|
||||
export interface Me extends Instance<typeof MeModel> {}
|
||||
export interface MeSnapshot extends SnapshotOut<typeof MeModel> {}
|
||||
|
||||
export function createDefaultMe() {
|
||||
return {}
|
||||
}
|
|
@ -5,9 +5,11 @@
|
|||
import {Instance, SnapshotOut, types} from 'mobx-state-tree'
|
||||
import {createContext, useContext} from 'react'
|
||||
import {SessionModel, createDefaultSession} from './session'
|
||||
import {MeModel, createDefaultMe} from './me'
|
||||
|
||||
export const RootStoreModel = types.model('RootStore').props({
|
||||
session: SessionModel,
|
||||
me: MeModel,
|
||||
})
|
||||
|
||||
export interface RootStore extends Instance<typeof RootStoreModel> {}
|
||||
|
@ -16,6 +18,7 @@ export interface RootStoreSnapshot extends SnapshotOut<typeof RootStoreModel> {}
|
|||
export function createDefaultRootStore() {
|
||||
return {
|
||||
session: createDefaultSession(),
|
||||
me: createDefaultMe(),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import {Instance, SnapshotOut, types, flow} from 'mobx-state-tree'
|
||||
// import {UserConfig} from '../../api'
|
||||
import * as auth from '../auth'
|
||||
import * as auth from '../lib/auth'
|
||||
import {withEnvironment} from '../env'
|
||||
|
||||
export const SessionModel = types
|
||||
|
@ -24,10 +24,10 @@ export const SessionModel = types
|
|||
self.uiIsProcessing = true
|
||||
self.uiError = undefined
|
||||
try {
|
||||
if (!self.environment.authStore) {
|
||||
if (!self.env.authStore) {
|
||||
throw new Error('Auth store not initialized')
|
||||
}
|
||||
const res = yield auth.requestAppUcan(self.environment.authStore)
|
||||
const res = yield auth.requestAppUcan(self.env.authStore)
|
||||
self.isAuthed = res
|
||||
self.uiIsProcessing = false
|
||||
return res
|
||||
|
@ -42,10 +42,10 @@ export const SessionModel = types
|
|||
self.uiIsProcessing = true
|
||||
self.uiError = undefined
|
||||
try {
|
||||
if (!self.environment.authStore) {
|
||||
if (!self.env.authStore) {
|
||||
throw new Error('Auth store not initialized')
|
||||
}
|
||||
const res = yield auth.logout(self.environment.authStore)
|
||||
const res = yield auth.logout(self.env.authStore)
|
||||
self.isAuthed = false
|
||||
self.uiIsProcessing = false
|
||||
return res
|
||||
|
@ -65,7 +65,7 @@ export const SessionModel = types
|
|||
// secretKeyStr: self.secretKeyStr,
|
||||
// rootAuthToken: self.rootAuthToken,
|
||||
// })
|
||||
// self.environment.api.setUserCfg(cfg)
|
||||
// self.env.api.setUserCfg(cfg)
|
||||
self.isAuthed = true
|
||||
self.uiIsProcessing = false
|
||||
return true
|
||||
|
@ -86,7 +86,7 @@ export const SessionModel = types
|
|||
// self.secretKeyStr = state.secretKeyStr
|
||||
// self.rootAuthToken = state.rootAuthToken
|
||||
self.isAuthed = true
|
||||
// self.environment.api.setUserCfg(cfg)
|
||||
// self.env.api.setUserCfg(cfg)
|
||||
} catch (e: any) {
|
||||
console.error('Failed to create test account', e)
|
||||
self.uiError = e.toString()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue