diff --git a/types/sharedb/index.d.ts b/types/sharedb/index.d.ts index 0f0f5575fd..7657075f8e 100644 --- a/types/sharedb/index.d.ts +++ b/types/sharedb/index.d.ts @@ -1,7 +1,9 @@ // Type definitions for sharedb 1.0 // Project: https://github.com/share/sharedb // Definitions by: Steve Oney +// Eric Hwang // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped +// TypeScript Version: 2.1 /// @@ -18,20 +20,33 @@ export = sharedb; declare class sharedb { constructor(options?: {db?: any, pubsub?: sharedb.PubSub, disableDocAction?: boolean, disableSpaceDelimitedActions?: boolean}); - connect: () => sharedb.Connection; - addProjection(name: string, collection: string, fields: {}): any; + connect: (connection?: any, req?: any) => sharedb.Connection; + /** + * Registers a projection that can be used from clients just like a normal collection. + * + * @param name name of the projection + * @param collection name of the backing collection + * @param fields field whitelist for the projection + */ + addProjection(name: string, collection: string, fields: ProjectionFields): void; listen(stream: any): void; - close(callback?: (err: Error) => any): void; - use(action: sharedb.UseAction, fn: sharedb.UseCallback): void; + close(callback?: (err?: Error) => any): void; + /** + * Registers a server middleware function. + * + * @param action name of an action from https://github.com/share/sharedb#middlewares + * @param fn listener invoked when the specified action occurs + */ + use( + action: A, + fn: (context: middleware.ActionContextMap[A], callback: (err?: any) => void) => void, + ): void; static types: { register: (type: { name?: string, uri?: string, [key: string]: any}) => void; }; } declare namespace sharedb { - type UseAction = 'connect' | 'op' | 'doc' | 'query' | 'submit' | 'apply' | 'commit' | 'after submit' | 'receive'; - type UseCallback = ((request: {action: UseAction, agent: any, req: any, collection: string, id: string, query: any, op: ShareDB.RawOp}, callback: () => void) => void); - abstract class DB { projectsSnapshots: boolean; disableSubscribe: boolean; @@ -100,3 +115,102 @@ declare namespace sharedb { type Path = ShareDB.Path; type ShareDBSourceOptions = ShareDB.ShareDBSourceOptions; } + +declare namespace middleware { + interface ActionContextMap { + afterSubmit: SubmitContext; + apply: ApplyContext; + commit: CommitContext; + connect: ConnectContext; + doc: DocContext; // Deprecated, use 'readSnapshots' instead. + op: OpContext; + query: QueryContext; + receive: ReceiveContext; + readSnapshots: ReadSnapshotsContext; + submit: SubmitContext; + } + + interface BaseContext { + action: keyof ActionContextMap; + agent: any; + backend: sharedb; + } + + interface ApplyContext extends BaseContext, SubmitRequest { + } + + interface CommitContext extends BaseContext, SubmitRequest { + } + + interface ConnectContext extends BaseContext { + stream: any; + req: any; // Property always exists, value may be undefined + } + + interface DocContext extends BaseContext { + collection: string; + id: string; + snapshot: ShareDB.Snapshot; + } + + interface OpContext extends BaseContext { + collection: string; + id: string; + op: ShareDB.Op; + } + + interface QueryContext extends BaseContext { + index: string; + collection: string; + projection: Projection | undefined; + fields: ProjectionFields | undefined; + channel: string; + query: any; + options: any; + db: sharedb.DB | null; + snapshotProjection: Projection | null; + } + + interface ReceiveContext extends BaseContext { + data: any; + } + + interface ReadSnapshotsContext extends BaseContext { + collection: string; + snapshots: ShareDB.Snapshot[]; + snapshotType: SnapshotType; + } + + type SnapshotType = 'current' | 'byVersion' | 'byTimestamp'; + + interface SubmitContext extends BaseContext, SubmitRequest { + } +} + +interface Projection { + target: string; + fields: ProjectionFields; +} + +interface ProjectionFields { + [propertyName: string]: true; +} + +interface SubmitRequest { + index: string; + projection: Projection | undefined; + collection: string; + id: string; + op: sharedb.Op; + options: any; + start: number; + + saveMilestoneSnapshot: boolean | null; + suppressPublish: boolean | null; + maxRetries: number | null; + retries: number; + + snapshot: ShareDB.Snapshot | null; + ops: ShareDB.Op[]; + channels: string[] | null; +} diff --git a/types/sharedb/lib/sharedb.d.ts b/types/sharedb/lib/sharedb.d.ts index 426eac5a0e..169b7e6674 100644 --- a/types/sharedb/lib/sharedb.d.ts +++ b/types/sharedb/lib/sharedb.d.ts @@ -1,7 +1,19 @@ import { EventEmitter } from 'events'; export type Path = ReadonlyArray; -export type Snapshot = number; +export interface Snapshot { + id: string; + v: number; + type: string | null; + data: any; // JSON object, could be undefined + m: SnapshotMeta | null; +} + +export interface SnapshotMeta { + ctime: number; + mtime: number; + [key: string]: any; +} export interface AddNumOp { p: Path; na: number; } diff --git a/types/sharedb/sharedb-tests.ts b/types/sharedb/sharedb-tests.ts index 55c3dc797d..a4e35d3507 100644 --- a/types/sharedb/sharedb-tests.ts +++ b/types/sharedb/sharedb-tests.ts @@ -30,7 +30,94 @@ class WebSocketJSONStream extends Duplex { } const backend = new ShareDB(); + +backend.addProjection('notes_minimal', 'notes', {title: true, creator: true, lastUpdateTime: true}); + +// Exercise middleware (backend.use) +type SubmitRelatedActions = 'afterSubmit' | 'apply' | 'commit' | 'submit'; +const submitRelatedActions: SubmitRelatedActions[] = ['afterSubmit', 'apply', 'commit', 'submit']; +for (const action of submitRelatedActions) { + backend.use(action, (request, callback) => { + console.log( + request.action, + request.agent, + request.backend, + request.index, + request.collection, + request.projection, + request.id, + request.op, + request.options, + request.snapshot, + request.ops, + request.channels, + ); + callback(); + }); +} +backend.use('connect', (context, callback) => { + console.log( + context.action, + context.agent, + context.backend, + context.stream, + context.req, + ); + callback(); +}); +backend.use('op', (context, callback) => { + console.log( + context.action, + context.agent, + context.backend, + context.collection, + context.id, + context.op, + ); + callback(); +}); +backend.use('query', (context, callback) => { + console.log( + context.action, + context.agent, + context.backend, + context.index, + context.collection, + context.projection, + context.fields, + context.channel, + context.query, + context.options, + context.snapshotProjection, + ); + callback(); +}); +backend.use('receive', (context, callback) => { + console.log( + context.action, + context.agent, + context.backend, + context.data, + ); + callback(); +}); +backend.use('readSnapshots', (context, callback) => { + console.log( + context.action, + context.agent, + context.backend, + context.collection, + context.snapshots, + context.snapshotType, + ); + callback(); +}); + const connection = backend.connect(); +const netRequest = {}; // Passed through to 'connect' middleware, not used by sharedb itself +const connectionWithReq = backend.connect(null, netRequest); +const reboundConnection = backend.connect(backend.connect(), netRequest); + const doc = connection.get('examples', 'counter'); doc.fetch((err) => {