diff --git a/src/types/dbTypes.ts b/src/types/dbTypes.ts new file mode 100644 index 0000000..6f5a395 --- /dev/null +++ b/src/types/dbTypes.ts @@ -0,0 +1,27 @@ +import { Device } from '../models/Device' +import { DeviceState, PushEvent, PushEventState } from './pushTypes' + +export interface DeviceRow { + device: Device + + updateEvents: (events: PushEvent[]) => Promise + updateState: (state: DeviceState) => Promise +} + +export interface PushEventRow { + event: PushEvent + + updateState: (state: PushEventState) => Promise +} + +export interface DbConnection { + // Background event watchers: + streamAddressBalanceEvents: () => Promise> + streamPriceEvents: () => Promise> + streamTxConfirmEvents: () => Promise> + + // Queries: + getDeviceById: (deviceId: string) => Promise + getEventsByDeviceId: (deviceId: string) => Promise + getEventsByLoginId: (loginId: Uint8Array) => Promise +} diff --git a/src/types/pushTypes.ts b/src/types/pushTypes.ts index 979fcb8..e03f506 100644 --- a/src/types/pushTypes.ts +++ b/src/types/pushTypes.ts @@ -28,3 +28,93 @@ export interface ApiKey { admin: boolean adminsdk?: FirebaseAdminKey } + +/** + * Mutable state on a device object. + */ +export interface DeviceState { + enableLegacyPrices: boolean // For legacy v1 API. + rootLoginIds: Uint8Array[] // asArray(asBase64) + visited: Date +} + +/** + * An app installed on a single phone. + */ +export interface Device extends DeviceState { + readonly appId: string + readonly created: Date + readonly deviceId: string + readonly deviceToken: string +} + +// +// Events that devices or logins may subscribe to. +// + +export interface AddressBalanceTrigger { + readonly type: 'address-balance' + readonly pluginId: string + readonly tokenId?: string + readonly address: string + readonly aboveAmount?: string // Satoshis or Wei or such + readonly belowAmount?: string // Satoshis or Wei or such +} + +export interface PriceChangeTrigger { + readonly type: 'price-change' + readonly pluginId: string + readonly tokenId?: string + readonly dailyChange?: number // Percentage + readonly hourlyChange?: number // Percentage +} + +export interface PriceLevelTrigger { + readonly type: 'price-level' + readonly currencyPair: string // From our rates server + readonly aboveRate?: number + readonly belowRate?: number +} + +export interface TxConfirmTrigger { + readonly type: 'tx-confirm' + readonly pluginId: string + readonly confirmations: number + readonly txid: string +} + +export type PushTrigger = + | AddressBalanceTrigger + | PriceChangeTrigger + | PriceLevelTrigger + | TxConfirmTrigger + +/** + * Mutable flags that we can toggle on a push event. + */ +export interface PushEventState { + active: boolean // Watch the trigger when true + triggered?: Date + broadcasted?: Date + pushed?: Date +} + +/** + * An action to perform once a trigger takes place. + */ +export interface PushEvent extends PushEventState { + readonly eventId?: string + readonly deviceId?: string + readonly loginId?: Uint8Array + + readonly broadcast?: Array<{ + pluginId: string + rawTx: Uint8Array // asBase64 + }> + readonly push?: { + title?: string + body?: string + data: { [key: string]: string } // JSON to push to device + } + readonly trigger: PushTrigger +} diff --git a/src/types/v2Types.ts b/src/types/v2Types.ts new file mode 100644 index 0000000..7fb436e --- /dev/null +++ b/src/types/v2Types.ts @@ -0,0 +1,125 @@ +export interface Device { + appId: string + deviceId: string + deviceToken: string + rootLoginIds: Uint8Array[] // asArray(asBase64) + created: Date + visited: Date +} + +interface PriceChangeTrigger { + type: 'price-change' + pluginId: string + tokenId?: string + aboveRatio?: number // 1.1 for +10% + belowRatio?: number // 0.9 for -10% + range: 'hourly' | 'daily' +} + +interface PriceLevelTrigger { + type: 'price-level' + currencyPair: string // From our rates server + aboveRate?: number + belowRate?: number +} + +interface AddressBalanceTrigger { + type: 'address-balance' + pluginId: string + tokenId?: string + address: string + aboveAmount?: string // Satoshis or Wei or such + belowAmount?: string // Satoshis or Wei or such +} + +interface TxConfirmTrigger { + type: 'tx-confirm' + pluginId: string + confirmations: number + txid: string +} + +export type PushTrigger = + | AddressBalanceTrigger + | PriceChangeTrigger + | PriceLevelTrigger + | TxConfirmTrigger + +interface PushEvent { + trigger: PushTrigger + triggered: boolean + + // TODO: Check firebase docs + pushMessage?: string + pushPayload?: unknown // JSON to push to device + broadcastTxs?: Array<{ + pluginId: string + rawTx: Uint8Array // asBase64 + }> +} + +export interface PushRequestBody { + // The request payload: + data: unknown + + // Who is making the request: + apiKey: string + appId: string + deviceId: string + + // For logins: + rootLoginId?: Uint8Array + // rootSecretHash?: Uint8Array +} + +/** + * Refreshes the `visited` date on a device and its effects or logins. + * Devices expire after 3 months. + * POST /v2/device/checkin + */ + +/** + * Registers / updates a device. + * POST /v2/device/update + */ +export interface UpdateDevicePayload { + rootLoginIds: Uint8Array[] // asArray(asBase64) + events: PushEvent[] + deviceToken: string +} + +/** + * Gets a device from the database. + * POST /v2/device + */ +export interface DevicePayload { + deviceId: string + deviceToken: string + events: PushEvent[] + rootLoginIds: Uint8Array[] // asArray(asBase64) + created: Date + visited: Date +} + +/** + * Registers / updates a login. + * POST /v2/login/update + */ +export interface UpdateLoginPayload { + events: PushEvent[] + + // removeEvents?: string[] + // replaceEvents?: PushEvent[] + // newEvents?: PushEvent[] +} + +/** + * Reads a login from the database. + * POST /v2/login + */ +export interface LoginPayload { + deviceIds: string + events: PushEvent[] + created: Date + visited: Date +}