reflectdb 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +1260 -0
- package/dist/cjs/client/index.cjs +1252 -0
- package/dist/cjs/client/index.d.cts +629 -0
- package/dist/cjs/client/storage/indexeddb.cjs +253 -0
- package/dist/cjs/client/storage/indexeddb.d.cts +85 -0
- package/dist/cjs/core/index.cjs +202 -0
- package/dist/cjs/core/index.d.cts +473 -0
- package/dist/cjs/react/index.cjs +1512 -0
- package/dist/cjs/react/index.d.cts +748 -0
- package/dist/cjs/server/drizzle.cjs +413 -0
- package/dist/cjs/server/drizzle.d.cts +233 -0
- package/dist/cjs/server/index.cjs +4486 -0
- package/dist/cjs/server/index.d.cts +1988 -0
- package/dist/cjs/svelte/index.cjs +1414 -0
- package/dist/cjs/svelte/index.d.cts +645 -0
- package/dist/cjs/transport/bun-ws.cjs +244 -0
- package/dist/cjs/transport/bun-ws.d.cts +215 -0
- package/dist/cjs/transport/polling.cjs +285 -0
- package/dist/cjs/transport/polling.d.cts +210 -0
- package/dist/cjs/transport/sse.cjs +312 -0
- package/dist/cjs/transport/sse.d.cts +205 -0
- package/dist/cjs/transport/ws.cjs +330 -0
- package/dist/cjs/transport/ws.d.cts +236 -0
- package/dist/cjs/vanilla/index.cjs +1430 -0
- package/dist/cjs/vanilla/index.d.cts +657 -0
- package/dist/client/index.d.ts +629 -0
- package/dist/client/index.js +106 -0
- package/dist/client/storage/indexeddb.d.ts +85 -0
- package/dist/client/storage/indexeddb.js +213 -0
- package/dist/core/index.d.ts +473 -0
- package/dist/core/index.js +56 -0
- package/dist/react/index.d.ts +748 -0
- package/dist/react/index.js +366 -0
- package/dist/server/drizzle.d.ts +233 -0
- package/dist/server/drizzle.js +9 -0
- package/dist/server/index.d.ts +1988 -0
- package/dist/server/index.js +3959 -0
- package/dist/shared/esm-3tkwvysa.js +54 -0
- package/dist/shared/esm-b7xs9cde.js +4 -0
- package/dist/shared/esm-rw7jjtrv.js +58 -0
- package/dist/shared/esm-wkwx6bd9.js +25 -0
- package/dist/shared/esm-ytrd3hbq.js +1007 -0
- package/dist/shared/esm-z1xse19c.js +369 -0
- package/dist/svelte/index.d.ts +645 -0
- package/dist/svelte/index.js +262 -0
- package/dist/transport/bun-ws.d.ts +215 -0
- package/dist/transport/bun-ws.js +140 -0
- package/dist/transport/polling.d.ts +210 -0
- package/dist/transport/polling.js +181 -0
- package/dist/transport/sse.d.ts +205 -0
- package/dist/transport/sse.js +208 -0
- package/dist/transport/ws.d.ts +236 -0
- package/dist/transport/ws.js +226 -0
- package/dist/vanilla/index.d.ts +657 -0
- package/dist/vanilla/index.js +278 -0
- package/package.json +253 -0
|
@@ -0,0 +1,473 @@
|
|
|
1
|
+
interface HLC {
|
|
2
|
+
ms: number;
|
|
3
|
+
counter: number;
|
|
4
|
+
nodeId: string;
|
|
5
|
+
}
|
|
6
|
+
declare function createHlc(nodeId: string): HLC;
|
|
7
|
+
declare function sendHlc(local: HLC): HLC;
|
|
8
|
+
declare function receiveHlc(local: HLC, remote: HLC): HLC;
|
|
9
|
+
declare function packHlc(hlc: HLC): string;
|
|
10
|
+
declare function unpackHlc(packed: string): HLC;
|
|
11
|
+
declare function compareHlc(a: string, b: string): number;
|
|
12
|
+
type OpType = "insert" | "update" | "delete";
|
|
13
|
+
type OpStatus = "pending" | "synced" | "rejected";
|
|
14
|
+
interface SyncOp {
|
|
15
|
+
id: string;
|
|
16
|
+
nodeId: string;
|
|
17
|
+
userId: string;
|
|
18
|
+
hlc: string;
|
|
19
|
+
op: OpType;
|
|
20
|
+
tableName: string;
|
|
21
|
+
rowId: string;
|
|
22
|
+
payload: Record<string, unknown> | null;
|
|
23
|
+
status: OpStatus;
|
|
24
|
+
rejectedReason: ErrorReason | null;
|
|
25
|
+
batchId: string | null;
|
|
26
|
+
batchSize: number | null;
|
|
27
|
+
batchSeq: number | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Server-side conflict policy for concurrent writes to the same row.
|
|
31
|
+
*
|
|
32
|
+
* Scope note for `"merge"`: the server resolves per column using the **client
|
|
33
|
+
* op HLCs** recorded in reflectdb's mirror, so two clients editing different
|
|
34
|
+
* fields both land. The per-column clocks the client sees on a broadcast are a
|
|
35
|
+
* different domain — a diff-driven broadcast can't attribute a column to the
|
|
36
|
+
* op that produced it, so every column changed in one broadcast carries that
|
|
37
|
+
* broadcast's HLC. Client-side merge therefore orders *broadcasts* against each
|
|
38
|
+
* other and against local optimistic state; it does not reconstruct per-column
|
|
39
|
+
* causality between clients. Column-level convergence is a server guarantee.
|
|
40
|
+
*/
|
|
41
|
+
type ConflictPolicy = "lww" | "merge" | "server" | CustomConflictPolicy;
|
|
42
|
+
interface CustomConflictPolicy {
|
|
43
|
+
policy: "custom";
|
|
44
|
+
resolve: ConflictResolver;
|
|
45
|
+
}
|
|
46
|
+
interface ConflictResolver {
|
|
47
|
+
(incoming: {
|
|
48
|
+
op: OpType;
|
|
49
|
+
payload: Record<string, unknown> | null;
|
|
50
|
+
hlc: string;
|
|
51
|
+
}, existing: {
|
|
52
|
+
row: Record<string, unknown>;
|
|
53
|
+
colClocks: Record<string, string>;
|
|
54
|
+
}, meta: {
|
|
55
|
+
table: string;
|
|
56
|
+
rowId: string;
|
|
57
|
+
userId: string;
|
|
58
|
+
}): {
|
|
59
|
+
row: Record<string, unknown>;
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
type ErrorReason = "outside_shape" | "readonly_query" | "rate_limited" | "buffer_full" | "server_conflict" | "custom_conflict" | "merge_stale" | "clock_drift" | "replay" | "batch_too_large" | "schema_outdated" | "auth_revoked" | "compacted" | "mutation_rejected" | "server_error" | "unknown_query";
|
|
63
|
+
interface SyncError {
|
|
64
|
+
table: string;
|
|
65
|
+
op: SyncOp;
|
|
66
|
+
reason: ErrorReason;
|
|
67
|
+
serverRow: Record<string, unknown> | null;
|
|
68
|
+
}
|
|
69
|
+
interface HelloMessage {
|
|
70
|
+
type: "hello";
|
|
71
|
+
/** Highest protocol version the client prefers. Retained for back-compat. */
|
|
72
|
+
protocolVersion: number;
|
|
73
|
+
/** All versions the client can speak. Omit for legacy single-version clients. */
|
|
74
|
+
supportedVersions?: readonly number[];
|
|
75
|
+
clientId: string;
|
|
76
|
+
token: string;
|
|
77
|
+
}
|
|
78
|
+
interface BootstrapMessage {
|
|
79
|
+
type: "bootstrap";
|
|
80
|
+
syncParams?: Record<string, Record<string, unknown>>;
|
|
81
|
+
}
|
|
82
|
+
interface ResumeMessage {
|
|
83
|
+
type: "resume";
|
|
84
|
+
since: string;
|
|
85
|
+
}
|
|
86
|
+
interface OpsMessage {
|
|
87
|
+
type: "ops";
|
|
88
|
+
ops: ClientOp[];
|
|
89
|
+
token: string;
|
|
90
|
+
}
|
|
91
|
+
interface ClientOp {
|
|
92
|
+
id: string;
|
|
93
|
+
table: string;
|
|
94
|
+
op: OpType;
|
|
95
|
+
rowId: string;
|
|
96
|
+
payload: Record<string, unknown> | null;
|
|
97
|
+
hlc: string;
|
|
98
|
+
batchId?: string;
|
|
99
|
+
batchSize?: number;
|
|
100
|
+
batchSeq?: number;
|
|
101
|
+
}
|
|
102
|
+
interface SyncDeclareMessage {
|
|
103
|
+
type: "sync_declare";
|
|
104
|
+
table: string;
|
|
105
|
+
params?: Record<string, unknown>;
|
|
106
|
+
window?: number;
|
|
107
|
+
}
|
|
108
|
+
interface LoadMoreMessage {
|
|
109
|
+
type: "load_more";
|
|
110
|
+
table: string;
|
|
111
|
+
count: number;
|
|
112
|
+
}
|
|
113
|
+
interface UnsyncMessage {
|
|
114
|
+
type: "unsync";
|
|
115
|
+
table: string;
|
|
116
|
+
}
|
|
117
|
+
interface AuthMessage {
|
|
118
|
+
type: "auth";
|
|
119
|
+
token: string;
|
|
120
|
+
}
|
|
121
|
+
interface EphemeralMessage {
|
|
122
|
+
type: "ephemeral";
|
|
123
|
+
key: string;
|
|
124
|
+
userId: string;
|
|
125
|
+
data: Record<string, unknown>;
|
|
126
|
+
ttlMs?: number;
|
|
127
|
+
}
|
|
128
|
+
interface HelloAckMessage {
|
|
129
|
+
type: "hello_ack";
|
|
130
|
+
protocolVersion: number;
|
|
131
|
+
serverId: string;
|
|
132
|
+
}
|
|
133
|
+
interface HelloRejectMessage {
|
|
134
|
+
type: "hello_reject";
|
|
135
|
+
reason: string;
|
|
136
|
+
supported: number[];
|
|
137
|
+
}
|
|
138
|
+
interface SnapshotMessage {
|
|
139
|
+
type: "snapshot";
|
|
140
|
+
table: string;
|
|
141
|
+
rows: Record<string, unknown>[];
|
|
142
|
+
colClocks: Record<string, Record<string, string>>;
|
|
143
|
+
append?: boolean;
|
|
144
|
+
totalCount?: number;
|
|
145
|
+
/**
|
|
146
|
+
* Primary key column name for this table. Self-contained per message so the
|
|
147
|
+
* client doesn't depend on `bootstrap_complete.tableMeta` arriving first.
|
|
148
|
+
* When omitted (older servers), the client falls back to tableMeta, then "id".
|
|
149
|
+
*/
|
|
150
|
+
pk?: string;
|
|
151
|
+
}
|
|
152
|
+
interface BootstrapCompleteMessage {
|
|
153
|
+
type: "bootstrap_complete";
|
|
154
|
+
serverHlc: string;
|
|
155
|
+
tableMeta: Record<string, TableMeta>;
|
|
156
|
+
}
|
|
157
|
+
interface TableMeta {
|
|
158
|
+
serverSet: string[];
|
|
159
|
+
readonly: string[];
|
|
160
|
+
broadcast: "consistent" | "eager" | "eager-durable";
|
|
161
|
+
/** Primary key column name. Defaults to "id" when omitted (older servers). */
|
|
162
|
+
pk?: string;
|
|
163
|
+
}
|
|
164
|
+
interface DeltaMessage {
|
|
165
|
+
type: "delta";
|
|
166
|
+
table: string;
|
|
167
|
+
op: OpType;
|
|
168
|
+
rowId: string;
|
|
169
|
+
payload: Record<string, unknown> | null;
|
|
170
|
+
hlc: string;
|
|
171
|
+
colClocks?: Record<string, string>;
|
|
172
|
+
}
|
|
173
|
+
interface AckMessage {
|
|
174
|
+
type: "ack";
|
|
175
|
+
opIds: string[];
|
|
176
|
+
}
|
|
177
|
+
interface RejectMessage {
|
|
178
|
+
type: "reject";
|
|
179
|
+
opId?: string;
|
|
180
|
+
batchId?: string;
|
|
181
|
+
reason: ErrorReason;
|
|
182
|
+
serverRow?: Record<string, unknown>;
|
|
183
|
+
}
|
|
184
|
+
interface ResumeCompleteMessage {
|
|
185
|
+
type: "resume_complete";
|
|
186
|
+
serverHlc: string;
|
|
187
|
+
}
|
|
188
|
+
interface ResumeRejectedMessage {
|
|
189
|
+
type: "resume_rejected";
|
|
190
|
+
reason: string;
|
|
191
|
+
serverHlc: string;
|
|
192
|
+
}
|
|
193
|
+
interface ShapeChangedMessage {
|
|
194
|
+
type: "shape_changed";
|
|
195
|
+
table: string;
|
|
196
|
+
reason: "auth_changed" | "params_changed" | "server_policy";
|
|
197
|
+
}
|
|
198
|
+
interface DisconnectMessage {
|
|
199
|
+
type: "disconnect";
|
|
200
|
+
reason: string;
|
|
201
|
+
}
|
|
202
|
+
interface ReauthMessage {
|
|
203
|
+
type: "reauth";
|
|
204
|
+
}
|
|
205
|
+
interface CountChangedMessage {
|
|
206
|
+
type: "count_changed";
|
|
207
|
+
table: string;
|
|
208
|
+
totalCount: number;
|
|
209
|
+
}
|
|
210
|
+
interface EphemeralEvent {
|
|
211
|
+
type: "ephemeral";
|
|
212
|
+
key: string;
|
|
213
|
+
clientId: string;
|
|
214
|
+
userId: string;
|
|
215
|
+
data: Record<string, unknown>;
|
|
216
|
+
ttlMs?: number;
|
|
217
|
+
}
|
|
218
|
+
type ClientMessage = HelloMessage | BootstrapMessage | ResumeMessage | OpsMessage | SyncDeclareMessage | LoadMoreMessage | UnsyncMessage | AuthMessage | EphemeralMessage;
|
|
219
|
+
type ServerMessage = HelloAckMessage | HelloRejectMessage | SnapshotMessage | BootstrapCompleteMessage | DeltaMessage | AckMessage | RejectMessage | ResumeCompleteMessage | ResumeRejectedMessage | ShapeChangedMessage | DisconnectMessage | ReauthMessage | EphemeralEvent | CountChangedMessage;
|
|
220
|
+
type SyncMessage = ClientMessage | ServerMessage;
|
|
221
|
+
/**
|
|
222
|
+
* Thrown/rejected by a `ServerTransport.send` that could not hand the frame to
|
|
223
|
+
* the peer (socket gone, not OPEN, queue overflow, backpressure limit).
|
|
224
|
+
*
|
|
225
|
+
* The broadcast engine treats a resolved `send` as "this delta reached the
|
|
226
|
+
* client" and only then commits the per-client result cache. A transport that
|
|
227
|
+
* swallows failures therefore makes the server believe a client holds rows it
|
|
228
|
+
* never received — divergence that persists until reconnect. Report failures.
|
|
229
|
+
*/
|
|
230
|
+
declare class TransportSendError extends Error {
|
|
231
|
+
clientId: string;
|
|
232
|
+
cause?: unknown;
|
|
233
|
+
constructor(clientId: string, message: string, cause?: unknown);
|
|
234
|
+
}
|
|
235
|
+
interface ServerTransport {
|
|
236
|
+
/**
|
|
237
|
+
* Deliver a message to one client.
|
|
238
|
+
*
|
|
239
|
+
* MUST reject (ideally with `TransportSendError`) when the frame could not
|
|
240
|
+
* be handed to the peer — unknown/closed socket, full outbound queue, or a
|
|
241
|
+
* throw from the underlying socket. Resolving on a dropped frame makes the
|
|
242
|
+
* broadcast engine commit result-cache state the client never received.
|
|
243
|
+
*/
|
|
244
|
+
send(clientId: string, message: ServerMessage): Promise<void>;
|
|
245
|
+
broadcast(roomId: string, message: ServerMessage, exclude?: string): Promise<void>;
|
|
246
|
+
onMessage(handler: (clientId: string, message: ClientMessage) => void): void;
|
|
247
|
+
onConnect(handler: (clientId: string, req: Request) => void): void;
|
|
248
|
+
onDisconnect(handler: (clientId: string) => void): void;
|
|
249
|
+
close(): Promise<void>;
|
|
250
|
+
/**
|
|
251
|
+
* Force-disconnect a single client. Optional — if absent, the handler relies
|
|
252
|
+
* on the client honoring a `disconnect` server-message. Required for any
|
|
253
|
+
* transport that carries authentication state, since an adversarial client
|
|
254
|
+
* can otherwise ignore the message and continue using a revoked session.
|
|
255
|
+
*/
|
|
256
|
+
disconnect?(clientId: string): Promise<void> | void;
|
|
257
|
+
}
|
|
258
|
+
interface ClientTransport {
|
|
259
|
+
send(message: ClientMessage): Promise<void>;
|
|
260
|
+
subscribe(handler: (message: ServerMessage) => void): void;
|
|
261
|
+
close(): Promise<void>;
|
|
262
|
+
}
|
|
263
|
+
declare const PROTOCOL_VERSION: number;
|
|
264
|
+
/** Versions this peer can speak, highest first. Server picks the highest shared version. */
|
|
265
|
+
declare const SUPPORTED_PROTOCOL_VERSIONS: readonly number[];
|
|
266
|
+
declare const MAX_CLOCK_DRIFT_MS: number;
|
|
267
|
+
declare const MAX_BATCH_SIZE: number;
|
|
268
|
+
declare const TOMBSTONE_RETENTION_MS: number;
|
|
269
|
+
declare const SERVER_TOMBSTONE_RETENTION_MS: number;
|
|
270
|
+
type Dialect = "postgresql" | "mysql" | "sqlite";
|
|
271
|
+
interface ShapeConfig {
|
|
272
|
+
filter?: unknown;
|
|
273
|
+
serverSet?: Record<string, unknown>;
|
|
274
|
+
readonly?: string[];
|
|
275
|
+
conflict?: ConflictPolicy;
|
|
276
|
+
}
|
|
277
|
+
interface RateLimitConfig {
|
|
278
|
+
opsPerSecond?: number;
|
|
279
|
+
opsPerMinute?: number;
|
|
280
|
+
batchesPerMinute?: number;
|
|
281
|
+
/**
|
|
282
|
+
* Per-table overrides. Applied in addition to the global limit: a write
|
|
283
|
+
* must pass both. Tables missing from this map inherit only the global
|
|
284
|
+
* bucket. Use to tighten write pressure on hot tables (e.g. ephemeral
|
|
285
|
+
* chat) without punishing cold ones.
|
|
286
|
+
*/
|
|
287
|
+
perTable?: Record<string, {
|
|
288
|
+
opsPerSecond?: number;
|
|
289
|
+
opsPerMinute?: number;
|
|
290
|
+
}>;
|
|
291
|
+
/**
|
|
292
|
+
* Ceiling on ephemeral (presence/cursor) messages per client per second.
|
|
293
|
+
* Metered separately from writes so presence traffic and the write budget
|
|
294
|
+
* don't starve each other. Defaults to 60; 0 disables metering entirely
|
|
295
|
+
* (each ephemeral message fans out to every room subscriber, so an
|
|
296
|
+
* unmetered channel is an amplification vector).
|
|
297
|
+
*/
|
|
298
|
+
ephemeralPerSecond?: number;
|
|
299
|
+
}
|
|
300
|
+
interface CompactionConfig {
|
|
301
|
+
clientInactivityTimeout: string;
|
|
302
|
+
interval: string;
|
|
303
|
+
minOpAge: string;
|
|
304
|
+
}
|
|
305
|
+
interface AuthContext {
|
|
306
|
+
userId: string;
|
|
307
|
+
[key: string]: unknown;
|
|
308
|
+
}
|
|
309
|
+
declare class MutationError extends Error {
|
|
310
|
+
reason: ErrorReason;
|
|
311
|
+
constructor(reason: ErrorReason, message?: string);
|
|
312
|
+
}
|
|
313
|
+
declare function isErrorReason(value: unknown): value is ErrorReason;
|
|
314
|
+
/** Safely extract an ErrorReason from an unknown thrown value. Falls back to
|
|
315
|
+
* "server_error" for non-MutationError throws or invalid reason strings. */
|
|
316
|
+
declare function reasonFromError(err: unknown): ErrorReason;
|
|
317
|
+
interface DrizzleTableLike {
|
|
318
|
+
$inferSelect: Record<string, unknown>;
|
|
319
|
+
$inferInsert: Record<string, unknown>;
|
|
320
|
+
}
|
|
321
|
+
/**
|
|
322
|
+
* Value supplied per serverSet field in the schema's object form.
|
|
323
|
+
* Either a static value or a function that receives the request context.
|
|
324
|
+
*/
|
|
325
|
+
type ServerSetSchemaValue = unknown | ((ctx: {
|
|
326
|
+
auth: unknown;
|
|
327
|
+
params: unknown;
|
|
328
|
+
}) => unknown);
|
|
329
|
+
/**
|
|
330
|
+
* Schema-side `serverSet` declaration. Two shapes:
|
|
331
|
+
* - `string[]` — keys only; values are supplied at `implement(...)` time.
|
|
332
|
+
* - `Record<string, ServerSetSchemaValue>` — keys + values collocated in schema.
|
|
333
|
+
*/
|
|
334
|
+
type SchemaServerSet = readonly string[] | Readonly<Record<string, ServerSetSchemaValue>>;
|
|
335
|
+
interface SyncQueryDef {
|
|
336
|
+
/** Drizzle table — row type derived from $inferSelect */
|
|
337
|
+
table?: DrizzleTableLike;
|
|
338
|
+
/** Phantom row type for non-drizzle usage: `{} as MyRow` */
|
|
339
|
+
row?: Record<string, unknown>;
|
|
340
|
+
/** Database tables for change detection. Falls back to query key name. */
|
|
341
|
+
tables?: string[];
|
|
342
|
+
/** Phantom value for params type: `{} as { orgId: string }` */
|
|
343
|
+
params?: Record<string, unknown>;
|
|
344
|
+
/** Primary key column name. Defaults to "id". Single-column only. */
|
|
345
|
+
pk?: string;
|
|
346
|
+
conflict?: ConflictPolicy;
|
|
347
|
+
readonly?: readonly string[];
|
|
348
|
+
serverSet?: SchemaServerSet;
|
|
349
|
+
countHints?: boolean;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Read-only computed query. Compiles down to `server.query(...)` with a
|
|
353
|
+
* throwing mutate so the type system blocks `useSync(...).insert/update/remove`
|
|
354
|
+
* and the runtime rejects any direct write attempt.
|
|
355
|
+
*/
|
|
356
|
+
interface SyncViewDef {
|
|
357
|
+
__view: true;
|
|
358
|
+
row?: Record<string, unknown>;
|
|
359
|
+
params?: Record<string, unknown>;
|
|
360
|
+
tables?: string[];
|
|
361
|
+
/** Tables to watch for change-detection. Defaults to `tables` or query key. */
|
|
362
|
+
deps?: string[];
|
|
363
|
+
}
|
|
364
|
+
declare function view<
|
|
365
|
+
TRow extends object,
|
|
366
|
+
TParams extends Record<string, unknown> | undefined = undefined
|
|
367
|
+
>(opts: {
|
|
368
|
+
row?: TRow;
|
|
369
|
+
params?: TParams;
|
|
370
|
+
deps?: string[];
|
|
371
|
+
tables?: string[];
|
|
372
|
+
}): SyncViewDef & {
|
|
373
|
+
row?: TRow;
|
|
374
|
+
params?: TParams;
|
|
375
|
+
};
|
|
376
|
+
/**
|
|
377
|
+
* Typed ephemeral channel. Sugar over the runtime `useEphemeral` hook —
|
|
378
|
+
* derives a stable key from the schema name + serialized params and gives
|
|
379
|
+
* `peers`/`set` a typed `state`.
|
|
380
|
+
*/
|
|
381
|
+
interface SyncPresenceDef {
|
|
382
|
+
__presence: true;
|
|
383
|
+
state?: Record<string, unknown>;
|
|
384
|
+
params?: Record<string, unknown>;
|
|
385
|
+
ttlMs?: number;
|
|
386
|
+
}
|
|
387
|
+
declare function presence<
|
|
388
|
+
TState extends object,
|
|
389
|
+
TParams extends Record<string, unknown> | undefined = undefined
|
|
390
|
+
>(opts: {
|
|
391
|
+
state?: TState;
|
|
392
|
+
params?: TParams;
|
|
393
|
+
ttlMs?: number;
|
|
394
|
+
}): SyncPresenceDef & {
|
|
395
|
+
state?: TState;
|
|
396
|
+
params?: TParams;
|
|
397
|
+
};
|
|
398
|
+
type SyncQueryEntry = SyncQueryDef | SyncViewDef | SyncPresenceDef;
|
|
399
|
+
type SyncQueryMap = Record<string, SyncQueryEntry>;
|
|
400
|
+
/** Extract column names from a query definition's table or row type */
|
|
401
|
+
type ColumnOf<TDef> = TDef extends {
|
|
402
|
+
table: DrizzleTableLike;
|
|
403
|
+
} ? keyof TDef["table"]["$inferSelect"] & string : TDef extends {
|
|
404
|
+
row: infer R extends Record<string, unknown>;
|
|
405
|
+
} ? keyof R & string : string;
|
|
406
|
+
/** Constrain serverSet and readonly to valid column names. Accepts either array or object form for serverSet. View/presence entries don't have these fields, so the constraint is empty. */
|
|
407
|
+
type FieldsConstraint<TDef> = TDef extends {
|
|
408
|
+
__view: true;
|
|
409
|
+
} | {
|
|
410
|
+
__presence: true;
|
|
411
|
+
} ? Record<string, never> : {
|
|
412
|
+
serverSet?: readonly ColumnOf<TDef>[] | Readonly<Partial<Record<ColumnOf<TDef>, ServerSetSchemaValue>>>;
|
|
413
|
+
readonly?: readonly ColumnOf<TDef>[];
|
|
414
|
+
};
|
|
415
|
+
declare function defineSyncQueries<const T extends SyncQueryMap>(queries: T & { [K in keyof T] : FieldsConstraint<T[K]> }): T;
|
|
416
|
+
/** Phantom type helper — passes a type without needing a real value or `as` cast */
|
|
417
|
+
declare function t<T>(): T;
|
|
418
|
+
/** Row type: from `table.$inferSelect` if drizzle, otherwise from `row` phantom */
|
|
419
|
+
type InferRow<
|
|
420
|
+
TQueries extends SyncQueryMap,
|
|
421
|
+
K extends keyof TQueries
|
|
422
|
+
> = TQueries[K] extends {
|
|
423
|
+
table: DrizzleTableLike;
|
|
424
|
+
} ? TQueries[K]["table"]["$inferSelect"] : TQueries[K] extends {
|
|
425
|
+
row: infer R extends Record<string, unknown>;
|
|
426
|
+
} ? R : Record<string, unknown>;
|
|
427
|
+
/** Presence state type — typed shape passed to/received from `usePresence`. */
|
|
428
|
+
type InferState<
|
|
429
|
+
TQueries extends SyncQueryMap,
|
|
430
|
+
K extends keyof TQueries
|
|
431
|
+
> = TQueries[K] extends {
|
|
432
|
+
state: infer S extends Record<string, unknown>;
|
|
433
|
+
} ? S : Record<string, unknown>;
|
|
434
|
+
/** Params type. `undefined` when no params declared. */
|
|
435
|
+
type InferParams<
|
|
436
|
+
TQueries extends SyncQueryMap,
|
|
437
|
+
K extends keyof TQueries
|
|
438
|
+
> = TQueries[K] extends {
|
|
439
|
+
params: infer P extends Record<string, unknown>;
|
|
440
|
+
} ? P : undefined;
|
|
441
|
+
/** `true` when the query declares params */
|
|
442
|
+
type RequiresParams<
|
|
443
|
+
TQueries extends SyncQueryMap,
|
|
444
|
+
K extends keyof TQueries
|
|
445
|
+
> = TQueries[K] extends {
|
|
446
|
+
params: Record<string, unknown>;
|
|
447
|
+
} ? true : false;
|
|
448
|
+
/** Primary key column name. Defaults to "id". */
|
|
449
|
+
type PkOf<TDef> = TDef extends {
|
|
450
|
+
pk: infer P extends string;
|
|
451
|
+
} ? P : "id";
|
|
452
|
+
/** Extract serverSet field names from either array form or object form. */
|
|
453
|
+
type InferServerSetKeys<TDef> = TDef extends {
|
|
454
|
+
serverSet: readonly (infer S extends string)[];
|
|
455
|
+
} ? S : TDef extends {
|
|
456
|
+
serverSet: infer O extends Readonly<Record<string, unknown>>;
|
|
457
|
+
} ? keyof O & string : never;
|
|
458
|
+
/**
|
|
459
|
+
* Row minus readonly fields, serverSet fields, and the primary key.
|
|
460
|
+
* View defs collapse to `never` to block client-side writes at the type level.
|
|
461
|
+
* Presence defs aren't writable rows; they collapse to `never` too.
|
|
462
|
+
*/
|
|
463
|
+
type InferWritableRow<
|
|
464
|
+
TQueries extends SyncQueryMap,
|
|
465
|
+
K extends keyof TQueries
|
|
466
|
+
> = TQueries[K] extends {
|
|
467
|
+
__view: true;
|
|
468
|
+
} | {
|
|
469
|
+
__presence: true;
|
|
470
|
+
} ? never : Omit<InferRow<TQueries, K>, (TQueries[K] extends {
|
|
471
|
+
readonly: readonly (infer R extends string)[];
|
|
472
|
+
} ? R : never) | InferServerSetKeys<TQueries[K]> | PkOf<TQueries[K]>>;
|
|
473
|
+
export { view, unpackHlc, t, sendHlc, receiveHlc, reasonFromError, presence, packHlc, isErrorReason, defineSyncQueries, createHlc, compareHlc, UnsyncMessage, TransportSendError, TableMeta, TOMBSTONE_RETENTION_MS, SyncViewDef, SyncQueryMap, SyncQueryEntry, SyncQueryDef, SyncPresenceDef, SyncOp, SyncMessage, SyncError, SyncDeclareMessage, SnapshotMessage, ShapeConfig, ShapeChangedMessage, ServerTransport, ServerMessage, SUPPORTED_PROTOCOL_VERSIONS, SERVER_TOMBSTONE_RETENTION_MS, ResumeRejectedMessage, ResumeMessage, ResumeCompleteMessage, RequiresParams, RejectMessage, ReauthMessage, RateLimitConfig, PROTOCOL_VERSION, OpsMessage, OpType, OpStatus, MutationError, MAX_CLOCK_DRIFT_MS, MAX_BATCH_SIZE, LoadMoreMessage, InferWritableRow, InferState, InferRow, InferParams, HelloRejectMessage, HelloMessage, HelloAckMessage, HLC, ErrorReason, EphemeralMessage, EphemeralEvent, DrizzleTableLike, DisconnectMessage, Dialect, DeltaMessage, CustomConflictPolicy, CountChangedMessage, ConflictResolver, ConflictPolicy, CompactionConfig, ClientTransport, ClientOp, ClientMessage, BootstrapMessage, BootstrapCompleteMessage, AuthMessage, AuthContext, AckMessage };
|