diff options
Diffstat (limited to 'src/state')
-rw-r--r-- | src/state/env.ts | 223 | ||||
-rw-r--r-- | src/state/index.ts | 26 | ||||
-rw-r--r-- | src/state/lib/auth.ts (renamed from src/state/auth.ts) | 8 | ||||
-rw-r--r-- | src/state/lib/storage.ts (renamed from src/state/storage.ts) | 0 | ||||
-rw-r--r-- | src/state/models/me.ts | 48 | ||||
-rw-r--r-- | src/state/models/root-store.ts | 3 | ||||
-rw-r--r-- | src/state/models/session.ts | 14 |
7 files changed, 295 insertions, 27 deletions
diff --git a/src/state/env.ts b/src/state/env.ts index c1e11ebd0..0ee59788c 100644 --- a/src/state/env.ts +++ b/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}, + ], + }) +} diff --git a/src/state/index.ts b/src/state/index.ts index 6040f8f9d..24c3b9430 100644 --- a/src/state/index.ts +++ b/src/state/index.ts @@ -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) - - // handle redirect from auth - if (await auth.initialLoadUcanCheck(env.authStore)) { - rootStore.session.setAuthed(true) - } - } + // 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) + // } + // } + await rootStore.me.load() + console.log(rootStore.me) return rootStore } diff --git a/src/state/auth.ts b/src/state/lib/auth.ts index a8483b926..d758745ed 100644 --- a/src/state/auth.ts +++ b/src/state/lib/auth.ts @@ -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( diff --git a/src/state/storage.ts b/src/state/lib/storage.ts index dc5fb620f..dc5fb620f 100644 --- a/src/state/storage.ts +++ b/src/state/lib/storage.ts diff --git a/src/state/models/me.ts b/src/state/models/me.ts new file mode 100644 index 000000000..bc4b13148 --- /dev/null +++ b/src/state/models/me.ts @@ -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 {} +} diff --git a/src/state/models/root-store.ts b/src/state/models/root-store.ts index 143c59ea1..b38b36e8a 100644 --- a/src/state/models/root-store.ts +++ b/src/state/models/root-store.ts @@ -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(), } } diff --git a/src/state/models/session.ts b/src/state/models/session.ts index c032d7594..3b52b8fc6 100644 --- a/src/state/models/session.ts +++ b/src/state/models/session.ts @@ -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() |