publish bemo canaries (#4175)
Switch on package publishing for sync libraries so we can start building templates on the canaries. ### Change type - [x] `other`
This commit is contained in:
parent
c5b2569bfc
commit
348ff9f66a
20 changed files with 631 additions and 30 deletions
1
.github/workflows/publish-canary.yml
vendored
1
.github/workflows/publish-canary.yml
vendored
|
@ -27,3 +27,4 @@ jobs:
|
|||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
R2_ACCESS_KEY_SECRET: ${{ secrets.R2_ACCESS_KEY_SECRET }}
|
||||
TLDRAW_BEMO_URL: https://canary-demo.tldraw.xyz
|
||||
|
|
1
.github/workflows/publish-manual.yml
vendored
1
.github/workflows/publish-manual.yml
vendored
|
@ -34,6 +34,7 @@ jobs:
|
|||
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
R2_ACCESS_KEY_SECRET: ${{ secrets.R2_ACCESS_KEY_SECRET }}
|
||||
TLDRAW_BEMO_URL: https://demo.tldraw.xyz
|
||||
|
||||
publish_templates:
|
||||
name: Publishes code templates to separate repositories
|
||||
|
|
1
.github/workflows/publish-new.yml
vendored
1
.github/workflows/publish-new.yml
vendored
|
@ -71,6 +71,7 @@ jobs:
|
|||
HUPPY_TOKEN: ${{ secrets.HUPPY_TOKEN }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
R2_ACCESS_KEY_SECRET: ${{ secrets.R2_ACCESS_KEY_SECRET }}
|
||||
TLDRAW_BEMO_URL: https://demo.tldraw.xyz
|
||||
|
||||
publish_templates:
|
||||
name: Publishes code templates to separate repositories
|
||||
|
|
1
.github/workflows/publish-patch.yml
vendored
1
.github/workflows/publish-patch.yml
vendored
|
@ -52,6 +52,7 @@ jobs:
|
|||
HUPPY_TOKEN: ${{ secrets.HUPPY_TOKEN }}
|
||||
R2_ACCESS_KEY_ID: ${{ secrets.R2_ACCESS_KEY_ID }}
|
||||
R2_ACCESS_KEY_SECRET: ${{ secrets.R2_ACCESS_KEY_SECRET }}
|
||||
TLDRAW_BEMO_URL: https://demo.tldraw.xyz
|
||||
|
||||
publish_templates:
|
||||
name: Publishes code templates to separate repositories
|
||||
|
|
503
packages/sync-core/api-report.md
Normal file
503
packages/sync-core/api-report.md
Normal file
|
@ -0,0 +1,503 @@
|
|||
## API Report File for "@tldraw/sync-core"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
|
||||
import { Atom } from '@tldraw/state';
|
||||
import { Emitter } from 'nanoevents';
|
||||
import { RecordsDiff } from '@tldraw/store';
|
||||
import { RecordType } from '@tldraw/store';
|
||||
import { Result } from '@tldraw/utils';
|
||||
import { SerializedSchema } from '@tldraw/store';
|
||||
import { Signal } from '@tldraw/state';
|
||||
import { Store } from '@tldraw/store';
|
||||
import { StoreSchema } from '@tldraw/store';
|
||||
import { TLRecord } from '@tldraw/tlschema';
|
||||
import { UnknownRecord } from '@tldraw/store';
|
||||
|
||||
// @public (undocumented)
|
||||
export type AppendOp = [type: typeof ValueOpType.Append, values: unknown[], offset: number];
|
||||
|
||||
// @public (undocumented)
|
||||
export function applyObjectDiff<T extends object>(object: T, objectDiff: ObjectDiff): T;
|
||||
|
||||
// @public (undocumented)
|
||||
export function chunk(msg: string, maxSafeMessageSize?: number): string[];
|
||||
|
||||
// @public (undocumented)
|
||||
export class ClientWebSocketAdapter implements TLPersistentClientSocket<TLRecord> {
|
||||
constructor(getUri: () => Promise<string> | string);
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
// (undocumented)
|
||||
_closeSocket(): void;
|
||||
// (undocumented)
|
||||
get connectionStatus(): TLPersistentClientSocketStatus;
|
||||
// (undocumented)
|
||||
_connectionStatus: Atom<'initial' | TLPersistentClientSocketStatus>;
|
||||
// (undocumented)
|
||||
isDisposed: boolean;
|
||||
// (undocumented)
|
||||
onReceiveMessage(cb: (val: TLSocketServerSentEvent<TLRecord>) => void): () => void;
|
||||
// (undocumented)
|
||||
onStatusChange(cb: (val: TLPersistentClientSocketStatus, closeCode?: number) => void): () => void;
|
||||
// @internal (undocumented)
|
||||
readonly _reconnectManager: ReconnectManager;
|
||||
// (undocumented)
|
||||
restart(): void;
|
||||
// (undocumented)
|
||||
sendMessage(msg: TLSocketClientSentEvent<TLRecord>): void;
|
||||
// (undocumented)
|
||||
_setNewSocket(ws: WebSocket): void;
|
||||
// (undocumented)
|
||||
_ws: null | WebSocket;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type DeleteOp = [type: typeof ValueOpType.Delete];
|
||||
|
||||
// @public (undocumented)
|
||||
export function diffRecord(prev: object, next: object): null | ObjectDiff;
|
||||
|
||||
// @internal (undocumented)
|
||||
export class DocumentState<R extends UnknownRecord> {
|
||||
// (undocumented)
|
||||
_atom: Atom<{
|
||||
lastChangedClock: number;
|
||||
state: R;
|
||||
}>;
|
||||
// (undocumented)
|
||||
static createAndValidate<R extends UnknownRecord>(state: R, lastChangedClock: number, recordType: RecordType<R, any>): Result<DocumentState<R>, Error>;
|
||||
// (undocumented)
|
||||
static createWithoutValidating<R extends UnknownRecord>(state: R, lastChangedClock: number, recordType: RecordType<R, any>): DocumentState<R>;
|
||||
// (undocumented)
|
||||
get lastChangedClock(): number;
|
||||
// (undocumented)
|
||||
mergeDiff(diff: ObjectDiff, clock: number): Result<null | ObjectDiff, Error>;
|
||||
// (undocumented)
|
||||
replaceState(state: R, clock: number): Result<null | ObjectDiff, Error>;
|
||||
// (undocumented)
|
||||
get state(): R;
|
||||
}
|
||||
|
||||
// @public
|
||||
export const getNetworkDiff: <R extends UnknownRecord>(diff: RecordsDiff<R>) => NetworkDiff<R> | null;
|
||||
|
||||
// @public (undocumented)
|
||||
export function getTlsyncProtocolVersion(): number;
|
||||
|
||||
// @public
|
||||
export interface NetworkDiff<R extends UnknownRecord> {
|
||||
// (undocumented)
|
||||
[id: string]: RecordOp<R>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface ObjectDiff {
|
||||
// (undocumented)
|
||||
[k: string]: ValueOp;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type PatchOp = [type: typeof ValueOpType.Patch, diff: ObjectDiff];
|
||||
|
||||
// @public (undocumented)
|
||||
export interface PersistedRoomSnapshotForSupabase {
|
||||
// (undocumented)
|
||||
drawing: RoomSnapshot;
|
||||
// (undocumented)
|
||||
id: string;
|
||||
// (undocumented)
|
||||
slug: string;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type PutOp = [type: typeof ValueOpType.Put, value: unknown];
|
||||
|
||||
// @internal (undocumented)
|
||||
export class ReconnectManager {
|
||||
constructor(socketAdapter: ClientWebSocketAdapter, getUri: () => Promise<string> | string);
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
// (undocumented)
|
||||
connected(): void;
|
||||
// (undocumented)
|
||||
disconnected(): void;
|
||||
// (undocumented)
|
||||
intendedDelay: number;
|
||||
// (undocumented)
|
||||
maybeReconnected(): void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type RecordOp<R extends UnknownRecord> = [typeof RecordOpType.Patch, ObjectDiff] | [typeof RecordOpType.Put, R] | [typeof RecordOpType.Remove];
|
||||
|
||||
// @public (undocumented)
|
||||
export const RecordOpType: {
|
||||
readonly Patch: "patch";
|
||||
readonly Put: "put";
|
||||
readonly Remove: "remove";
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type RecordOpType = (typeof RecordOpType)[keyof typeof RecordOpType];
|
||||
|
||||
// @public (undocumented)
|
||||
export type RoomSession<R extends UnknownRecord, Meta> = {
|
||||
cancellationTime: number;
|
||||
meta: Meta;
|
||||
presenceId: string;
|
||||
sessionKey: string;
|
||||
socket: TLRoomSocket<R>;
|
||||
state: typeof RoomSessionState.AwaitingRemoval;
|
||||
} | {
|
||||
debounceTimer: null | ReturnType<typeof setTimeout>;
|
||||
lastInteractionTime: number;
|
||||
meta: Meta;
|
||||
outstandingDataMessages: TLSocketServerSentDataEvent<R>[];
|
||||
presenceId: string;
|
||||
serializedSchema: SerializedSchema;
|
||||
sessionKey: string;
|
||||
socket: TLRoomSocket<R>;
|
||||
state: typeof RoomSessionState.Connected;
|
||||
} | {
|
||||
meta: Meta;
|
||||
presenceId: string;
|
||||
sessionKey: string;
|
||||
sessionStartTime: number;
|
||||
socket: TLRoomSocket<R>;
|
||||
state: typeof RoomSessionState.AwaitingConnectMessage;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export const RoomSessionState: {
|
||||
readonly AwaitingConnectMessage: "awaiting-connect-message";
|
||||
readonly AwaitingRemoval: "awaiting-removal";
|
||||
readonly Connected: "connected";
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type RoomSessionState = (typeof RoomSessionState)[keyof typeof RoomSessionState];
|
||||
|
||||
// @public (undocumented)
|
||||
export interface RoomSnapshot {
|
||||
// (undocumented)
|
||||
clock: number;
|
||||
// (undocumented)
|
||||
documents: Array<{
|
||||
lastChangedClock: number;
|
||||
state: UnknownRecord;
|
||||
}>;
|
||||
// (undocumented)
|
||||
schema?: SerializedSchema;
|
||||
// (undocumented)
|
||||
tombstones?: Record<string, number>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type SubscribingFn<T> = (cb: (val: T) => void) => () => void;
|
||||
|
||||
// @public
|
||||
export const TLCloseEventCode: {
|
||||
readonly NOT_FOUND: 4099;
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export interface TLConnectRequest {
|
||||
// (undocumented)
|
||||
connectRequestId: string;
|
||||
// (undocumented)
|
||||
lastServerClock: number;
|
||||
// (undocumented)
|
||||
protocolVersion: number;
|
||||
// (undocumented)
|
||||
schema: SerializedSchema;
|
||||
// (undocumented)
|
||||
type: 'connect';
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export const TLIncompatibilityReason: {
|
||||
readonly ClientTooOld: "clientTooOld";
|
||||
readonly InvalidOperation: "invalidOperation";
|
||||
readonly InvalidRecord: "invalidRecord";
|
||||
readonly RoomNotFound: "roomNotFound";
|
||||
readonly ServerTooOld: "serverTooOld";
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLIncompatibilityReason = (typeof TLIncompatibilityReason)[keyof typeof TLIncompatibilityReason];
|
||||
|
||||
// @public
|
||||
export interface TLPersistentClientSocket<R extends UnknownRecord = UnknownRecord> {
|
||||
connectionStatus: 'error' | 'offline' | 'online';
|
||||
onReceiveMessage: SubscribingFn<TLSocketServerSentEvent<R>>;
|
||||
onStatusChange: SubscribingFn<TLPersistentClientSocketStatus>;
|
||||
restart: () => void;
|
||||
sendMessage: (msg: TLSocketClientSentEvent<R>) => void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLPersistentClientSocketStatus = 'error' | 'offline' | 'online';
|
||||
|
||||
// @public (undocumented)
|
||||
export interface TLPingRequest {
|
||||
// (undocumented)
|
||||
type: 'ping';
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface TLPushRequest<R extends UnknownRecord> {
|
||||
// (undocumented)
|
||||
clientClock: number;
|
||||
// (undocumented)
|
||||
diff?: NetworkDiff<R>;
|
||||
// (undocumented)
|
||||
presence?: [typeof RecordOpType.Patch, ObjectDiff] | [typeof RecordOpType.Put, R];
|
||||
// (undocumented)
|
||||
type: 'push';
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export class TLRemoteSyncError extends Error {
|
||||
constructor(reason: TLIncompatibilityReason);
|
||||
// (undocumented)
|
||||
name: string;
|
||||
// (undocumented)
|
||||
readonly reason: TLIncompatibilityReason;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface TLRoomSocket<R extends UnknownRecord> {
|
||||
// (undocumented)
|
||||
close: () => void;
|
||||
// (undocumented)
|
||||
isOpen: boolean;
|
||||
// (undocumented)
|
||||
sendMessage: (msg: TLSocketServerSentEvent<R>) => void;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLSocketClientSentEvent<R extends UnknownRecord> = TLConnectRequest | TLPingRequest | TLPushRequest<R>;
|
||||
|
||||
// @public (undocumented)
|
||||
export class TLSocketRoom<R extends UnknownRecord, SessionMeta> {
|
||||
constructor(opts: {
|
||||
clientTimeout?: number;
|
||||
initialSnapshot?: RoomSnapshot;
|
||||
log?: TLSyncLog;
|
||||
onAfterReceiveMessage?: (args: {
|
||||
message: TLSocketServerSentEvent<R>;
|
||||
meta: SessionMeta;
|
||||
sessionId: string;
|
||||
stringified: string;
|
||||
}) => void;
|
||||
onBeforeSendMessage?: (args: {
|
||||
message: TLSocketServerSentEvent<R>;
|
||||
meta: SessionMeta;
|
||||
sessionId: string;
|
||||
stringified: string;
|
||||
}) => void;
|
||||
onDataChange?: () => void;
|
||||
onSessionRemoved?: (room: TLSocketRoom<R, SessionMeta>, args: {
|
||||
meta: SessionMeta;
|
||||
numSessionsRemaining: number;
|
||||
sessionKey: string;
|
||||
}) => void;
|
||||
schema?: StoreSchema<R, any>;
|
||||
});
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
// (undocumented)
|
||||
getCurrentDocumentClock(): number;
|
||||
// (undocumented)
|
||||
getCurrentSnapshot(): RoomSnapshot;
|
||||
// (undocumented)
|
||||
getNumActiveSessions(): number;
|
||||
// (undocumented)
|
||||
handleSocketClose(sessionId: string): void;
|
||||
// (undocumented)
|
||||
handleSocketConnect(sessionId: string, socket: WebSocket, meta: SessionMeta): void;
|
||||
// (undocumented)
|
||||
handleSocketError(sessionId: string): void;
|
||||
// (undocumented)
|
||||
handleSocketMessage(sessionId: string, message: ArrayBuffer | string): void;
|
||||
// (undocumented)
|
||||
loadSnapshot(snapshot: RoomSnapshot): void;
|
||||
// (undocumented)
|
||||
readonly log: TLSyncLog;
|
||||
// (undocumented)
|
||||
readonly opts: {
|
||||
clientTimeout?: number;
|
||||
initialSnapshot?: RoomSnapshot;
|
||||
log?: TLSyncLog;
|
||||
onAfterReceiveMessage?: (args: {
|
||||
message: TLSocketServerSentEvent<R>;
|
||||
meta: SessionMeta;
|
||||
sessionId: string;
|
||||
stringified: string;
|
||||
}) => void;
|
||||
onBeforeSendMessage?: (args: {
|
||||
message: TLSocketServerSentEvent<R>;
|
||||
meta: SessionMeta;
|
||||
sessionId: string;
|
||||
stringified: string;
|
||||
}) => void;
|
||||
onDataChange?: () => void;
|
||||
onSessionRemoved?: (room: TLSocketRoom<R, SessionMeta>, args: {
|
||||
meta: SessionMeta;
|
||||
numSessionsRemaining: number;
|
||||
sessionKey: string;
|
||||
}) => void;
|
||||
schema?: StoreSchema<R, any>;
|
||||
};
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLSocketServerSentDataEvent<R extends UnknownRecord> = {
|
||||
action: 'commit' | 'discard' | {
|
||||
rebaseWithDiff: NetworkDiff<R>;
|
||||
};
|
||||
clientClock: number;
|
||||
serverClock: number;
|
||||
type: 'push_result';
|
||||
} | {
|
||||
diff: NetworkDiff<R>;
|
||||
serverClock: number;
|
||||
type: 'patch';
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type TLSocketServerSentEvent<R extends UnknownRecord> = {
|
||||
connectRequestId: string;
|
||||
diff: NetworkDiff<R>;
|
||||
hydrationType: 'wipe_all' | 'wipe_presence';
|
||||
protocolVersion: number;
|
||||
schema: SerializedSchema;
|
||||
serverClock: number;
|
||||
type: 'connect';
|
||||
} | {
|
||||
data: TLSocketServerSentDataEvent<R>[];
|
||||
type: 'data';
|
||||
} | {
|
||||
error?: any;
|
||||
type: 'error';
|
||||
} | {
|
||||
reason: TLIncompatibilityReason;
|
||||
type: 'incompatibility_error';
|
||||
} | {
|
||||
type: 'pong';
|
||||
} | TLSocketServerSentDataEvent<R>;
|
||||
|
||||
// @public
|
||||
export class TLSyncClient<R extends UnknownRecord, S extends Store<R> = Store<R>> {
|
||||
constructor(config: {
|
||||
didCancel?: () => boolean;
|
||||
onAfterConnect?: (self: TLSyncClient<R, S>, isNew: boolean) => void;
|
||||
onLoad: (self: TLSyncClient<R, S>) => void;
|
||||
onLoadError: (error: Error) => void;
|
||||
onSyncError: (reason: TLIncompatibilityReason) => void;
|
||||
presence: Signal<null | R>;
|
||||
socket: TLPersistentClientSocket<R>;
|
||||
store: S;
|
||||
});
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
// (undocumented)
|
||||
didCancel?: () => boolean;
|
||||
// (undocumented)
|
||||
incomingDiffBuffer: TLSocketServerSentDataEvent<R>[];
|
||||
// (undocumented)
|
||||
isConnectedToRoom: boolean;
|
||||
// (undocumented)
|
||||
lastPushedPresenceState: null | R;
|
||||
// (undocumented)
|
||||
latestConnectRequestId: null | string;
|
||||
readonly onAfterConnect?: (self: TLSyncClient<R, S>, isNew: boolean) => void;
|
||||
// (undocumented)
|
||||
readonly onSyncError: (reason: TLIncompatibilityReason) => void;
|
||||
// (undocumented)
|
||||
readonly presenceState: Signal<null | R> | undefined;
|
||||
// (undocumented)
|
||||
readonly socket: TLPersistentClientSocket<R>;
|
||||
// (undocumented)
|
||||
readonly store: S;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export interface TLSyncLog {
|
||||
// (undocumented)
|
||||
error?: (...args: any[]) => void;
|
||||
// (undocumented)
|
||||
info?: (...args: any[]) => void;
|
||||
// (undocumented)
|
||||
warn?: (...args: any[]) => void;
|
||||
}
|
||||
|
||||
// @public
|
||||
export class TLSyncRoom<R extends UnknownRecord, SessionMeta> {
|
||||
constructor(schema: StoreSchema<R, any>, snapshot?: RoomSnapshot);
|
||||
broadcastPatch({ diff, sourceSessionKey: sourceSessionKey, }: {
|
||||
diff: NetworkDiff<R>;
|
||||
sourceSessionKey: string;
|
||||
}): this;
|
||||
// (undocumented)
|
||||
clock: number;
|
||||
// (undocumented)
|
||||
close(): void;
|
||||
// (undocumented)
|
||||
documentClock: number;
|
||||
// (undocumented)
|
||||
readonly documentTypes: Set<string>;
|
||||
// (undocumented)
|
||||
readonly events: Emitter< {
|
||||
room_became_empty: () => void;
|
||||
session_removed: (args: {
|
||||
meta: SessionMeta;
|
||||
sessionKey: string;
|
||||
}) => void;
|
||||
}>;
|
||||
// (undocumented)
|
||||
_flushDataMessages(sessionKey: string): void;
|
||||
// (undocumented)
|
||||
getSnapshot(): RoomSnapshot;
|
||||
handleClose: (sessionKey: string) => void;
|
||||
handleMessage: (sessionKey: string, message: TLSocketClientSentEvent<R>) => Promise<void>;
|
||||
handleNewSession: (sessionKey: string, socket: TLRoomSocket<R>, meta: SessionMeta) => this;
|
||||
// (undocumented)
|
||||
readonly presenceType: RecordType<R, any>;
|
||||
// (undocumented)
|
||||
pruneSessions: () => void;
|
||||
// (undocumented)
|
||||
readonly schema: StoreSchema<R, any>;
|
||||
// (undocumented)
|
||||
readonly serializedSchema: SerializedSchema;
|
||||
// (undocumented)
|
||||
readonly sessions: Map<string, RoomSession<R, SessionMeta>>;
|
||||
// @internal (undocumented)
|
||||
state: Atom<{
|
||||
documents: Record<string, DocumentState<R>>;
|
||||
tombstones: Record<string, number>;
|
||||
}, unknown>;
|
||||
// (undocumented)
|
||||
tombstoneHistoryStartsAtClock: number;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export type ValueOp = AppendOp | DeleteOp | PatchOp | PutOp;
|
||||
|
||||
// @public (undocumented)
|
||||
export const ValueOpType: {
|
||||
readonly Append: "append";
|
||||
readonly Delete: "delete";
|
||||
readonly Patch: "patch";
|
||||
readonly Put: "put";
|
||||
};
|
||||
|
||||
// @public (undocumented)
|
||||
export type ValueOpType = (typeof ValueOpType)[keyof typeof ValueOpType];
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"name": "@tldraw/sync-core",
|
||||
"description": "A tiny little drawing app (multiplayer sync).",
|
||||
"version": "2.0.0-alpha.11",
|
||||
"private": true,
|
||||
"version": "2.3.0",
|
||||
"author": {
|
||||
"name": "tldraw GB Ltd.",
|
||||
"email": "hello@tldraw.com"
|
||||
|
@ -34,7 +33,12 @@
|
|||
"test-ci": "lazy inherit",
|
||||
"test": "yarn run -T jest",
|
||||
"test-coverage": "lazy inherit",
|
||||
"lint": "yarn run -T tsx ../../scripts/lint.ts"
|
||||
"lint": "yarn run -T tsx ../../scripts/lint.ts",
|
||||
"build": "yarn run -T tsx ../../scripts/build-package.ts",
|
||||
"build-api": "yarn run -T tsx ../../scripts/build-api.ts",
|
||||
"prepack": "yarn run -T tsx ../../scripts/prepack.ts",
|
||||
"postpack": "../../scripts/postpack.sh",
|
||||
"pack-tarball": "yarn pack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"tldraw": "workspace:*",
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
export { ClientWebSocketAdapter } from './lib/ClientWebSocketAdapter'
|
||||
export { ClientWebSocketAdapter, ReconnectManager } from './lib/ClientWebSocketAdapter'
|
||||
export { RoomSessionState, type RoomSession } from './lib/RoomSession'
|
||||
export { TLRemoteSyncError } from './lib/TLRemoteSyncError'
|
||||
export { TLSocketRoom } from './lib/TLSocketRoom'
|
||||
export { TLSocketRoom, type TLSyncLog } from './lib/TLSocketRoom'
|
||||
export {
|
||||
TLCloseEventCode,
|
||||
TLSyncClient,
|
||||
type SubscribingFn,
|
||||
type TLPersistentClientSocket,
|
||||
type TLPersistentClientSocketStatus,
|
||||
} from './lib/TLSyncClient'
|
||||
export { TLSyncRoom, type RoomSnapshot, type TLRoomSocket } from './lib/TLSyncRoom'
|
||||
export { DocumentState, TLSyncRoom, type RoomSnapshot, type TLRoomSocket } from './lib/TLSyncRoom'
|
||||
export { chunk } from './lib/chunk'
|
||||
export {
|
||||
RecordOpType,
|
||||
|
@ -31,6 +33,7 @@ export {
|
|||
type TLPingRequest,
|
||||
type TLPushRequest,
|
||||
type TLSocketClientSentEvent,
|
||||
type TLSocketServerSentDataEvent,
|
||||
type TLSocketServerSentEvent,
|
||||
} from './lib/protocol'
|
||||
export type { PersistedRoomSnapshotForSupabase } from './lib/server-types'
|
||||
|
|
|
@ -40,11 +40,13 @@ function debug(...args: any[]) {
|
|||
// pings need to be implemented one level up, on the application API side, which for our
|
||||
// codebase means whatever code that uses ClientWebSocketAdapter.
|
||||
|
||||
/** @public */
|
||||
export class ClientWebSocketAdapter implements TLPersistentClientSocket<TLRecord> {
|
||||
_ws: WebSocket | null = null
|
||||
|
||||
isDisposed = false
|
||||
|
||||
/** @internal */
|
||||
readonly _reconnectManager: ReconnectManager
|
||||
|
||||
// TODO: .close should be a project-wide interface with a common contract (.close()d thing
|
||||
|
@ -235,7 +237,8 @@ export const DELAY_EXPONENT = 1.5
|
|||
// not needlessly reconnecting if the connection is just slow to establish
|
||||
export const ATTEMPT_TIMEOUT = 1000
|
||||
|
||||
class ReconnectManager {
|
||||
/** @internal */
|
||||
export class ReconnectManager {
|
||||
private isDisposed = false
|
||||
private disposables: (() => void)[] = [
|
||||
() => {
|
||||
|
|
|
@ -2,18 +2,21 @@ import { SerializedSchema, UnknownRecord } from '@tldraw/store'
|
|||
import { TLRoomSocket } from './TLSyncRoom'
|
||||
import { TLSocketServerSentDataEvent } from './protocol'
|
||||
|
||||
/** @public */
|
||||
export const RoomSessionState = {
|
||||
AwaitingConnectMessage: 'awaiting-connect-message',
|
||||
AwaitingRemoval: 'awaiting-removal',
|
||||
Connected: 'connected',
|
||||
} as const
|
||||
|
||||
/** @public */
|
||||
export type RoomSessionState = (typeof RoomSessionState)[keyof typeof RoomSessionState]
|
||||
|
||||
export const SESSION_START_WAIT_TIME = 10000
|
||||
export const SESSION_REMOVAL_WAIT_TIME = 10000
|
||||
export const SESSION_IDLE_TIMEOUT = 20000
|
||||
|
||||
/** @public */
|
||||
export type RoomSession<R extends UnknownRecord, Meta> =
|
||||
| {
|
||||
state: typeof RoomSessionState.AwaitingConnectMessage
|
||||
|
|
|
@ -6,12 +6,14 @@ import { JsonChunkAssembler } from './chunk'
|
|||
import { TLSocketServerSentEvent } from './protocol'
|
||||
|
||||
// TODO: structured logging support
|
||||
interface TLSyncLog {
|
||||
/** @public */
|
||||
export interface TLSyncLog {
|
||||
info?: (...args: any[]) => void
|
||||
warn?: (...args: any[]) => void
|
||||
error?: (...args: any[]) => void
|
||||
}
|
||||
|
||||
/** @public */
|
||||
export class TLSocketRoom<R extends UnknownRecord, SessionMeta> {
|
||||
private room: TLSyncRoom<R, SessionMeta>
|
||||
private readonly sessions = new Map<
|
||||
|
|
|
@ -21,10 +21,11 @@ import {
|
|||
getTlsyncProtocolVersion,
|
||||
} from './protocol'
|
||||
|
||||
type SubscribingFn<T> = (cb: (val: T) => void) => () => void
|
||||
/** @public */
|
||||
export type SubscribingFn<T> = (cb: (val: T) => void) => () => void
|
||||
|
||||
/**
|
||||
* These are our private codes to be sent from server->client.
|
||||
* These are our private codes to be sent from server-\>client.
|
||||
* They are in the private range of the websocket code range.
|
||||
* See: https://developer.mozilla.org/en-US/docs/Web/API/CloseEvent/code
|
||||
*
|
||||
|
|
|
@ -63,7 +63,8 @@ export const DATA_MESSAGE_DEBOUNCE_INTERVAL = 1000 / 60
|
|||
|
||||
const timeSince = (time: number) => Date.now() - time
|
||||
|
||||
class DocumentState<R extends UnknownRecord> {
|
||||
/** @internal */
|
||||
export class DocumentState<R extends UnknownRecord> {
|
||||
_atom: Atom<{ state: R; lastChangedClock: number }>
|
||||
|
||||
static createWithoutValidating<R extends UnknownRecord>(
|
||||
|
@ -184,6 +185,7 @@ export class TLSyncRoom<R extends UnknownRecord, SessionMeta> {
|
|||
}>()
|
||||
|
||||
// Values associated with each uid (must be serializable).
|
||||
/** @internal */
|
||||
state = atom<{
|
||||
documents: Record<string, DocumentState<R>>
|
||||
tombstones: Record<string, number>
|
||||
|
|
|
@ -8,6 +8,7 @@ const MAX_BYTES_PER_CHAR = 4
|
|||
// in the (admittedly impossible) worst case, the max size is 1/4 of a megabyte
|
||||
const MAX_SAFE_MESSAGE_SIZE = MAX_CLIENT_SENT_MESSAGE_SIZE_BYTES / MAX_BYTES_PER_CHAR
|
||||
|
||||
/** @public */
|
||||
export function chunk(msg: string, maxSafeMessageSize = MAX_SAFE_MESSAGE_SIZE) {
|
||||
if (msg.length < maxSafeMessageSize) {
|
||||
return [msg]
|
||||
|
|
|
@ -69,6 +69,7 @@ export const ValueOpType = {
|
|||
Append: 'append',
|
||||
Patch: 'patch',
|
||||
} as const
|
||||
/** @public */
|
||||
export type ValueOpType = (typeof ValueOpType)[keyof typeof ValueOpType]
|
||||
|
||||
/** @public */
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { SerializedSchema, UnknownRecord } from '@tldraw/store'
|
||||
import { NetworkDiff, ObjectDiff, RecordOpType } from './diff'
|
||||
|
||||
/** @public */
|
||||
const TLSYNC_PROTOCOL_VERSION = 6
|
||||
|
||||
/** @public */
|
||||
export function getTlsyncProtocolVersion() {
|
||||
return TLSYNC_PROTOCOL_VERSION
|
||||
}
|
||||
|
|
64
packages/sync/api-report.md
Normal file
64
packages/sync/api-report.md
Normal file
|
@ -0,0 +1,64 @@
|
|||
## API Report File for "@tldraw/sync"
|
||||
|
||||
> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
|
||||
|
||||
```ts
|
||||
|
||||
import { Editor } from 'tldraw';
|
||||
import { Signal } from 'tldraw';
|
||||
import { TLAssetStore } from 'tldraw';
|
||||
import { TLSchema } from 'tldraw';
|
||||
import { TLStoreWithStatus } from 'tldraw';
|
||||
import { TLUserPreferences } from 'tldraw';
|
||||
|
||||
// @public (undocumented)
|
||||
export type RemoteTLStoreWithStatus = Exclude<TLStoreWithStatus, {
|
||||
status: 'not-synced';
|
||||
} | {
|
||||
status: 'synced-local';
|
||||
}>;
|
||||
|
||||
// @public (undocumented)
|
||||
export function useMultiplayerDemo(options: UseMultiplayerDemoOptions): RemoteTLStoreWithStatus;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UseMultiplayerDemoOptions {
|
||||
// @internal (undocumented)
|
||||
host?: string;
|
||||
// (undocumented)
|
||||
roomId: string;
|
||||
// (undocumented)
|
||||
schema?: TLSchema;
|
||||
// (undocumented)
|
||||
userPreferences?: Signal<TLUserPreferences>;
|
||||
}
|
||||
|
||||
// @public (undocumented)
|
||||
export function useMultiplayerSync(opts: UseMultiplayerSyncOptions): RemoteTLStoreWithStatus;
|
||||
|
||||
// @public (undocumented)
|
||||
export interface UseMultiplayerSyncOptions {
|
||||
// (undocumented)
|
||||
assets?: Partial<TLAssetStore>;
|
||||
// (undocumented)
|
||||
onEditorMount?: (editor: Editor) => void;
|
||||
// (undocumented)
|
||||
roomId?: string;
|
||||
// (undocumented)
|
||||
schema?: TLSchema;
|
||||
// (undocumented)
|
||||
trackAnalyticsEvent?(name: string, data: {
|
||||
[key: string]: any;
|
||||
}): void;
|
||||
// (undocumented)
|
||||
uri: string;
|
||||
// (undocumented)
|
||||
userPreferences?: Signal<TLUserPreferences>;
|
||||
}
|
||||
|
||||
|
||||
export * from "@tldraw/sync-core";
|
||||
|
||||
// (No @packageDocumentation comment for this package)
|
||||
|
||||
```
|
|
@ -1,8 +1,7 @@
|
|||
{
|
||||
"name": "@tldraw/sync",
|
||||
"description": "A tiny little drawing app (multiplayer sync react bindings).",
|
||||
"version": "2.0.0-alpha.11",
|
||||
"private": true,
|
||||
"version": "2.3.0",
|
||||
"author": {
|
||||
"name": "tldraw GB Ltd.",
|
||||
"email": "hello@tldraw.com"
|
||||
|
@ -34,7 +33,12 @@
|
|||
"test-ci": "lazy inherit",
|
||||
"test": "yarn run -T jest",
|
||||
"test-coverage": "lazy inherit",
|
||||
"lint": "yarn run -T tsx ../../scripts/lint.ts"
|
||||
"lint": "yarn run -T tsx ../../scripts/lint.ts",
|
||||
"build": "yarn run -T tsx ../../scripts/build-package.ts",
|
||||
"build-api": "yarn run -T tsx ../../scripts/build-api.ts",
|
||||
"prepack": "yarn run -T tsx ../../scripts/prepack.ts",
|
||||
"postpack": "../../scripts/postpack.sh",
|
||||
"pack-tarball": "yarn pack"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^5.3.3",
|
||||
|
|
|
@ -41,12 +41,9 @@ function getEnv(cb: () => string | undefined): string | undefined {
|
|||
const DEMO_WORKER = getEnv(() => process.env.TLDRAW_BEMO_URL) ?? 'https://demo.tldraw.xyz'
|
||||
const IMAGE_WORKER = getEnv(() => process.env.TLDRAW_IMAGE_URL) ?? 'https://images.tldraw.xyz'
|
||||
|
||||
export function useMultiplayerDemo({
|
||||
roomId,
|
||||
userPreferences,
|
||||
host = DEMO_WORKER,
|
||||
schema,
|
||||
}: UseMultiplayerDemoOptions): RemoteTLStoreWithStatus {
|
||||
/** @public */
|
||||
export function useMultiplayerDemo(options: UseMultiplayerDemoOptions): RemoteTLStoreWithStatus {
|
||||
const { roomId, userPreferences, host = DEMO_WORKER, schema } = options
|
||||
const assets = useMemo(() => createDemoAssetStore(host), [host])
|
||||
|
||||
return useMultiplayerSync({
|
||||
|
|
|
@ -11,8 +11,7 @@ const packagesOurTypesCanDependOn = [
|
|||
'@types/react',
|
||||
'@types/react-dom',
|
||||
'eventemitter3',
|
||||
// todo: external types shouldn't depend on this
|
||||
'@types/ws',
|
||||
'nanoevents',
|
||||
]
|
||||
|
||||
main()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { build } from 'esbuild'
|
||||
import { BuildOptions, build } from 'esbuild'
|
||||
import { copyFileSync, existsSync } from 'fs'
|
||||
import glob from 'glob'
|
||||
import kleur from 'kleur'
|
||||
|
@ -42,6 +42,20 @@ async function buildPackage({ sourcePackageDir }: { sourcePackageDir: string })
|
|||
)
|
||||
}
|
||||
|
||||
function getCommonEsbuildOptions() {
|
||||
const define: Record<string, string> = {}
|
||||
if (process.env.TLDRAW_BEMO_URL) {
|
||||
define['process.env.TLDRAW_BEMO_URL'] = JSON.stringify(process.env.TLDRAW_BEMO_URL)
|
||||
}
|
||||
|
||||
return {
|
||||
bundle: false,
|
||||
platform: 'neutral',
|
||||
sourcemap: true,
|
||||
define,
|
||||
} satisfies BuildOptions
|
||||
}
|
||||
|
||||
/** This uses esbuild to build the esm version of the package */
|
||||
async function buildEsm({
|
||||
sourceFiles,
|
||||
|
@ -55,11 +69,9 @@ async function buildEsm({
|
|||
const res = await build({
|
||||
entryPoints: sourceFiles,
|
||||
outdir,
|
||||
bundle: false,
|
||||
platform: 'neutral',
|
||||
sourcemap: true,
|
||||
format: 'esm',
|
||||
outExtension: { '.js': '.mjs' },
|
||||
...getCommonEsbuildOptions(),
|
||||
})
|
||||
|
||||
addJsExtensions(path.join(sourcePackageDir, 'dist-esm'))
|
||||
|
@ -84,10 +96,8 @@ async function buildCjs({
|
|||
const res = await build({
|
||||
entryPoints: sourceFiles,
|
||||
outdir,
|
||||
bundle: false,
|
||||
platform: 'neutral',
|
||||
sourcemap: true,
|
||||
format: 'cjs',
|
||||
...getCommonEsbuildOptions(),
|
||||
})
|
||||
|
||||
if (res.errors.length) {
|
||||
|
|
Loading…
Reference in a new issue