import { LocalDB, WrappedState } from './LocalDB';
import type Network from '@browser-network/network';
import * as t from './types.d';
type StateUpdateMessage = {
    type: 'state-update';
    data: WrappedState;
    appId: string;
};
type StateRequestMessage = {
    type: 'state-request';
    data: t.IDString;
    appId: string;
    destination: string;
};
type StateOfferingMessage = {
    type: 'state-offering';
    data: StateOfferings;
    appId: string;
};
type DbMessage = StateUpdateMessage | StateOfferingMessage | StateRequestMessage;
type StateOfferings = {
    [stateId: t.GUID]: t.TimeStamp;
};
type DbProps = {
    /**
    * @description The @browser-network/network that this Db app sits on top of. Without this there is no Db!
    */
    network: Network;
    /**
    * @description The EC private key that Db will use to both generate a public key and validate Db entries with.
    * See @browser-network/crypto's generateSecret() function.
    */
    secret: string;
    /**
    * @description This is the namespace under which Db will make its messages. It just needs to be unique
    * on the network, that's why it's up to the developer to provide this. Every instance of this db that you
    * want to share data with needs to have the same appId. You could, if you wanted to, have multiple databases
    * that each had their own set of data, unshared with each other, by providing different appIds here.
    */
    appId: string;
};
export default class Db<S> {
    appId: string;
    network: Network<DbMessage>;
    localDB: LocalDB;
    networkId: t.IDString;
    address: t.IDString;
    publicKey: t.PublicKey;
    secret: string;
    switchAddress: t.SwitchAddress;
    private _denyList;
    private _allowList;
    private _onChangeHandlers;
    constructor({ secret, appId, network }: DbProps);
    /**
    * @description This is how you write data to the network. This will put whatever
    * state you give it into a DB specific wrapper with your state in the `state` key.
    */
    set(state: S): Promise<void>;
    /**
    * @description Get the state of the user whose address is passed in.
    */
    get(address: t.IDString): WrappedState<S> | undefined;
    /**
    * @description Get all entries from our local DB, wrapped in the DB's
    * WrappedState type.
    *
    * @TODO: Does it need to be wrapped? Does the user ever care about this
    * wrapping or should they just be able to go straight to their state?
    */
    getAll: () => WrappedState<S>[];
    /**
    * @description This will fire every time we update our state. This way reactive
    * UIs can listen for changes and update based on the new state of the world
    */
    onChange(handler: () => void): void;
    /**
    * @description clear the DB of all listeners.
    */
    removeChangeHandlers(): void;
    /**
    * @description clear the DB of a specific listener.
    */
    removeChangeHandler(func: Function): void;
    /**
    * @description Clear the local storage of everyone's items. Essentially resets the machine
    * to as if it's never seen the network before. If it is connected still, it will
    * rapidly start to repopulate.
    */
    clear: () => void;
    /**
    * @description Effectively blocks a user. Adds them to our deny list, which means we'll no longer
    * accept updates from them, which means we will no longer forward their updates as well. Also
    * removes their state from our storage.
    *
    * It's up to the developer to keep track of these (probably
    * within the state object that they store in this db), and repopulate this list on startup.
    * Calling deny with an address that's already blocked is a noop and O(1) time so don't worry about
    * spamming this call.
    */
    deny: (address: t.PublicKey) => void;
    /**
    * @description Unblock a user. Removes them from our deny list, at which point the DB will naturally
    * start to repopulate that user's state.
    */
    undeny: (address: t.PublicKey) => void;
    /**
    * @description Add a user to our allow list. Once a single user is on this list, _only users on the
    * allow list will be recorded in the database_. All other users will automatically be ignored.
    *
    * It's up to the developer to keep track of these (probably
    * within the state object that they store in this db), and repopulate this list on startup.
    * Calling allow with an address that's already on the list is a noop and O(1) time so don't worry about
    * spamming this call.
    */
    allow: (address: t.PublicKey) => void;
    /**
    * @description Remove a user from the allow list. Calling this will remove the user's state from
    * our storage, and that user's state will no longer be forwarded either.
    */
    unallow: (address: t.PublicKey) => void;
    private onMessage;
    private onStateOffering;
    private onStateUpdate;
    private isForbidden;
    private broadcastStateUpdate;
    private broadcastStateUpdateByStateId;
    /**
    * We will periodically inform the network of what states we have
    * and how old they are. If someone else hears that we have a state
    * newer than what they have on record, they can send us a request for
    * what we have.
    */
    private broadcastStateOfferings;
    private setLocal;
    private runChangeHandlers;
    private verify;
    private isNew;
}
export {};
