diff --git a/apps/humding/verdant/src/client/client.d.ts b/apps/humding/verdant/src/client/client.d.ts index ff79a409..d74544b3 100644 --- a/apps/humding/verdant/src/client/client.d.ts +++ b/apps/humding/verdant/src/client/client.d.ts @@ -24,10 +24,36 @@ export class Client { import: BaseClient["import"]; subscribe: BaseClient["subscribe"]; stats: BaseClient["stats"]; + + /** + * Deletes all local data. If the client is connected to sync, + * this will cause the client to re-sync all data from the server. + * Use this very carefully, and only as a last resort. + */ __dangerous__resetLocal: BaseClient< Presence, Profile >["__dangerous__resetLocal"]; + + /** + * Export all data, then re-import it. This might resolve + * some issues with the local database, but it should + * only be done as a second-to-last resort. The last resort + * would be __dangerous__resetLocal on ClientDescriptor, which + * clears all local data. + * + * Unlike __dangerous__resetLocal, this method allows local-only + * clients to recover data, whereas __dangerous__resetLocal only + * lets networked clients recover from the server. + */ + __dangerous__hardReset: () => Promise; + + /** + * Manually triggers storage rebasing. Follows normal + * rebasing rules. Rebases already happen automatically + * during normal operation, so you probably don't need this. + */ + __manualRebase: () => Promise; } export interface ClientDescriptorOptions diff --git a/apps/humding/verdant/src/client/index.ts b/apps/humding/verdant/src/client/index.ts index 44f4dc13..25b31357 100644 --- a/apps/humding/verdant/src/client/index.ts +++ b/apps/humding/verdant/src/client/index.ts @@ -1,6 +1,7 @@ import { ClientDescriptorOptions } from "./client.js"; export * from "./client.js"; import schema from "./schema.js"; +import oldSchemas from "./schemaVersions/index.js"; import { ClientDescriptor as StorageDescriptor } from "./client.js"; import migrations from "../migrations/index.js"; export * from "@verdant-web/store"; @@ -12,10 +13,12 @@ export class ClientDescriptor< constructor(init: ClientDescriptorOptions) { const defaultedSchema = init.schema || schema; const defaultedMigrations = init.migrations || migrations; + const defaultedOldSchemas = init.oldSchemas || oldSchemas; super({ ...init, schema: defaultedSchema, migrations: defaultedMigrations, + oldSchemas: defaultedOldSchemas, }); } } diff --git a/apps/humding/verdant/src/client/react.d.ts b/apps/humding/verdant/src/client/react.d.ts index cd48961b..1baecab3 100644 --- a/apps/humding/verdant/src/client/react.d.ts +++ b/apps/humding/verdant/src/client/react.d.ts @@ -1,4 +1,10 @@ -import { Context, ComponentType, ReactNode } from "react"; +import { + Context, + ComponentType, + ReactNode, + ChangeEvent, + FocusEvent, +} from "react"; import type { Client, ClientDescriptor, @@ -12,6 +18,7 @@ import type { EntityShape, AnyEntity, EntityDestructured, + EntityInit, EntityFile, Song, SongFilter, @@ -23,20 +30,29 @@ type HookConfig = { key?: string; }; +type FieldInputProps = { + value: Shape extends boolean ? undefined : Shape; + checked?: boolean; + onChange: (event: ChangeEvent) => void; + onFocus: (event: FocusEvent) => void; + onBlur: (event: FocusEvent) => void; + type?: string; +}; + export interface GeneratedHooks { /** * Render this context Provider at the top level of your * React tree to provide a Client to all hooks. */ Provider: ComponentType<{ - value: ClientDescriptor; + value: ClientDescriptor; children: ReactNode; sync?: boolean; }>; /** * Direct access to the React Context, if needed. */ - Context: Context>; + Context: Context>; /** @deprecated use useClient instead */ useStorage: () => Client; useClient: () => Client; @@ -52,6 +68,46 @@ export interface GeneratedHooks { query: (peer: UserInfo) => boolean, options?: { includeSelf: boolean }, ) => UserInfo[]; + useViewPeers: () => UserInfo[]; + useViewId: (viewId: string | undefined) => void; + useField< + T extends AnyEntity, + K extends keyof EntityDestructured, + >( + entity: T, + fieldName: K, + options?: { + /** after this timeout, the field will be considered abandoned by a peer. defaults to 1m */ + timeout: number; + }, + ): { + /* The live value of the field */ + value: EntityDestructured[K]; + /* Sets the value of the field */ + setValue: (value: Exclude[K], undefined>) => void; + /* Pass these props to any or