@supalive/core 0.1.6 → 1.0.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/dist/index-DouKwYL6.d.ts +1754 -0
- package/dist/index-DouKwYL6.d.ts.map +1 -0
- package/dist/mysql-Bxurg_PH.d.ts +104 -0
- package/dist/mysql-Bxurg_PH.d.ts.map +1 -0
- package/dist/postgres-CfT_aDx3.d.ts +108 -0
- package/dist/postgres-CfT_aDx3.d.ts.map +1 -0
- package/dist/procedure-DX87tyef.js.map +1 -1
- package/dist/router-DlTYWpop.js.map +1 -1
- package/dist/src/client/index.d.ts +1 -1
- package/dist/src/exports/codegen.d.ts +38 -0
- package/dist/src/exports/codegen.d.ts.map +1 -0
- package/dist/src/exports/codegen.js +134 -0
- package/dist/src/exports/codegen.js.map +1 -0
- package/dist/src/exports/mysql.d.ts +1 -1
- package/dist/src/exports/postgres.d.ts +1 -1
- package/dist/src/exports/procedure.d.ts +1 -1
- package/dist/src/exports/schema-sql.d.ts +1 -1
- package/dist/src/exports/server.d.ts +4 -4
- package/dist/src/exports/server.d.ts.map +1 -1
- package/dist/src/exports/server.js +2 -7
- package/dist/src/exports/server.js.map +1 -1
- package/dist/src/exports/subscription-manager-worker-entry.js +1 -2
- package/dist/src/exports/subscription-manager-worker-entry.js.map +1 -1
- package/dist/src/exports/types.d.ts +2 -2
- package/dist/subscription-worker-CqoWp6zB.js +511 -0
- package/dist/subscription-worker-CqoWp6zB.js.map +1 -0
- package/dist/subscription-worker-PtmJWEj1.js +511 -0
- package/dist/subscription-worker-PtmJWEj1.js.map +1 -0
- package/dist/types_server-BW1ys_SK.d.ts +216 -0
- package/dist/types_server-BW1ys_SK.d.ts.map +1 -0
- package/dist/types_server-Dk6o_B7N.js.map +1 -1
- package/dist/types_server-Dpsi0wpG.d.ts +216 -0
- package/dist/types_server-Dpsi0wpG.d.ts.map +1 -0
- package/dist/types_server-DzrIccyO.d.ts +216 -0
- package/dist/types_server-DzrIccyO.d.ts.map +1 -0
- package/package.json +3 -2
|
@@ -0,0 +1,1754 @@
|
|
|
1
|
+
import z, { ZodRawShape, ZodType, z as z$1 } from "zod";
|
|
2
|
+
import { RetryPolicy } from "cockatiel";
|
|
3
|
+
import Redis$1 from "ioredis";
|
|
4
|
+
import { Redis as Redis$2 } from "@upstash/redis";
|
|
5
|
+
|
|
6
|
+
//#region src/db/types_db.d.ts
|
|
7
|
+
/** Monotonically increasing integer from global_commit_ts sequence in Postgres */
|
|
8
|
+
type CommitTs = bigint;
|
|
9
|
+
declare const BigIntSchema: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
|
|
10
|
+
declare const CompareOperatorSchema: z.ZodEnum<{
|
|
11
|
+
"=": "=";
|
|
12
|
+
"!=": "!=";
|
|
13
|
+
">": ">";
|
|
14
|
+
">=": ">=";
|
|
15
|
+
"<": "<";
|
|
16
|
+
"<=": "<=";
|
|
17
|
+
like: "like";
|
|
18
|
+
ilike: "ilike";
|
|
19
|
+
contains: "contains";
|
|
20
|
+
icontains: "icontains";
|
|
21
|
+
between: "between";
|
|
22
|
+
jsonContains: "jsonContains";
|
|
23
|
+
jsonContainedBy: "jsonContainedBy";
|
|
24
|
+
jsonHasKey: "jsonHasKey";
|
|
25
|
+
jsonArrayContains: "jsonArrayContains";
|
|
26
|
+
isNull: "isNull";
|
|
27
|
+
isNotNull: "isNotNull";
|
|
28
|
+
}>;
|
|
29
|
+
type CompareOperator = z.infer<typeof CompareOperatorSchema>;
|
|
30
|
+
type Predicate = LeafPredicate | {
|
|
31
|
+
kind: "and";
|
|
32
|
+
children: Predicate[];
|
|
33
|
+
} | {
|
|
34
|
+
kind: "or";
|
|
35
|
+
children: Predicate[];
|
|
36
|
+
};
|
|
37
|
+
declare const PredicateSchema: z.ZodType<Predicate>;
|
|
38
|
+
declare const LeafPredicateSchema: z.ZodObject<{
|
|
39
|
+
kind: z.ZodLiteral<"leaf">;
|
|
40
|
+
column: z.ZodString;
|
|
41
|
+
operator: z.ZodEnum<{
|
|
42
|
+
"=": "=";
|
|
43
|
+
"!=": "!=";
|
|
44
|
+
">": ">";
|
|
45
|
+
">=": ">=";
|
|
46
|
+
"<": "<";
|
|
47
|
+
"<=": "<=";
|
|
48
|
+
like: "like";
|
|
49
|
+
ilike: "ilike";
|
|
50
|
+
contains: "contains";
|
|
51
|
+
icontains: "icontains";
|
|
52
|
+
between: "between";
|
|
53
|
+
jsonContains: "jsonContains";
|
|
54
|
+
jsonContainedBy: "jsonContainedBy";
|
|
55
|
+
jsonHasKey: "jsonHasKey";
|
|
56
|
+
jsonArrayContains: "jsonArrayContains";
|
|
57
|
+
isNull: "isNull";
|
|
58
|
+
isNotNull: "isNotNull";
|
|
59
|
+
}>;
|
|
60
|
+
value: z.ZodUnknown;
|
|
61
|
+
value2: z.ZodOptional<z.ZodUnknown>;
|
|
62
|
+
raw: z.ZodOptional<z.ZodBoolean>;
|
|
63
|
+
path: z.ZodOptional<z.ZodString>;
|
|
64
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
65
|
+
one: "one";
|
|
66
|
+
all: "all";
|
|
67
|
+
}>>;
|
|
68
|
+
}, z.core.$strip>;
|
|
69
|
+
type LeafPredicate = z.infer<typeof LeafPredicateSchema>;
|
|
70
|
+
declare const AndPredicateSchema: z.ZodObject<{
|
|
71
|
+
kind: z.ZodLiteral<"and">;
|
|
72
|
+
children: z.ZodArray<z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>>;
|
|
73
|
+
}, z.core.$strip>;
|
|
74
|
+
type AndPredicate = z.infer<typeof AndPredicateSchema>;
|
|
75
|
+
declare const OrPredicateSchema: z.ZodObject<{
|
|
76
|
+
kind: z.ZodLiteral<"or">;
|
|
77
|
+
children: z.ZodArray<z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>>;
|
|
78
|
+
}, z.core.$strip>;
|
|
79
|
+
type OrPredicate = z.infer<typeof OrPredicateSchema>;
|
|
80
|
+
/** Query specification - what was queried (used for cache key generation) */
|
|
81
|
+
type QuerySpec = ReadEntry;
|
|
82
|
+
declare function normalizeIdToBytes(id: string | number, fromHex?: boolean): Uint8Array;
|
|
83
|
+
declare function normalizeToBytes(value: Uint8Array | unknown): Uint8Array;
|
|
84
|
+
declare function bytesFromJson(value: Uint8Array | unknown): Uint8Array;
|
|
85
|
+
declare const PointReadSchema: z.ZodObject<{
|
|
86
|
+
kind: z.ZodLiteral<"point">;
|
|
87
|
+
table: z.ZodString;
|
|
88
|
+
id: z.ZodString;
|
|
89
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
90
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
91
|
+
}, z.core.$strip>;
|
|
92
|
+
type PointRead = z.infer<typeof PointReadSchema>;
|
|
93
|
+
declare const RawPointReadSchema: z.ZodObject<{
|
|
94
|
+
kind: z.ZodLiteral<"point">;
|
|
95
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
96
|
+
id: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
97
|
+
table: z.ZodString;
|
|
98
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
99
|
+
}, z.core.$strip>;
|
|
100
|
+
type RawPointRead = z.infer<typeof RawPointReadSchema>;
|
|
101
|
+
/**
|
|
102
|
+
* Query specification for a range read (get with filters).
|
|
103
|
+
* This is the query definition, not the result.
|
|
104
|
+
*/
|
|
105
|
+
declare const RangeReadSchema: z.ZodObject<{
|
|
106
|
+
kind: z.ZodLiteral<"range">;
|
|
107
|
+
table: z.ZodString;
|
|
108
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
109
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
110
|
+
columns: z.ZodArray<z.ZodString>;
|
|
111
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
112
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
113
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
114
|
+
}, z.core.$strip>;
|
|
115
|
+
type RangeRead = z.infer<typeof RangeReadSchema>;
|
|
116
|
+
declare const RawRangeReadSchema: z.ZodObject<{
|
|
117
|
+
kind: z.ZodLiteral<"range">;
|
|
118
|
+
table: z.ZodString;
|
|
119
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
120
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
121
|
+
columns: z.ZodArray<z.ZodString>;
|
|
122
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
123
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
124
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
125
|
+
}, z.core.$strip>;
|
|
126
|
+
type RawRangeRead = z.infer<typeof RawRangeReadSchema>;
|
|
127
|
+
declare const ReadEntrySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
128
|
+
kind: z.ZodLiteral<"point">;
|
|
129
|
+
table: z.ZodString;
|
|
130
|
+
id: z.ZodString;
|
|
131
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
132
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
133
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
134
|
+
kind: z.ZodLiteral<"range">;
|
|
135
|
+
table: z.ZodString;
|
|
136
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
137
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
138
|
+
columns: z.ZodArray<z.ZodString>;
|
|
139
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
140
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
141
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
142
|
+
}, z.core.$strip>]>;
|
|
143
|
+
type ReadEntry = z.infer<typeof ReadEntrySchema>;
|
|
144
|
+
declare const RawReadEntrySchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
145
|
+
kind: z.ZodLiteral<"point">;
|
|
146
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
147
|
+
id: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
148
|
+
table: z.ZodString;
|
|
149
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
150
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
151
|
+
kind: z.ZodLiteral<"range">;
|
|
152
|
+
table: z.ZodString;
|
|
153
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
154
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
155
|
+
columns: z.ZodArray<z.ZodString>;
|
|
156
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
157
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
158
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
159
|
+
}, z.core.$strip>]>;
|
|
160
|
+
type RawReadEntry = z.infer<typeof RawReadEntrySchema>;
|
|
161
|
+
declare const WriteOpSchema: z.ZodEnum<{
|
|
162
|
+
insert: "insert";
|
|
163
|
+
update: "update";
|
|
164
|
+
delete: "delete";
|
|
165
|
+
}>;
|
|
166
|
+
type WriteOp = z.infer<typeof WriteOpSchema>;
|
|
167
|
+
declare const WriteEntrySchema: z.ZodObject<{
|
|
168
|
+
table: z.ZodString;
|
|
169
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
170
|
+
id: z.ZodString;
|
|
171
|
+
op: z.ZodEnum<{
|
|
172
|
+
insert: "insert";
|
|
173
|
+
update: "update";
|
|
174
|
+
delete: "delete";
|
|
175
|
+
}>;
|
|
176
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
177
|
+
prevData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
178
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
179
|
+
}, z.core.$strip>;
|
|
180
|
+
type WriteEntry = z.infer<typeof WriteEntrySchema>;
|
|
181
|
+
interface CommitLogEntry {
|
|
182
|
+
id: Uint8Array;
|
|
183
|
+
ts: bigint;
|
|
184
|
+
tableId: Uint8Array;
|
|
185
|
+
data: Uint8Array;
|
|
186
|
+
_parsedData?: Record<string, unknown> | null;
|
|
187
|
+
}
|
|
188
|
+
interface MutationResult<T> {
|
|
189
|
+
result: T;
|
|
190
|
+
writeSet: WriteEntry[];
|
|
191
|
+
commitTs: CommitTs;
|
|
192
|
+
}
|
|
193
|
+
interface LiveResult<T> {
|
|
194
|
+
ts: bigint;
|
|
195
|
+
data: T;
|
|
196
|
+
readSet: ReadEntry[];
|
|
197
|
+
}
|
|
198
|
+
declare const QueryCacheMetadataSchema: z.ZodObject<{
|
|
199
|
+
lastSnapshotTs: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
|
|
200
|
+
readSet: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
201
|
+
kind: z.ZodLiteral<"point">;
|
|
202
|
+
table: z.ZodString;
|
|
203
|
+
id: z.ZodString;
|
|
204
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
205
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
206
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
207
|
+
kind: z.ZodLiteral<"range">;
|
|
208
|
+
table: z.ZodString;
|
|
209
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
210
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
211
|
+
columns: z.ZodArray<z.ZodString>;
|
|
212
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
213
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
214
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
215
|
+
}, z.core.$strip>]>>;
|
|
216
|
+
}, z.core.$strip>;
|
|
217
|
+
type QueryCacheMetadata = z.infer<typeof QueryCacheMetadataSchema>;
|
|
218
|
+
declare const QueryCacheEntrySchema: z.ZodObject<{
|
|
219
|
+
data: z.ZodUnknown;
|
|
220
|
+
}, z.core.$strip>;
|
|
221
|
+
type QueryCacheEntry = z.infer<typeof QueryCacheEntrySchema>;
|
|
222
|
+
declare const CachedPgMetadataSchema: z.ZodRecord<z.ZodString, z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
223
|
+
type CachedPgMetadata = z.infer<typeof CachedPgMetadataSchema>;
|
|
224
|
+
interface RetryConfig {
|
|
225
|
+
maxAttempts: number;
|
|
226
|
+
backoff: "none" | "linear" | "exponential";
|
|
227
|
+
delayMs?: number;
|
|
228
|
+
onConflict?: (attempt: number, error: OccConflictError) => void;
|
|
229
|
+
}
|
|
230
|
+
declare const NO_RETRY: RetryConfig;
|
|
231
|
+
declare const DEFAULT_RETRY: RetryConfig;
|
|
232
|
+
declare class OccConflictError extends Error {
|
|
233
|
+
readonly reason: string;
|
|
234
|
+
readonly conflictDetail?: unknown | undefined;
|
|
235
|
+
constructor(reason: string, conflictDetail?: unknown | undefined);
|
|
236
|
+
static isOccConflictError(err: unknown): boolean;
|
|
237
|
+
}
|
|
238
|
+
declare class OccAbortError extends Error {
|
|
239
|
+
constructor(message: string);
|
|
240
|
+
}
|
|
241
|
+
//#endregion
|
|
242
|
+
//#region src/server/subscription-manager-types.d.ts
|
|
243
|
+
declare const RegisterSubscriptionParamsSchema: z.ZodObject<{
|
|
244
|
+
subId: z.ZodString;
|
|
245
|
+
cacheKey: z.ZodString;
|
|
246
|
+
queryName: z.ZodString;
|
|
247
|
+
args: z.ZodUnknown;
|
|
248
|
+
queryIdentity: z.ZodString;
|
|
249
|
+
instanceName: z.ZodString;
|
|
250
|
+
lastSnapshotTs: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
|
|
251
|
+
}, z.core.$strip>;
|
|
252
|
+
type RegisterSubscriptionParams = z.infer<typeof RegisterSubscriptionParamsSchema>;
|
|
253
|
+
declare const RegisterSubscriptionResultSchema: z.ZodObject<{
|
|
254
|
+
cacheKey: z.ZodString;
|
|
255
|
+
recompute: z.ZodBoolean;
|
|
256
|
+
readSet: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
257
|
+
kind: z.ZodLiteral<"point">;
|
|
258
|
+
table: z.ZodString;
|
|
259
|
+
id: z.ZodString;
|
|
260
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
261
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
262
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
263
|
+
kind: z.ZodLiteral<"range">;
|
|
264
|
+
table: z.ZodString;
|
|
265
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
266
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
267
|
+
columns: z.ZodArray<z.ZodString>;
|
|
268
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
269
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
270
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
271
|
+
}, z.core.$strip>]>>;
|
|
272
|
+
}, z.core.$strip>;
|
|
273
|
+
type RegisterSubscriptionResult = z.infer<typeof RegisterSubscriptionResultSchema>;
|
|
274
|
+
declare const UpdateSubscriptionReadSetParamsSchema: z.ZodObject<{
|
|
275
|
+
cacheKey: z.ZodString;
|
|
276
|
+
subId: z.ZodString;
|
|
277
|
+
instanceName: z.ZodString;
|
|
278
|
+
lastSnapshotTs: z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>;
|
|
279
|
+
readSet: z.ZodArray<z.ZodUnion<readonly [z.ZodObject<{
|
|
280
|
+
kind: z.ZodLiteral<"point">;
|
|
281
|
+
table: z.ZodString;
|
|
282
|
+
id: z.ZodString;
|
|
283
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
284
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
285
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
286
|
+
kind: z.ZodLiteral<"range">;
|
|
287
|
+
table: z.ZodString;
|
|
288
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
289
|
+
predicate: z.ZodType<Predicate, unknown, z.core.$ZodTypeInternals<Predicate, unknown>>;
|
|
290
|
+
columns: z.ZodArray<z.ZodString>;
|
|
291
|
+
orderBy: z.ZodOptional<z.ZodNullable<z.ZodString>>;
|
|
292
|
+
limit: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
293
|
+
offset: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
|
|
294
|
+
}, z.core.$strip>]>>;
|
|
295
|
+
}, z.core.$strip>;
|
|
296
|
+
type UpdateSubscriptionReadSetParams = z.infer<typeof UpdateSubscriptionReadSetParamsSchema>;
|
|
297
|
+
/**
|
|
298
|
+
* `tracked: false` means the sub-manager has no record of this subId (e.g.
|
|
299
|
+
* a restart wiped state and the caller hasn't re-registered yet). The app
|
|
300
|
+
* server should treat this as a signal to register the sub before retrying.
|
|
301
|
+
*/
|
|
302
|
+
declare const UpdateSubscriptionReadSetResultSchema: z.ZodObject<{
|
|
303
|
+
tracked: z.ZodBoolean;
|
|
304
|
+
}, z.core.$strip>;
|
|
305
|
+
type UpdateSubscriptionReadSetResult = z.infer<typeof UpdateSubscriptionReadSetResultSchema>;
|
|
306
|
+
declare const UnregisterSubscriptionParamsSchema: z.ZodObject<{
|
|
307
|
+
subId: z.ZodString;
|
|
308
|
+
instanceName: z.ZodString;
|
|
309
|
+
}, z.core.$strip>;
|
|
310
|
+
type UnregisterSubscriptionParams = z.infer<typeof UnregisterSubscriptionParamsSchema>;
|
|
311
|
+
declare const UnregisterSubscriptionsParamsSchema: z.ZodArray<z.ZodObject<{
|
|
312
|
+
subId: z.ZodString;
|
|
313
|
+
instanceName: z.ZodString;
|
|
314
|
+
}, z.core.$strip>>;
|
|
315
|
+
type UnregisterSubscriptionsParams = z.infer<typeof UnregisterSubscriptionsParamsSchema>;
|
|
316
|
+
declare const UnregisterSubscriptionResultSchema: z.ZodObject<{
|
|
317
|
+
ok: z.ZodBoolean;
|
|
318
|
+
}, z.core.$strip>;
|
|
319
|
+
type UnregisterSubscriptionResult = z.infer<typeof UnregisterSubscriptionResultSchema>;
|
|
320
|
+
declare const UnregisterSubscriptionsResultSchema: z.ZodArray<z.ZodObject<{
|
|
321
|
+
ok: z.ZodBoolean;
|
|
322
|
+
}, z.core.$strip>>;
|
|
323
|
+
type UnregisterSubscriptionsResult = z.infer<typeof UnregisterSubscriptionsResultSchema>;
|
|
324
|
+
declare const InvalidateWritesetParamsSchema: z.ZodObject<{
|
|
325
|
+
writeSet: z.ZodArray<z.ZodObject<{
|
|
326
|
+
table: z.ZodString;
|
|
327
|
+
tableId: z.ZodPipe<z.ZodAny, z.ZodTransform<Uint8Array<ArrayBufferLike>, any>>;
|
|
328
|
+
id: z.ZodString;
|
|
329
|
+
op: z.ZodEnum<{
|
|
330
|
+
insert: "insert";
|
|
331
|
+
update: "update";
|
|
332
|
+
delete: "delete";
|
|
333
|
+
}>;
|
|
334
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
335
|
+
prevData: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
336
|
+
expectedCommitTs: z.ZodOptional<z.ZodNullable<z.ZodPipe<z.ZodString, z.ZodTransform<bigint, string>>>>;
|
|
337
|
+
}, z.core.$strip>>;
|
|
338
|
+
}, z.core.$strip>;
|
|
339
|
+
type InvalidateWritesetParams = z.infer<typeof InvalidateWritesetParamsSchema>;
|
|
340
|
+
declare const AffectedSubscriptionSchema: z.ZodObject<{
|
|
341
|
+
subId: z.ZodString;
|
|
342
|
+
queryName: z.ZodString;
|
|
343
|
+
args: z.ZodUnknown;
|
|
344
|
+
cacheKey: z.ZodString;
|
|
345
|
+
notifyInstances: z.ZodArray<z.ZodString>;
|
|
346
|
+
}, z.core.$strip>;
|
|
347
|
+
type AffectedSubscription = z.infer<typeof AffectedSubscriptionSchema>;
|
|
348
|
+
declare const InvalidateWritesetResultSchema: z.ZodObject<{
|
|
349
|
+
affected: z.ZodArray<z.ZodObject<{
|
|
350
|
+
subId: z.ZodString;
|
|
351
|
+
queryName: z.ZodString;
|
|
352
|
+
args: z.ZodUnknown;
|
|
353
|
+
cacheKey: z.ZodString;
|
|
354
|
+
notifyInstances: z.ZodArray<z.ZodString>;
|
|
355
|
+
}, z.core.$strip>>;
|
|
356
|
+
}, z.core.$strip>;
|
|
357
|
+
type InvalidateWritesetResult = z.infer<typeof InvalidateWritesetResultSchema>;
|
|
358
|
+
declare const RegistrationRecordSchema: z.ZodObject<{
|
|
359
|
+
queryName: z.ZodString;
|
|
360
|
+
args: z.ZodUnknown;
|
|
361
|
+
queryIdentity: z.ZodString;
|
|
362
|
+
cacheKey: z.ZodString;
|
|
363
|
+
}, z.core.$strip>;
|
|
364
|
+
type RegistrationRecord = z.infer<typeof RegistrationRecordSchema>;
|
|
365
|
+
//#endregion
|
|
366
|
+
//#region src/db/cache.d.ts
|
|
367
|
+
declare class CacheLayer {
|
|
368
|
+
redis: Redis$1 | Redis$2;
|
|
369
|
+
private readonly ttlSeconds;
|
|
370
|
+
constructor(upstash: Redis$1 | Redis$2, ttlSeconds?: number);
|
|
371
|
+
setQueryCacheFor(cacheKey: string, data: unknown, ttlSeconds?: number): Promise<void>;
|
|
372
|
+
getQueryCacheFor(cacheKey: string): Promise<QueryCacheEntry | null>;
|
|
373
|
+
getQueryCacheMetaData(cacheKey: string): Promise<QueryCacheMetadata | null>;
|
|
374
|
+
setQueryCacheMetadata(cacheKey: string, metaData: QueryCacheMetadata): Promise<void>;
|
|
375
|
+
persistRegistrationRecord(subId: string, record: RegistrationRecord): Promise<void>;
|
|
376
|
+
deleteRegistrationRecord(subId: string): Promise<void>;
|
|
377
|
+
deleteRegistrationsRecord(subIds: string[]): Promise<void>;
|
|
378
|
+
fetchRegistrationRecordsBatch(subIds: string[]): Promise<Map<string, RegistrationRecord | null>>;
|
|
379
|
+
getCachedTableColumnTypes(key: string): Promise<CachedPgMetadata | null>;
|
|
380
|
+
setCachedTableColumnsTypes(key: string, value: CachedPgMetadata): Promise<void>;
|
|
381
|
+
/**
|
|
382
|
+
* Race participant: try to claim `lock:recompute:<subId>:<commitTs>`
|
|
383
|
+
* with `SET NX EX`. The single Redis round-trip both arbitrates and
|
|
384
|
+
* sets a TTL fallback in case the winner crashes mid-recompute.
|
|
385
|
+
*/
|
|
386
|
+
tryAcquireRecomputeLock(instanceId: string, subId: string, commitTs: string, ttl: number): Promise<boolean>;
|
|
387
|
+
private getRegistrationKey;
|
|
388
|
+
private getQueryCacheDataKey;
|
|
389
|
+
private getQeruyCacheMetaKey;
|
|
390
|
+
}
|
|
391
|
+
//#endregion
|
|
392
|
+
//#region src/db/db.d.ts
|
|
393
|
+
interface DbQueryResult<T = any> {
|
|
394
|
+
rows: T[];
|
|
395
|
+
rowCount?: number | null;
|
|
396
|
+
}
|
|
397
|
+
interface RawClient {
|
|
398
|
+
query<T = any>(sql: string, params?: unknown[]): Promise<DbQueryResult<T>>;
|
|
399
|
+
}
|
|
400
|
+
interface PooledClient extends RawClient {
|
|
401
|
+
release(): void;
|
|
402
|
+
}
|
|
403
|
+
type DbType = "postgres" | "mysql";
|
|
404
|
+
interface PendingPointEntry {
|
|
405
|
+
entry: PointRead;
|
|
406
|
+
key: string;
|
|
407
|
+
}
|
|
408
|
+
interface PreparedQuery {
|
|
409
|
+
sql: string;
|
|
410
|
+
params: unknown[] | unknown[][];
|
|
411
|
+
operation: "insertSingle" | "insertBatch" | "updateSingle" | "updateBatch" | "deleteSingle" | "deleteBatch" | "pointReadValidation" | "commit_logs";
|
|
412
|
+
table: string;
|
|
413
|
+
entryId?: unknown;
|
|
414
|
+
expectedTs?: bigint;
|
|
415
|
+
entries?: WriteEntry[];
|
|
416
|
+
pendingsEntry?: PendingPointEntry[];
|
|
417
|
+
}
|
|
418
|
+
interface PreparedQueries {
|
|
419
|
+
commits: PreparedQuery[];
|
|
420
|
+
validateReadPoints?: PreparedQuery[];
|
|
421
|
+
hasRangeRead: boolean;
|
|
422
|
+
tableIds?: Uint8Array[];
|
|
423
|
+
rawReadSet?: RawReadEntry[];
|
|
424
|
+
}
|
|
425
|
+
interface Database {
|
|
426
|
+
readonly dbType: DbType;
|
|
427
|
+
readonly sqlBuilder: SqlBuilder;
|
|
428
|
+
columnTypes: Map<string, Map<string, string>>;
|
|
429
|
+
migrationSql: string[];
|
|
430
|
+
bootstrapColumnTypes(opts: {
|
|
431
|
+
redis?: CacheLayer;
|
|
432
|
+
cacheKey: string;
|
|
433
|
+
tables?: string[];
|
|
434
|
+
}): Promise<void>;
|
|
435
|
+
query<T = any>(sql: string, params?: unknown[]): Promise<DbQueryResult<T>>;
|
|
436
|
+
getClient(): Promise<PooledClient>;
|
|
437
|
+
getTransactionClient(): Promise<TxDatabase>;
|
|
438
|
+
getLatestSnapshotTimestamp(): Promise<bigint>;
|
|
439
|
+
updateLatestSnapshotTimestamp(commitTs: bigint): Promise<void>;
|
|
440
|
+
getNextTimestamp(): Promise<bigint>;
|
|
441
|
+
prepareCommitWrites(readSet: ReadEntry[], writeSet: WriteEntry[], commitTs: LazyCommitTsParam): Promise<PreparedQueries>;
|
|
442
|
+
commitWrites(beginTs: bigint, queries: PreparedQueries, commitTs: bigint): Promise<{
|
|
443
|
+
success: boolean;
|
|
444
|
+
}>;
|
|
445
|
+
close(): Promise<void>;
|
|
446
|
+
/**
|
|
447
|
+
* Delete commit_logs older than `ts` (exclusive). Used by the periodic
|
|
448
|
+
* retention sweep in SubscriptionManager so the table doesn't grow
|
|
449
|
+
* unbounded.
|
|
450
|
+
*/
|
|
451
|
+
pruneCommitLogsBefore(ts: bigint): Promise<bigint>;
|
|
452
|
+
/**
|
|
453
|
+
* Half-open range scan: ts >= beginTs AND ts < endTs. Used by the
|
|
454
|
+
* subscription-recovery path to replay logs in a specific time window.
|
|
455
|
+
*/
|
|
456
|
+
getCommitLogsBetweenTs(beginTs: bigint, endTs: bigint, tableIds: Uint8Array[]): Promise<CommitLogEntry[]>;
|
|
457
|
+
/**
|
|
458
|
+
* Conflict-check scan for OCC: ts >= sinceTs AND ts <> excludeTs. The
|
|
459
|
+
* exclude is our own commitTs so we don't conflict with ourselves; the
|
|
460
|
+
* lack of an upper bound is intentional, so a concurrent peer that
|
|
461
|
+
* happens to have a higher commitTs but committed before us is still
|
|
462
|
+
* visible. (MVCC keeps in-flight peers invisible until they commit.)
|
|
463
|
+
*/
|
|
464
|
+
getCommitLogsSinceTs(sinceTs: bigint, excludeTs: bigint, tableIds: Uint8Array[]): Promise<CommitLogEntry[]>;
|
|
465
|
+
/**
|
|
466
|
+
* For each `update`/`delete` entry, attach `prevData` (consumed by the
|
|
467
|
+
* invalidator) and `expectedCommitTs` (the CAS fence).
|
|
468
|
+
*
|
|
469
|
+
* `expectedCommitTs` is preferentially copied from a prior point-read of
|
|
470
|
+
* the same row in `readSet` — that's the value the handler's logic
|
|
471
|
+
* actually depended on, so the CAS check enforces beginTs-level isolation
|
|
472
|
+
* for read-then-update patterns. If no prior read exists ("blind"
|
|
473
|
+
* write), we fall back to the value observed in this batch fetch (weak
|
|
474
|
+
* OCC, sufficient for writes that don't depend on prior state).
|
|
475
|
+
*
|
|
476
|
+
* `prevData` always comes from this batch fetch (SELECT * per table) so
|
|
477
|
+
* the invalidator has the full row regardless of which columns the
|
|
478
|
+
* handler's read selected.
|
|
479
|
+
*
|
|
480
|
+
* If the target row no longer exists at fetch time, `expectedCommitTs`
|
|
481
|
+
* is left undefined and the per-row CAS will match nothing — surfaced
|
|
482
|
+
* as OccConflictError.
|
|
483
|
+
*/
|
|
484
|
+
attachPrevDataToWriteSet(writeSet: WriteEntry[], readSet: ReadEntry[]): Promise<void>;
|
|
485
|
+
}
|
|
486
|
+
interface TxDatabase extends Database {
|
|
487
|
+
begin(): Promise<void>;
|
|
488
|
+
commit(): Promise<void>;
|
|
489
|
+
rollback(): Promise<void>;
|
|
490
|
+
release(): void;
|
|
491
|
+
}
|
|
492
|
+
interface JsonOpOptions$1 {
|
|
493
|
+
/**
|
|
494
|
+
* When true, the bound `value` parameter is treated as already prepared
|
|
495
|
+
* for the underlying SQL (e.g. a literal JSON path string for
|
|
496
|
+
* jsonHasKey, a JSON-encoded literal for the contains family). When
|
|
497
|
+
* false/omitted, the value was prepared client-side from a JS value.
|
|
498
|
+
*/
|
|
499
|
+
raw?: boolean;
|
|
500
|
+
/**
|
|
501
|
+
* 1-based positional index of an extra bound parameter holding a
|
|
502
|
+
* jsonpath that scopes the contains-family check to a sub-document of
|
|
503
|
+
* the target column. When omitted, the check runs against the whole
|
|
504
|
+
* column value.
|
|
505
|
+
*/
|
|
506
|
+
pathIndex?: number;
|
|
507
|
+
/**
|
|
508
|
+
* jsonHasKey only: when set, multiple path parameters are bound starting
|
|
509
|
+
* at `paramIndex`, and the predicate evaluates whether any (`one`) or
|
|
510
|
+
* every (`all`) path exists in the column.
|
|
511
|
+
*/
|
|
512
|
+
mode?: "one" | "all";
|
|
513
|
+
/** Number of bound path parameters in multi-path mode. */
|
|
514
|
+
pathCount?: number;
|
|
515
|
+
}
|
|
516
|
+
interface SqlBuilder {
|
|
517
|
+
placeholder(index: number): string;
|
|
518
|
+
like(col: string, paramIndex: number): string;
|
|
519
|
+
ilike(col: string, paramIndex: number): string;
|
|
520
|
+
icontains(col: string, paramIndex: number): string;
|
|
521
|
+
/** PG @> ; MySQL JSON_CONTAINS */
|
|
522
|
+
jsonContains(col: string, paramIndex: number, opts?: JsonOpOptions$1): string;
|
|
523
|
+
/** PG <@ ; MySQL JSON_CONTAINS(candidate, target) */
|
|
524
|
+
jsonContainedBy(col: string, paramIndex: number, opts?: JsonOpOptions$1): string;
|
|
525
|
+
/**
|
|
526
|
+
* Key/path existence. With `opts.raw === true`, the bound param is a JSON
|
|
527
|
+
* path expression (PG `jsonb_path_exists`, MySQL `JSON_CONTAINS_PATH`).
|
|
528
|
+
* Otherwise the bound param is a literal top-level key (PG `?`, MySQL
|
|
529
|
+
* `JSON_CONTAINS_PATH($."<key>")` with server-side quoting).
|
|
530
|
+
* With `opts.pathCount` set, emits the multi-path form keyed by `mode`.
|
|
531
|
+
*/
|
|
532
|
+
jsonHasKey(col: string, paramIndex: number, opts?: JsonOpOptions$1): string;
|
|
533
|
+
/** Array membership: target array contains the given element. */
|
|
534
|
+
jsonArrayContains(col: string, paramIndex: number, opts?: JsonOpOptions$1): string;
|
|
535
|
+
}
|
|
536
|
+
declare class LazyCommitTsParam {
|
|
537
|
+
value: unknown;
|
|
538
|
+
constructor(value: unknown);
|
|
539
|
+
toPostgres(prepareValue: (value: any) => any): any;
|
|
540
|
+
toString(): any;
|
|
541
|
+
validate(): void;
|
|
542
|
+
}
|
|
543
|
+
//#endregion
|
|
544
|
+
//#region src/db/schema.d.ts
|
|
545
|
+
interface ColumnCodec<TData = unknown, TDriver = unknown> {
|
|
546
|
+
encode?: (value: TData) => TDriver;
|
|
547
|
+
decode?: (value: TDriver) => TData;
|
|
548
|
+
}
|
|
549
|
+
type SchemaCodecField<TSchema extends ZodRawShape, K extends PropertyKey> = K extends keyof TSchema ? TSchema[K] extends z$1.ZodTypeAny ? z$1.infer<TSchema[K]> : unknown : K extends keyof BaseSchema ? BaseSchema[K] extends z$1.ZodTypeAny ? z$1.infer<BaseSchema[K]> : unknown : unknown;
|
|
550
|
+
type SchemaCodecs<TSchema extends ZodRawShape> = Partial<{ [K in keyof (TSchema & BaseSchema)]: ColumnCodec<SchemaCodecField<TSchema, K>, any> }>;
|
|
551
|
+
interface SchemaColumnsOptions<TSchema extends ZodRawShape = ZodRawShape> {
|
|
552
|
+
codecs?: SchemaCodecs<TSchema>;
|
|
553
|
+
}
|
|
554
|
+
interface SchemaColumnMapping {
|
|
555
|
+
[key: string]: string;
|
|
556
|
+
}
|
|
557
|
+
interface DeclarativeIndex {
|
|
558
|
+
name: string;
|
|
559
|
+
columns: string[];
|
|
560
|
+
unique?: boolean;
|
|
561
|
+
type?: "btree" | "hash" | "gin" | "gist" | "spgist" | "brin";
|
|
562
|
+
where?: string;
|
|
563
|
+
using?: string;
|
|
564
|
+
options?: string;
|
|
565
|
+
tablespace?: string;
|
|
566
|
+
}
|
|
567
|
+
type IndexDefinition = string | DeclarativeIndex;
|
|
568
|
+
interface DefineSchemaConfig<TSchema extends ZodRawShape> {
|
|
569
|
+
name: string;
|
|
570
|
+
schema: TSchema;
|
|
571
|
+
options?: SchemaColumnsOptions<TSchema>;
|
|
572
|
+
columns?: SchemaColumnMapping;
|
|
573
|
+
indexes?: IndexDefinition[];
|
|
574
|
+
}
|
|
575
|
+
type CodecDataType<TCodec, TFallback> = [TCodec] extends [undefined] ? TFallback : TCodec extends {
|
|
576
|
+
decode: (...args: any[]) => infer TDecoded;
|
|
577
|
+
} ? TDecoded : TCodec extends ColumnCodec<infer TData, unknown> ? TData : TFallback;
|
|
578
|
+
type ZodOutput<TZod> = [TZod] extends [undefined] ? unknown : TZod extends z$1.ZodTypeAny ? z$1.infer<TZod> : unknown;
|
|
579
|
+
type ComputedDataType<TCodec, TZod> = CodecDataType<TCodec, ZodOutput<TZod>>;
|
|
580
|
+
type ComputedCodec<TData, TDriver> = ColumnCodec<TData, TDriver>;
|
|
581
|
+
type OverrideField<TObj, TKey extends PropertyKey, TValue> = Omit<TObj, TKey> & { [K in TKey]: TValue };
|
|
582
|
+
interface ComputedFieldConfig<TField extends string, TDecoded = unknown, TDriver = unknown, TZodType extends z$1.ZodTypeAny | undefined = undefined> {
|
|
583
|
+
field: TField;
|
|
584
|
+
sql: string;
|
|
585
|
+
alias?: string;
|
|
586
|
+
type?: TZodType;
|
|
587
|
+
codec?: {
|
|
588
|
+
decode: (value: TDriver) => TDecoded;
|
|
589
|
+
encode?: (value: TDecoded) => TDriver;
|
|
590
|
+
};
|
|
591
|
+
}
|
|
592
|
+
type ComputedField = {
|
|
593
|
+
field: string;
|
|
594
|
+
sql: string;
|
|
595
|
+
alias: string;
|
|
596
|
+
codec?: ColumnCodec<any, any>;
|
|
597
|
+
};
|
|
598
|
+
declare function defineComputedField<TField extends string, TDecoded = unknown, TDriver = unknown, TZodType extends z$1.ZodTypeAny | undefined = undefined>(config: ComputedFieldConfig<TField, TDecoded, TDriver, TZodType>): ComputedFieldConfig<TField, TDecoded, TDriver, TZodType>;
|
|
599
|
+
type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
600
|
+
type ApplySchemaCodecs<TBase, TCodecs> = { [K in keyof TBase]: K extends keyof TCodecs ? CodecDataType<TCodecs[K], TBase[K]> : TBase[K] };
|
|
601
|
+
type ResolveSchemaType<TSchema extends ZodRawShape, TOptions extends SchemaColumnsOptions<TSchema>> = TOptions extends {
|
|
602
|
+
codecs: infer TCodecs;
|
|
603
|
+
} ? Prettify<ApplySchemaCodecs<z$1.infer<z$1.ZodObject<TSchema & BaseSchema>>, TCodecs>> : Prettify<z$1.infer<z$1.ZodObject<TSchema & BaseSchema>>>;
|
|
604
|
+
type IsOptionalField<T> = T extends z$1.ZodOptional<any> ? true : T extends z$1.ZodNullable<any> ? true : T extends z$1.ZodDefault<any> ? true : false;
|
|
605
|
+
type OptionalKeys<TZod extends ZodRawShape> = { [K in keyof TZod]: IsOptionalField<TZod[K]> extends true ? K : never }[keyof TZod];
|
|
606
|
+
type RequiredKeys<TZod extends ZodRawShape> = { [K in keyof TZod]: IsOptionalField<TZod[K]> extends true ? never : K }[keyof TZod];
|
|
607
|
+
type BaseSchema = {
|
|
608
|
+
id: z$1.ZodString;
|
|
609
|
+
commitTs: z$1.ZodCoercedBigInt;
|
|
610
|
+
};
|
|
611
|
+
declare const schemaRegistry: Map<string, SchemaDefinition<string, any, any>>;
|
|
612
|
+
declare let shouldTrackSchema: boolean;
|
|
613
|
+
declare function trackSchema(): void;
|
|
614
|
+
declare function defineSchema<TSchema extends ZodRawShape, TName extends string, TOptions extends SchemaColumnsOptions<TSchema> = SchemaColumnsOptions<TSchema>>(config: DefineSchemaConfig<TSchema> & {
|
|
615
|
+
name: TName;
|
|
616
|
+
options?: TOptions;
|
|
617
|
+
}): SchemaDefinition<TName, Prettify<TSchema & BaseSchema>, ResolveSchemaType<TSchema, TOptions>>;
|
|
618
|
+
declare function tableNameToId(tableName: string): Uint8Array;
|
|
619
|
+
interface StoredSchemaColumnsOptions {
|
|
620
|
+
codecs?: Record<string, ColumnCodec<any, any>>;
|
|
621
|
+
}
|
|
622
|
+
interface SchemaDefinition<TTable extends string, TZod extends ZodRawShape, TData = z$1.infer<z$1.ZodObject<TZod>>> {
|
|
623
|
+
tableId: Uint8Array;
|
|
624
|
+
table: TTable;
|
|
625
|
+
schema: z$1.ZodObject<TZod>;
|
|
626
|
+
columnsOptions: StoredSchemaColumnsOptions;
|
|
627
|
+
columns: Record<string, string>;
|
|
628
|
+
indexes: IndexDefinition[];
|
|
629
|
+
_dataType?: TData;
|
|
630
|
+
}
|
|
631
|
+
type InferSchema<T extends SchemaDefinition<string, ZodRawShape, any>> = T extends SchemaDefinition<string, ZodRawShape, infer TData> ? TData : never;
|
|
632
|
+
type InsertData<T extends SchemaDefinition<string, ZodRawShape, any>> = T extends SchemaDefinition<string, infer TZod, infer TData> ? { [K in RequiredKeys<TZod> as K extends "id" | "commitTs" ? never : K]: Extract<K, string> extends keyof TData ? TData[Extract<K, string>] : never } & { [K in OptionalKeys<TZod> as K extends "id" | "commitTs" ? never : K]?: Extract<K, string> extends keyof TData ? TData[Extract<K, string>] : never } : never;
|
|
633
|
+
interface Model {
|
|
634
|
+
table: string;
|
|
635
|
+
tableId: Uint8Array;
|
|
636
|
+
columns: Record<string, string>;
|
|
637
|
+
reverseColumns: Record<string, string>;
|
|
638
|
+
types: Record<string, string>;
|
|
639
|
+
codecs: Record<string, ColumnCodec<any, any>>;
|
|
640
|
+
}
|
|
641
|
+
type MaybePromise<T> = T | Promise<T>;
|
|
642
|
+
type ReturnLiveQuery<TLiveQueryFn extends (...args: any[]) => MaybePromise<LiveQueryHandle<any>>> = Awaited<ReturnType<TLiveQueryFn>> extends LiveQueryHandle<infer T> ? T : never;
|
|
643
|
+
type ReturnQuery<TQueryFn extends (...args: any[]) => any> = Awaited<ReturnType<TQueryFn>>;
|
|
644
|
+
type QueryArgs<TQueryFn extends (...args: any[]) => any> = Parameters<TQueryFn>[0];
|
|
645
|
+
type MutationArgs<TMutationFn extends (...args: any[]) => any> = Parameters<TMutationFn>[0];
|
|
646
|
+
type ActionArgs<TActionFn extends (...args: any[]) => any> = Parameters<TActionFn>[0];
|
|
647
|
+
//#endregion
|
|
648
|
+
//#region src/db/query.d.ts
|
|
649
|
+
type FieldValue<S extends SchemaDefinition<string, ZodRawShape>, K> = K extends keyof InferSchema<S> ? InferSchema<S>[K] : never;
|
|
650
|
+
type OrderableValue = number | bigint | string | Date;
|
|
651
|
+
type StringFieldKeys<S extends SchemaDefinition<string, ZodRawShape>> = { [K in keyof InferSchema<S>]: NonNullable<InferSchema<S>[K]> extends string ? K : never }[keyof InferSchema<S>];
|
|
652
|
+
type OrderableFieldKeys<S extends SchemaDefinition<string, ZodRawShape>> = { [K in keyof InferSchema<S>]: NonNullable<InferSchema<S>[K]> extends OrderableValue ? K : never }[keyof InferSchema<S>];
|
|
653
|
+
type JsonFieldKeys<S extends SchemaDefinition<string, ZodRawShape>> = { [K in keyof InferSchema<S>]: NonNullable<InferSchema<S>[K]> extends OrderableValue ? never : NonNullable<InferSchema<S>[K]> extends boolean ? never : NonNullable<InferSchema<S>[K]> extends (object | unknown[]) ? K : unknown extends NonNullable<InferSchema<S>[K]> ? K : never }[keyof InferSchema<S>];
|
|
654
|
+
interface JsonOpOptions {
|
|
655
|
+
/**
|
|
656
|
+
* Skip client-side preparation of the value (no JSON-stringify, no key
|
|
657
|
+
* escaping). The caller is responsible for the exact form the dialect
|
|
658
|
+
* expects: a JSON path string for jsonHasKey, a JSON-encoded string for
|
|
659
|
+
* the contains family.
|
|
660
|
+
*/
|
|
661
|
+
raw?: true;
|
|
662
|
+
}
|
|
663
|
+
interface JsonContainsOptions extends JsonOpOptions {
|
|
664
|
+
/**
|
|
665
|
+
* Sub-path into the target JSON to scope the check to. `string` is a
|
|
666
|
+
* single literal top-level key; `string[]` is a nested literal-key path
|
|
667
|
+
* compiled to `$."a"."b"`. Mutually exclusive with `pathRaw`.
|
|
668
|
+
*/
|
|
669
|
+
path?: string | string[];
|
|
670
|
+
/**
|
|
671
|
+
* Raw jsonpath expression used verbatim by the dialect (PG `jsonpath`,
|
|
672
|
+
* MySQL JSON path). Mutually exclusive with `path`.
|
|
673
|
+
*/
|
|
674
|
+
pathRaw?: string;
|
|
675
|
+
}
|
|
676
|
+
interface JsonHasKeyMultiOptions extends JsonOpOptions {
|
|
677
|
+
/** Required for the multi-path overload — chooses any vs every. */
|
|
678
|
+
mode: "one" | "all";
|
|
679
|
+
}
|
|
680
|
+
declare class QueryBuilder<S extends SchemaDefinition<string, ZodRawShape>> {
|
|
681
|
+
protected ctx: TxContext;
|
|
682
|
+
protected model: Model;
|
|
683
|
+
constructor(ctx: TxContext, model: Model);
|
|
684
|
+
protected getColumnName(key: string): string;
|
|
685
|
+
select(): SelectQueryBuilder<S, keyof InferSchema<S>>;
|
|
686
|
+
select<K extends keyof InferSchema<S>>(...columns: K[]): SelectQueryBuilder<S, K>;
|
|
687
|
+
}
|
|
688
|
+
type IdAndCommitTs = {
|
|
689
|
+
id: string;
|
|
690
|
+
commitTs: bigint;
|
|
691
|
+
};
|
|
692
|
+
type SelectRow<S extends SchemaDefinition<string, ZodRawShape>, K extends keyof InferSchema<S>, C extends Record<string, unknown>> = Prettify<Pick<InferSchema<S>, Extract<K | "id" | "commitTs", keyof InferSchema<S>>> & C>;
|
|
693
|
+
declare class SelectQueryBuilder<S extends SchemaDefinition<string, ZodRawShape>, K extends keyof InferSchema<S> = never, C extends Record<string, unknown> = {}> {
|
|
694
|
+
private ctx;
|
|
695
|
+
private model;
|
|
696
|
+
private filters;
|
|
697
|
+
private orderByClause;
|
|
698
|
+
private limitVal;
|
|
699
|
+
private offsetVal;
|
|
700
|
+
private selectedProps;
|
|
701
|
+
private computedFields;
|
|
702
|
+
private commentStr;
|
|
703
|
+
constructor(ctx: TxContext, model: Model, filters?: ((fb: FilterBuilder<S>) => void)[], orderByClause?: string | null, limitVal?: number | null, offsetVal?: number | null, selectedProps?: (keyof InferSchema<S>)[], computedFields?: ComputedField[], commentStr?: string);
|
|
704
|
+
private getColumnName;
|
|
705
|
+
private getPropertyName;
|
|
706
|
+
private mapRowToSchema;
|
|
707
|
+
where(filterFn: (fb: FilterBuilder<S>) => void): SelectQueryBuilder<S, K, C>;
|
|
708
|
+
orderBy(column: keyof InferSchema<S> | keyof C, direction?: "asc" | "desc"): SelectQueryBuilder<S, K, C>;
|
|
709
|
+
limit(n: number): SelectQueryBuilder<S, K, C>;
|
|
710
|
+
offset(n: number): SelectQueryBuilder<S, K, C>;
|
|
711
|
+
computed<TField extends string, TZodType extends z$1.ZodTypeAny | undefined = undefined, TDecode extends (value: any) => any = (value: unknown) => unknown>(config: ComputedFieldConfig<TField, ReturnType<TDecode>, Parameters<TDecode>[0], TZodType> & {
|
|
712
|
+
codec: {
|
|
713
|
+
decode: TDecode;
|
|
714
|
+
encode?: (value: ReturnType<TDecode>) => Parameters<TDecode>[0];
|
|
715
|
+
};
|
|
716
|
+
}): SelectQueryBuilder<S, K | TField, OverrideField<C, TField, ComputedDataType<ComputedCodec<ReturnType<TDecode>, Parameters<TDecode>[0]>, TZodType>>>;
|
|
717
|
+
computed<TField extends string, TZodType extends z$1.ZodTypeAny | undefined = undefined>(config: ComputedFieldConfig<TField, unknown, unknown, TZodType> & {
|
|
718
|
+
codec?: undefined;
|
|
719
|
+
}): SelectQueryBuilder<S, K | TField, OverrideField<C, TField, ComputedDataType<undefined, TZodType>>>;
|
|
720
|
+
comment(input: string | Record<string, string>): SelectQueryBuilder<S, K, C>;
|
|
721
|
+
first(): Promise<SelectRow<S, K, C> | null>;
|
|
722
|
+
exists(): Promise<boolean>;
|
|
723
|
+
private static defaultCountType;
|
|
724
|
+
count(): Promise<number>;
|
|
725
|
+
count<T extends z$1.ZodType>(parser: T): Promise<z$1.output<T>>;
|
|
726
|
+
find(id: string): Promise<SelectRow<S, K, C> | null>;
|
|
727
|
+
get(): Promise<SelectRow<S, K, C>[]>;
|
|
728
|
+
private buildPredicate;
|
|
729
|
+
}
|
|
730
|
+
declare class FilterBuilder<S extends SchemaDefinition<string, ZodRawShape>> {
|
|
731
|
+
private columns;
|
|
732
|
+
private codecs;
|
|
733
|
+
predicates: Predicate[];
|
|
734
|
+
constructor(columns: Record<string, string>, codecs: Record<string, ColumnCodec<unknown, unknown>>);
|
|
735
|
+
private add;
|
|
736
|
+
private addJsonContains;
|
|
737
|
+
private getColumnName;
|
|
738
|
+
private encode;
|
|
739
|
+
private encodeJson;
|
|
740
|
+
eq<K extends keyof InferSchema<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S>;
|
|
741
|
+
neq<K extends keyof InferSchema<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S>;
|
|
742
|
+
gt<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S>;
|
|
743
|
+
gte<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S>;
|
|
744
|
+
lt<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S>;
|
|
745
|
+
lte<K extends OrderableFieldKeys<S>>(key: K, value: FieldValue<S, K>): FilterBuilder<S>;
|
|
746
|
+
like<K extends StringFieldKeys<S>>(key: K, pattern: string): FilterBuilder<S>;
|
|
747
|
+
ilike<K extends StringFieldKeys<S>>(key: K, pattern: string): FilterBuilder<S>;
|
|
748
|
+
contains<K extends StringFieldKeys<S>>(key: K, value: string): FilterBuilder<S>;
|
|
749
|
+
icontains<K extends StringFieldKeys<S>>(key: K, value: string): FilterBuilder<S>;
|
|
750
|
+
/**
|
|
751
|
+
* JSON containment. Targets a JSON/JSONB column and asserts the document
|
|
752
|
+
* contains the given candidate (object-key subset for objects,
|
|
753
|
+
* element-subset for arrays — see dialect-specific docs for edge cases).
|
|
754
|
+
* Pass `{ raw: true }` if `value` is already a JSON-encoded string.
|
|
755
|
+
* Pass `{ path: ... }` to scope the check to a sub-document of the
|
|
756
|
+
* target (jsonb_path_query_first on PG, JSON_CONTAINS path arg on MySQL).
|
|
757
|
+
*/
|
|
758
|
+
jsonContains<K extends JsonFieldKeys<S>>(key: K, value: unknown, opts?: JsonContainsOptions): FilterBuilder<S>;
|
|
759
|
+
/** Inverse of {@link jsonContains}: column is contained in the given value. */
|
|
760
|
+
jsonContainedBy<K extends JsonFieldKeys<S>>(key: K, value: unknown, opts?: JsonContainsOptions): FilterBuilder<S>;
|
|
761
|
+
/**
|
|
762
|
+
* Key/path existence check on a JSON column.
|
|
763
|
+
*
|
|
764
|
+
* - String form (top-level key): `jsonHasKey("meta", "color")`. On PG
|
|
765
|
+
* also matches when the column is a string array and `value` is one of
|
|
766
|
+
* its elements (PG `?` semantics); MySQL stays strict to object keys.
|
|
767
|
+
* - Array form (nested path): `jsonHasKey("meta", ["a", "b"])` compiles
|
|
768
|
+
* to a path expression `$."a"."b"` on both dialects.
|
|
769
|
+
* - Raw form: `jsonHasKey("meta", "$.foo[*]", { raw: true })` passes the
|
|
770
|
+
* string through as a dialect path expression (PG `jsonb_path_exists`
|
|
771
|
+
* jsonpath, MySQL `JSON_CONTAINS_PATH`). Caller owns the syntax.
|
|
772
|
+
* - Multi-path form: `jsonHasKey("meta", [["a","b"], "color"], { mode: "all" })`
|
|
773
|
+
* compiles each entry to a jsonpath and emits PG OR/AND of
|
|
774
|
+
* `jsonb_path_exists` or MySQL `JSON_CONTAINS_PATH('all', ...)`.
|
|
775
|
+
*/
|
|
776
|
+
jsonHasKey<K extends JsonFieldKeys<S>>(key: K, value: string): FilterBuilder<S>;
|
|
777
|
+
jsonHasKey<K extends JsonFieldKeys<S>>(key: K, value: string[]): FilterBuilder<S>;
|
|
778
|
+
jsonHasKey<K extends JsonFieldKeys<S>>(key: K, value: string, opts: {
|
|
779
|
+
raw: true;
|
|
780
|
+
}): FilterBuilder<S>;
|
|
781
|
+
jsonHasKey<K extends JsonFieldKeys<S>>(key: K, paths: (string | string[])[], opts: JsonHasKeyMultiOptions): FilterBuilder<S>;
|
|
782
|
+
jsonHasKey<K extends JsonFieldKeys<S>>(key: K, paths: string[], opts: JsonHasKeyMultiOptions & {
|
|
783
|
+
raw: true;
|
|
784
|
+
}): FilterBuilder<S>;
|
|
785
|
+
/**
|
|
786
|
+
* Array element containment: target column is a JSON array; the given
|
|
787
|
+
* `value` (any JSON-encodable type) must appear as one of its elements.
|
|
788
|
+
* Pass `{ raw: true }` if `value` is already a JSON-encoded string.
|
|
789
|
+
* Pass `{ path: ... }` to scope the check to a sub-array of the column.
|
|
790
|
+
*/
|
|
791
|
+
jsonArrayContains<K extends JsonFieldKeys<S>>(key: K, value: unknown, opts?: JsonContainsOptions): FilterBuilder<S>;
|
|
792
|
+
between<K extends OrderableFieldKeys<S>>(key: K, lo: FieldValue<S, K>, hi: FieldValue<S, K>): FilterBuilder<S>;
|
|
793
|
+
isNull<K extends keyof InferSchema<S>>(key: K): FilterBuilder<S>;
|
|
794
|
+
notNull<K extends keyof InferSchema<S>>(key: K): FilterBuilder<S>;
|
|
795
|
+
/**
|
|
796
|
+
* Compose an OR clause. Each callback fills a fresh sub-FilterBuilder
|
|
797
|
+
* with predicates that are AND-ed together within that branch; the
|
|
798
|
+
* branches themselves are OR-ed. Example:
|
|
799
|
+
* f.or([
|
|
800
|
+
* b => b.eq("tag", "a"),
|
|
801
|
+
* b => b.eq("tag", "b").gt("qty", 3), // (tag=b AND qty>3)
|
|
802
|
+
* ])
|
|
803
|
+
* produces (tag=a) OR (tag=b AND qty>3).
|
|
804
|
+
*/
|
|
805
|
+
or(branches: ((fb: FilterBuilder<S>) => void)[]): FilterBuilder<S>;
|
|
806
|
+
}
|
|
807
|
+
declare function buildPredicateSql(predicate: Predicate, params: unknown[], sql: SqlBuilder): string;
|
|
808
|
+
declare function matchesPredicate(row: Record<string, unknown>, predicate: Predicate): boolean;
|
|
809
|
+
declare function jsonContains(target: unknown, candidate: unknown): boolean;
|
|
810
|
+
declare function jsonPathExtract(val: unknown, path: string): unknown;
|
|
811
|
+
declare function jsonPathExists(val: unknown, path: string): boolean;
|
|
812
|
+
//#endregion
|
|
813
|
+
//#region src/db/context.d.ts
|
|
814
|
+
declare class TxContext {
|
|
815
|
+
readonly beginTs: bigint;
|
|
816
|
+
readonly db: Database;
|
|
817
|
+
protected readSet: ReadEntry[];
|
|
818
|
+
protected writeSet: WriteEntry[];
|
|
819
|
+
private models;
|
|
820
|
+
protected getOrCreateModel(schema: SchemaDefinition<string, ZodRawShape>): Model;
|
|
821
|
+
constructor(db: Database, beginTs: bigint);
|
|
822
|
+
internalGetReadSet(): ReadEntry[];
|
|
823
|
+
internalGetWriteSet(): WriteEntry[];
|
|
824
|
+
protected findPendingWrite(table: string, id: string): WriteEntry | undefined;
|
|
825
|
+
protected findPendingInsert(table: string, id: string): WriteEntry | undefined;
|
|
826
|
+
protected encodeWithCodec(model: Model, property: string, value: unknown): unknown;
|
|
827
|
+
}
|
|
828
|
+
declare class DbReader extends TxContext {
|
|
829
|
+
query<S extends SchemaDefinition<string, ZodRawShape>>(schema: S): QueryBuilder<S>;
|
|
830
|
+
}
|
|
831
|
+
declare class DbWriter extends DbReader {
|
|
832
|
+
insert<S extends SchemaDefinition<string, ZodRawShape>, ID extends string>(schema: S, id: ID, data: InsertData<S>): Promise<void>;
|
|
833
|
+
update<S extends SchemaDefinition<string, ZodRawShape>, ID extends string>(schema: S, id: ID, data: Partial<Omit<InferSchema<S>, "id" | "commitTs">>): Promise<void>;
|
|
834
|
+
delete<S extends SchemaDefinition<string, ZodRawShape>, ID extends string>(schema: S, id: ID): Promise<void>;
|
|
835
|
+
}
|
|
836
|
+
//#endregion
|
|
837
|
+
//#region src/db/query_definition.d.ts
|
|
838
|
+
/**
|
|
839
|
+
* A named, typed query definition produced by defineQuery().
|
|
840
|
+
* Carries the query function at runtime and the name/params/result types
|
|
841
|
+
* at compile time — making it the single source of truth for both the
|
|
842
|
+
* server-side registry and the client-side RPC.
|
|
843
|
+
*/
|
|
844
|
+
interface QueryDefinition<TName extends string, TParams, TResult> {
|
|
845
|
+
readonly _type: "QueryDefinition";
|
|
846
|
+
readonly name: TName;
|
|
847
|
+
readonly fn: (ctx: DbReader, params: TParams) => Promise<TResult>;
|
|
848
|
+
}
|
|
849
|
+
type AnyQueryDef = QueryDefinition<string, any, any>;
|
|
850
|
+
/** Extract the params type from a QueryDefinition. */
|
|
851
|
+
type ParamsOf<D extends AnyQueryDef> = D extends QueryDefinition<any, infer P, any> ? P : never;
|
|
852
|
+
/** Extract the result type from a QueryDefinition. */
|
|
853
|
+
type ResultOf<D extends AnyQueryDef> = D extends QueryDefinition<any, any, infer R> ? R : never;
|
|
854
|
+
/**
|
|
855
|
+
* Convert a readonly tuple of QueryDefinitions into a Record keyed by their
|
|
856
|
+
* name literals. This is what makes ClientRpc fully type-safe: each key in
|
|
857
|
+
* the map carries its own TParams and TResult rather than collapsing to `any`.
|
|
858
|
+
*
|
|
859
|
+
* Example:
|
|
860
|
+
* const defs = [projectBoardQuery, teamMembersQuery] as const;
|
|
861
|
+
* type Map = DefsToMap<typeof defs>;
|
|
862
|
+
* // → { projectBoard: typeof projectBoardQuery; teamMembers: typeof teamMembersQuery }
|
|
863
|
+
*/
|
|
864
|
+
type DefsToMap<T extends readonly AnyQueryDef[]> = { [D in T[number] as D["name"]]: D };
|
|
865
|
+
/** For test teardown only — clears the global map between suites. */
|
|
866
|
+
declare function _resetGlobalDefs(): void;
|
|
867
|
+
/**
|
|
868
|
+
* Create a named, typed query definition.
|
|
869
|
+
*
|
|
870
|
+
* The definition is automatically registered in a module-level global so
|
|
871
|
+
* the server can call registry.defineAll() instead of listing every query
|
|
872
|
+
* explicitly. On the client, pass the definition to createClientRpc() to
|
|
873
|
+
* get a fully typed subscribe() call.
|
|
874
|
+
*
|
|
875
|
+
* Usage:
|
|
876
|
+
* export const projectBoardQuery = defineQuery(
|
|
877
|
+
* "projectBoard",
|
|
878
|
+
* async (ctx, params: { projectId: string }) => {
|
|
879
|
+
* return ctx.query(Tasks)
|
|
880
|
+
* .select()
|
|
881
|
+
* .where(f => f.eq("projectId", params.projectId))
|
|
882
|
+
* .get();
|
|
883
|
+
* }
|
|
884
|
+
* );
|
|
885
|
+
*/
|
|
886
|
+
declare function defineQuery<TName extends string, TParams, TResult>(name: TName, fn: (ctx: DbReader, params: TParams) => Promise<TResult>): QueryDefinition<TName, TParams, TResult>;
|
|
887
|
+
//#endregion
|
|
888
|
+
//#region src/db/realtime_db.d.ts
|
|
889
|
+
declare class SupaliveDb {
|
|
890
|
+
readonly impl: Database;
|
|
891
|
+
constructor(impl: Database);
|
|
892
|
+
static create(config: {
|
|
893
|
+
db: Database;
|
|
894
|
+
}): SupaliveDb;
|
|
895
|
+
protected onAfterCommit?: (writeSet: WriteEntry[], commitTs: CommitTs) => void;
|
|
896
|
+
query<T>(fn: (ctx: DbReader) => Promise<T>): Promise<T>;
|
|
897
|
+
liveQuery<T>(fn: (ctx: DbReader) => Promise<T>): Promise<LiveResult<T>>;
|
|
898
|
+
mutation<T>(fn: (ctx: DbWriter) => Promise<T>, retryPolicy?: RetryPolicy): Promise<MutationResult<T>>;
|
|
899
|
+
}
|
|
900
|
+
declare const sleep: (ms: number) => Promise<void>;
|
|
901
|
+
//#endregion
|
|
902
|
+
//#region src/router/procedure.d.ts
|
|
903
|
+
/**
|
|
904
|
+
* Query context passed to query handlers.
|
|
905
|
+
* Contains database reader and user-defined server context.
|
|
906
|
+
*/
|
|
907
|
+
interface QueryCtx<TContext = unknown> {
|
|
908
|
+
/** Database reader for queries */
|
|
909
|
+
db: DbReader;
|
|
910
|
+
/** User-defined server context (auth, requestId, etc.) */
|
|
911
|
+
serverCtx?: TContext;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Mutation context passed to mutation handlers.
|
|
915
|
+
* Contains database writer and user-defined server context.
|
|
916
|
+
*/
|
|
917
|
+
interface MutationCtx<TContext = unknown> {
|
|
918
|
+
/** Database writer for mutations (includes insert/update/delete) */
|
|
919
|
+
db: DbWriter;
|
|
920
|
+
/** User-defined server context (auth, requestId, etc.) */
|
|
921
|
+
serverCtx?: TContext;
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Action context passed to action handlers.
|
|
925
|
+
* Contains the full SupaliveDb for both queries and mutations, plus user-defined server context.
|
|
926
|
+
*/
|
|
927
|
+
interface ActionCtx<TContext = unknown> {
|
|
928
|
+
/** Full database interface for queries and mutations */
|
|
929
|
+
db: SupaliveDb;
|
|
930
|
+
/** User-defined server context (auth, requestId, etc.) */
|
|
931
|
+
serverCtx?: TContext;
|
|
932
|
+
}
|
|
933
|
+
type QueryFn<TInput, TResult, TContext = unknown> = (ctx: QueryCtx<TContext>, input: TInput) => Promise<TResult>;
|
|
934
|
+
type MutationFn<TInput, TResult, TContext = unknown> = (ctx: MutationCtx<TContext>, input: TInput) => Promise<TResult>;
|
|
935
|
+
type ActionFn<TInput, TResult, TContext = unknown> = (ctx: ActionCtx<TContext>, input: TInput) => Promise<TResult>;
|
|
936
|
+
/**
|
|
937
|
+
* Per-procedure override for the cache/subscription segmentation key.
|
|
938
|
+
*
|
|
939
|
+
* omitted | undefined → fall back to `config.getUserId(serverCtx)` (default)
|
|
940
|
+
* false → no identity in hash; cache/sub shared across all users
|
|
941
|
+
* string → a static identity literal (e.g. "public" or a tenant id)
|
|
942
|
+
* function → compute from serverCtx + input (sync)
|
|
943
|
+
*
|
|
944
|
+
* When the result of a query is identical regardless of who calls it, set
|
|
945
|
+
* this to a literal (or `false`) so a single cache entry serves everyone.
|
|
946
|
+
*
|
|
947
|
+
* The function form intentionally takes `serverCtx` (not the full `QueryCtx`)
|
|
948
|
+
* because identity is resolved before any DB read is issued.
|
|
949
|
+
*/
|
|
950
|
+
type QueryIdentitySpec<TInput, TContext> = false | string | ((serverCtx: TContext, input: TInput) => string | null | undefined);
|
|
951
|
+
interface BaseProcedure<TInput, TResult, TType extends "query" | "mutation" | "action", TContext = unknown, TInternal extends boolean = boolean> {
|
|
952
|
+
readonly _type: "procedure";
|
|
953
|
+
readonly procedureType: TType;
|
|
954
|
+
readonly inputSchema: ZodType<TInput>;
|
|
955
|
+
readonly fn: QueryFn<TInput, TResult, TContext> | MutationFn<TInput, TResult, TContext> | ActionFn<TInput, TResult, TContext>;
|
|
956
|
+
readonly internal: TInternal;
|
|
957
|
+
}
|
|
958
|
+
interface QueryProcedure<TInput, TResult, TContext = unknown, TInternal extends boolean = boolean> extends BaseProcedure<TInput, TResult, "query", TContext, TInternal> {
|
|
959
|
+
readonly procedureType: "query";
|
|
960
|
+
readonly fn: QueryFn<TInput, TResult, TContext>;
|
|
961
|
+
readonly queryIdentity?: QueryIdentitySpec<TInput, TContext>;
|
|
962
|
+
}
|
|
963
|
+
interface MutationProcedure<TInput, TResult, TContext = unknown, TInternal extends boolean = boolean> extends BaseProcedure<TInput, TResult, "mutation", TContext, TInternal> {
|
|
964
|
+
readonly procedureType: "mutation";
|
|
965
|
+
readonly fn: MutationFn<TInput, TResult, TContext>;
|
|
966
|
+
}
|
|
967
|
+
interface ActionProcedure<TInput, TResult, TContext = unknown, TInternal extends boolean = boolean> extends BaseProcedure<TInput, TResult, "action", TContext, TInternal> {
|
|
968
|
+
readonly procedureType: "action";
|
|
969
|
+
readonly fn: ActionFn<TInput, TResult, TContext>;
|
|
970
|
+
}
|
|
971
|
+
type AnyProcedure<TContext = unknown> = QueryProcedure<any, any, TContext> | MutationProcedure<any, any, TContext> | ActionProcedure<any, any, TContext>;
|
|
972
|
+
interface QueryConfig<TInput, TResult, TContext = unknown> {
|
|
973
|
+
/** Zod schema for input validation */
|
|
974
|
+
args: ZodType<TInput>;
|
|
975
|
+
/** The query handler function */
|
|
976
|
+
handler: QueryFn<TInput, TResult, TContext>;
|
|
977
|
+
/** Mark as internal (server-only). Default: false */
|
|
978
|
+
internal?: boolean;
|
|
979
|
+
/**
|
|
980
|
+
* Override the cache/subscription segmentation key for this procedure.
|
|
981
|
+
* See {@link QueryIdentitySpec}. Omit to keep the default (per-user) behavior.
|
|
982
|
+
*/
|
|
983
|
+
queryIdentity?: QueryIdentitySpec<TInput, TContext>;
|
|
984
|
+
}
|
|
985
|
+
interface MutationConfig<TInput, TResult, TContext = unknown> {
|
|
986
|
+
/** Zod schema for input validation */
|
|
987
|
+
args: ZodType<TInput>;
|
|
988
|
+
/** The mutation handler function */
|
|
989
|
+
handler: MutationFn<TInput, TResult, TContext>;
|
|
990
|
+
/** Mark as internal (server-only). Default: false */
|
|
991
|
+
internal?: boolean;
|
|
992
|
+
}
|
|
993
|
+
interface ActionConfig<TInput, TResult, TContext = unknown> {
|
|
994
|
+
/** Zod schema for input validation */
|
|
995
|
+
args: ZodType<TInput>;
|
|
996
|
+
/** The action handler function */
|
|
997
|
+
handler: ActionFn<TInput, TResult, TContext>;
|
|
998
|
+
/** Mark as internal (server-only). Default: false */
|
|
999
|
+
internal?: boolean;
|
|
1000
|
+
}
|
|
1001
|
+
/** Extract input type from a procedure */
|
|
1002
|
+
type InputOf<T> = T extends BaseProcedure<infer I, any, any, any> ? I : never;
|
|
1003
|
+
/** Extract output type from a procedure */
|
|
1004
|
+
type OutputOf<T> = T extends BaseProcedure<any, infer O, any, any> ? O : never;
|
|
1005
|
+
/** Extract procedure type (query/mutation) */
|
|
1006
|
+
type TypeOf<T> = T extends BaseProcedure<any, any, infer Type, any> ? Type : never;
|
|
1007
|
+
/** Extract server context type from a procedure */
|
|
1008
|
+
type ContextOf<T> = T extends BaseProcedure<any, any, any, infer C> ? C : never;
|
|
1009
|
+
/**
|
|
1010
|
+
* Create a query builder with a pre-defined context type.
|
|
1011
|
+
* This allows you to define the context type once and have it inferred
|
|
1012
|
+
* automatically in all your query handlers.
|
|
1013
|
+
*
|
|
1014
|
+
* @example
|
|
1015
|
+
* // Define your server context
|
|
1016
|
+
* interface ServerContext {
|
|
1017
|
+
* auth: { userId: string };
|
|
1018
|
+
* requestId: string;
|
|
1019
|
+
* }
|
|
1020
|
+
*
|
|
1021
|
+
* // Create a typed query builder
|
|
1022
|
+
* const query = createQueryBuilder<ServerContext>();
|
|
1023
|
+
*
|
|
1024
|
+
* // Use it - context type is automatically inferred!
|
|
1025
|
+
* const getUser = query({
|
|
1026
|
+
* args: z.object({ id: z.string() }),
|
|
1027
|
+
* handler: async (ctx, { id }) => {
|
|
1028
|
+
* // ctx.db for database queries
|
|
1029
|
+
* const user = await ctx.db.query(UsersSchema).find(id);
|
|
1030
|
+
* // ctx.context for server context
|
|
1031
|
+
* console.log(ctx.context.requestId);
|
|
1032
|
+
* return user;
|
|
1033
|
+
* }
|
|
1034
|
+
* });
|
|
1035
|
+
*/
|
|
1036
|
+
declare function createQueryBuilder<TContext = unknown>(): <TInput, TResult, const TInternal extends boolean = false>(config: QueryConfig<TInput, TResult, TContext> & {
|
|
1037
|
+
internal?: TInternal;
|
|
1038
|
+
}) => QueryProcedure<TInput, TResult, TContext, TInternal>;
|
|
1039
|
+
/**
|
|
1040
|
+
* Create a mutation builder with a pre-defined context type.
|
|
1041
|
+
* This allows you to define the context type once and have it inferred
|
|
1042
|
+
* automatically in all your mutation handlers.
|
|
1043
|
+
*
|
|
1044
|
+
* @example
|
|
1045
|
+
* // Define your server context
|
|
1046
|
+
* interface ServerContext {
|
|
1047
|
+
* auth: { userId: string };
|
|
1048
|
+
* requestId: string;
|
|
1049
|
+
* }
|
|
1050
|
+
*
|
|
1051
|
+
* // Create a typed mutation builder
|
|
1052
|
+
* const mutation = createMutationBuilder<ServerContext>();
|
|
1053
|
+
*
|
|
1054
|
+
* // Use it - context type is automatically inferred!
|
|
1055
|
+
* const createUser = mutation({
|
|
1056
|
+
* args: z.object({ name: z.string() }),
|
|
1057
|
+
* handler: async (ctx, { name }) => {
|
|
1058
|
+
* // ctx.db for mutations
|
|
1059
|
+
* await ctx.db.insert(UsersSchema, id, { name });
|
|
1060
|
+
* // ctx.context for server context
|
|
1061
|
+
* console.log(ctx.context.requestId);
|
|
1062
|
+
* return { success: true };
|
|
1063
|
+
* }
|
|
1064
|
+
* });
|
|
1065
|
+
*/
|
|
1066
|
+
declare function createMutationBuilder<TContext = unknown>(): <TInput, TResult, const TInternal extends boolean = false>(config: MutationConfig<TInput, TResult, TContext> & {
|
|
1067
|
+
internal?: TInternal;
|
|
1068
|
+
}) => MutationProcedure<TInput, TResult, TContext, TInternal>;
|
|
1069
|
+
/**
|
|
1070
|
+
* Create an action builder with a pre-defined context type.
|
|
1071
|
+
* Actions have access to the full SupaliveDb for both queries and mutations.
|
|
1072
|
+
*
|
|
1073
|
+
* @example
|
|
1074
|
+
* // Define your server context
|
|
1075
|
+
* interface ServerContext {
|
|
1076
|
+
* auth: { userId: string };
|
|
1077
|
+
* requestId: string;
|
|
1078
|
+
* }
|
|
1079
|
+
*
|
|
1080
|
+
* // Create a typed action builder
|
|
1081
|
+
* const action = createActionBuilder<ServerContext>();
|
|
1082
|
+
*
|
|
1083
|
+
* // Use it - context type is automatically inferred!
|
|
1084
|
+
* const processOrder = action({
|
|
1085
|
+
* args: z.object({ orderId: z.string() }),
|
|
1086
|
+
* handler: async (ctx, { orderId }) => {
|
|
1087
|
+
* // ctx.db for full database access
|
|
1088
|
+
* const order = await ctx.db.query(async (db) => {
|
|
1089
|
+
* return db.query(OrdersSchema).find(orderId);
|
|
1090
|
+
* });
|
|
1091
|
+
* await ctx.db.mutation(async (db) => {
|
|
1092
|
+
* await db.update(OrdersSchema, orderId, { status: "processed" });
|
|
1093
|
+
* });
|
|
1094
|
+
* // ctx.context for server context
|
|
1095
|
+
* console.log(ctx.context.requestId);
|
|
1096
|
+
* return { success: true };
|
|
1097
|
+
* }
|
|
1098
|
+
* });
|
|
1099
|
+
*/
|
|
1100
|
+
declare function createActionBuilder<TContext = unknown>(): <TInput, TResult, const TInternal extends boolean = false>(config: ActionConfig<TInput, TResult, TContext> & {
|
|
1101
|
+
internal?: TInternal;
|
|
1102
|
+
}) => ActionProcedure<TInput, TResult, TContext, TInternal>;
|
|
1103
|
+
//#endregion
|
|
1104
|
+
//#region src/router/router.d.ts
|
|
1105
|
+
/**
|
|
1106
|
+
* A router maps procedure names (keys) to their definitions.
|
|
1107
|
+
* This is the type that's exported from your app and used by the client.
|
|
1108
|
+
*/
|
|
1109
|
+
type Router<TProcedures extends Record<string, AnyProcedure<TContext>>, TContext = unknown> = {
|
|
1110
|
+
_type: "router";
|
|
1111
|
+
procedures: TProcedures;
|
|
1112
|
+
contextName: string;
|
|
1113
|
+
};
|
|
1114
|
+
/**
|
|
1115
|
+
* Inferred AppRouter type from router() call.
|
|
1116
|
+
* Captures the full procedure map for client type inference.
|
|
1117
|
+
*/
|
|
1118
|
+
type AppRouter<TProcedures extends Record<string, AnyProcedure<TContext>> = Record<string, AnyProcedure>, TContext = unknown> = Router<TProcedures, TContext>;
|
|
1119
|
+
/** Get query procedures only from a router */
|
|
1120
|
+
type QueryProcedures<T extends Record<string, AnyProcedure>> = { [K in keyof T as T[K] extends {
|
|
1121
|
+
procedureType: "query";
|
|
1122
|
+
} ? K : never]: T[K] };
|
|
1123
|
+
/** Get mutation procedures only from a router */
|
|
1124
|
+
type MutationProcedures<T extends Record<string, AnyProcedure>> = { [K in keyof T as T[K] extends {
|
|
1125
|
+
procedureType: "mutation";
|
|
1126
|
+
} ? K : never]: T[K] };
|
|
1127
|
+
/** Get action procedures only from a router */
|
|
1128
|
+
type ActionProcedures<T extends Record<string, AnyProcedure>> = { [K in keyof T as T[K] extends {
|
|
1129
|
+
procedureType: "action";
|
|
1130
|
+
} ? K : never]: T[K] };
|
|
1131
|
+
/** Get public (non-internal) procedures - for client type safety */
|
|
1132
|
+
type PublicProcedures<T extends Record<string, AnyProcedure>> = Pick<T, { [K in keyof T]: T[K] extends {
|
|
1133
|
+
internal: true;
|
|
1134
|
+
} ? never : K }[keyof T]>;
|
|
1135
|
+
/** Extract procedure names from a router */
|
|
1136
|
+
type ProcedureNames<T extends Router<any>> = T extends Router<infer P> ? keyof P : never;
|
|
1137
|
+
type RouterConfig<T> = {
|
|
1138
|
+
procedures: T;
|
|
1139
|
+
contextName?: string;
|
|
1140
|
+
};
|
|
1141
|
+
/**
|
|
1142
|
+
* Create a router from procedure definitions.
|
|
1143
|
+
* Procedure names are inferred from the object keys.
|
|
1144
|
+
*
|
|
1145
|
+
* @example
|
|
1146
|
+
* const appRouter = router({
|
|
1147
|
+
* procedures: {
|
|
1148
|
+
* getUser,
|
|
1149
|
+
* createUser,
|
|
1150
|
+
* internalGetAll,
|
|
1151
|
+
* },
|
|
1152
|
+
* });
|
|
1153
|
+
*
|
|
1154
|
+
* export type AppRouter = typeof appRouter;
|
|
1155
|
+
*/
|
|
1156
|
+
declare function router<TProcedures extends Record<string, AnyProcedure<any>>, TContext = unknown>(config: RouterConfig<TProcedures>): Router<TProcedures, TContext>;
|
|
1157
|
+
interface RegisteredProcedure<TContext = unknown> {
|
|
1158
|
+
name: string;
|
|
1159
|
+
type: "query" | "mutation" | "action";
|
|
1160
|
+
internal: boolean;
|
|
1161
|
+
inputSchema: AnyProcedure<TContext>["inputSchema"];
|
|
1162
|
+
fn: AnyProcedure<TContext>["fn"];
|
|
1163
|
+
/** Only present for `type === "query"`. See `QueryIdentitySpec`. */
|
|
1164
|
+
queryIdentity?: false | string | ((serverCtx: TContext | undefined, input: unknown) => string | null | undefined);
|
|
1165
|
+
}
|
|
1166
|
+
declare function getContextRegistry(inContext: string): ContextRegistry;
|
|
1167
|
+
declare class ContextRegistry {
|
|
1168
|
+
procedureRegistry: Map<string, RegisteredProcedure<any>>;
|
|
1169
|
+
internalProcedureNames: Set<string>;
|
|
1170
|
+
registerProcedure<TContext>(name: string, proc: AnyProcedure<TContext>): void;
|
|
1171
|
+
/** Get a registered procedure by name (runtime lookup) */
|
|
1172
|
+
getProcedure<TContext = unknown>(name: string): RegisteredProcedure<TContext> | undefined;
|
|
1173
|
+
/** Get all registered procedure names */
|
|
1174
|
+
getProcedureNames(): string[];
|
|
1175
|
+
/** Get all registered procedures */
|
|
1176
|
+
getAllProcedures(): Map<string, RegisteredProcedure>;
|
|
1177
|
+
/** Clear the registry (for testing only) */
|
|
1178
|
+
clearRegistry(): void;
|
|
1179
|
+
markInternalProcedure(name: string): void;
|
|
1180
|
+
isInternalProcedure(name: string): boolean;
|
|
1181
|
+
clearInternalProcedures(): void;
|
|
1182
|
+
}
|
|
1183
|
+
//#endregion
|
|
1184
|
+
//#region src/client/ws_client_manager.d.ts
|
|
1185
|
+
declare class RPCError extends Error {
|
|
1186
|
+
code?: string;
|
|
1187
|
+
constructor(message: string, code?: string);
|
|
1188
|
+
}
|
|
1189
|
+
interface HeartbeatOptions {
|
|
1190
|
+
/**
|
|
1191
|
+
* Close + reconnect when no server message arrives for this long. The
|
|
1192
|
+
* server emits `{type:"ping"}` every ~15s of channel idle, so anything
|
|
1193
|
+
* larger than ~30s leaves comfortable headroom. Default 60_000.
|
|
1194
|
+
*/
|
|
1195
|
+
serverInactivityMs?: number;
|
|
1196
|
+
}
|
|
1197
|
+
interface SendThrottleOptions {
|
|
1198
|
+
/** Yield the event loop every N `call()` invocations. 0 disables. Default 100. */
|
|
1199
|
+
everyN?: number;
|
|
1200
|
+
/** Length of the yield in ms. Default 10. */
|
|
1201
|
+
delayMs?: number;
|
|
1202
|
+
}
|
|
1203
|
+
interface WSClientOptions {
|
|
1204
|
+
/** WebSocket URL (e.g. ws://localhost:3000/ws) */
|
|
1205
|
+
url: string;
|
|
1206
|
+
/** Auth token to send after connection */
|
|
1207
|
+
token?: () => Promise<string | undefined>;
|
|
1208
|
+
/** Optional: reconnection timeout in ms (default: 180000 = 3 minutes) */
|
|
1209
|
+
reconnectionTimeout?: number;
|
|
1210
|
+
/** Reconnection options */
|
|
1211
|
+
reconnect?: {
|
|
1212
|
+
/** Enable automatic reconnection (default: true) */enabled?: boolean; /** Max reconnection attempts (default: 5) */
|
|
1213
|
+
maxAttempts?: number; /** Delay between attempts in ms (default: 1000) */
|
|
1214
|
+
delay?: number; /** Exponential backoff multiplier (default: 1.5) */
|
|
1215
|
+
backoff?: number;
|
|
1216
|
+
};
|
|
1217
|
+
/** Server-inactivity watchdog. See {@link HeartbeatOptions.serverInactivityMs}. */
|
|
1218
|
+
heartbeat?: HeartbeatOptions;
|
|
1219
|
+
/**
|
|
1220
|
+
* Yields the event loop for `delayMs` ms after every `everyN`
|
|
1221
|
+
* `call()` invocations. Useful for keeping React renders / GC tasks
|
|
1222
|
+
* scheduled during long synchronous bursts of mutations/actions; the
|
|
1223
|
+
* heartbeat does not depend on this (the server drives it).
|
|
1224
|
+
* Default `{ everyN: 100, delayMs: 10 }`. Set `everyN: 0` to disable.
|
|
1225
|
+
*/
|
|
1226
|
+
throttle?: SendThrottleOptions;
|
|
1227
|
+
/** Called when connection is established */
|
|
1228
|
+
onConnect?: () => void;
|
|
1229
|
+
/** Called when connection is lost */
|
|
1230
|
+
onDisconnect?: () => void;
|
|
1231
|
+
/** Called on connection error */
|
|
1232
|
+
onError?: (error: Error) => void;
|
|
1233
|
+
}
|
|
1234
|
+
/**
|
|
1235
|
+
* Public state of the client, surfaced to consumers (React provider, etc.).
|
|
1236
|
+
* - "connecting" — initial connect or reconnect handshake in flight
|
|
1237
|
+
* - "authenticating" — connected, waiting for auth result
|
|
1238
|
+
* - "ready" — connected and auth resolved (authenticated, anonymous, or
|
|
1239
|
+
* explicitly failed — i.e. ready to send calls)
|
|
1240
|
+
* - "disconnected" — currently offline (may auto-retry)
|
|
1241
|
+
*/
|
|
1242
|
+
type ClientPublicState = "disconnected" | "connecting" | "authenticating" | "ready";
|
|
1243
|
+
declare class WsClientManager {
|
|
1244
|
+
private ws;
|
|
1245
|
+
private options;
|
|
1246
|
+
private lastSuccessfulConnectionTime;
|
|
1247
|
+
private reconnectionTimeout;
|
|
1248
|
+
private requestId;
|
|
1249
|
+
private pendingRequests;
|
|
1250
|
+
/**
|
|
1251
|
+
* Single source of truth for live subscriptions.
|
|
1252
|
+
*
|
|
1253
|
+
* Keying:
|
|
1254
|
+
* - In-flight subscribe (no subId yet): `_pending:<requestId>`.
|
|
1255
|
+
* - Established: the server-returned canonical `subId`.
|
|
1256
|
+
*
|
|
1257
|
+
* Routing `sub:update` / `sub:gone` is O(1) (`get(subId)`). Subscribe-time
|
|
1258
|
+
* dedup scans `values()` for a matching `localKey` (O(N)), which is cheap
|
|
1259
|
+
* since subscribes happen on component mounts, not in the hot path.
|
|
1260
|
+
*/
|
|
1261
|
+
private subscriptions;
|
|
1262
|
+
private queuedCalls;
|
|
1263
|
+
private reconnectAttempts;
|
|
1264
|
+
private reconnectTimer;
|
|
1265
|
+
private connectionState;
|
|
1266
|
+
private authState;
|
|
1267
|
+
/**
|
|
1268
|
+
* Authenticated user id from `auth:success`. Distinct from `queryIdentity`
|
|
1269
|
+
* (server-side cache/sub segmentation key); this is just "who am I logged
|
|
1270
|
+
* in as" for app display purposes. Null while unauthenticated / anonymous.
|
|
1271
|
+
*/
|
|
1272
|
+
private authUserId;
|
|
1273
|
+
private explicitlyClosed;
|
|
1274
|
+
private stateListeners;
|
|
1275
|
+
private lastPublicState;
|
|
1276
|
+
private serverInactivityMs;
|
|
1277
|
+
private lastServerMessageAt;
|
|
1278
|
+
private inactivityTimer;
|
|
1279
|
+
private pendingConnectResolve;
|
|
1280
|
+
private pendingConnectReject;
|
|
1281
|
+
private throttleEveryN;
|
|
1282
|
+
private throttleDelayMs;
|
|
1283
|
+
private throttleCounter;
|
|
1284
|
+
private throttling;
|
|
1285
|
+
private visibilityListener;
|
|
1286
|
+
private onlineListener;
|
|
1287
|
+
constructor(options: WSClientOptions);
|
|
1288
|
+
/**
|
|
1289
|
+
* Subscribe to client state transitions. Returns an unsubscribe fn.
|
|
1290
|
+
* The listener is called immediately with the current state.
|
|
1291
|
+
*/
|
|
1292
|
+
onState(listener: (s: ClientPublicState) => void): () => void;
|
|
1293
|
+
/** Current public state. */
|
|
1294
|
+
getPublicState(): ClientPublicState;
|
|
1295
|
+
/**
|
|
1296
|
+
* Connect to the WebSocket server.
|
|
1297
|
+
* Returns a promise that resolves when connected and authenticated.
|
|
1298
|
+
*/
|
|
1299
|
+
connect(): Promise<void>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Disconnect from the server.
|
|
1302
|
+
*/
|
|
1303
|
+
disconnect(): void;
|
|
1304
|
+
/**
|
|
1305
|
+
* Check if connected and authenticated.
|
|
1306
|
+
*/
|
|
1307
|
+
isReady(): boolean;
|
|
1308
|
+
/**
|
|
1309
|
+
* Check if authenticated.
|
|
1310
|
+
*/
|
|
1311
|
+
isAuthenticated(): boolean;
|
|
1312
|
+
/**
|
|
1313
|
+
* Check if anonymouse.
|
|
1314
|
+
*/
|
|
1315
|
+
isAnonymouse(): boolean;
|
|
1316
|
+
/**
|
|
1317
|
+
* The authenticated user's id (from `auth:success`), or null when
|
|
1318
|
+
* unauthenticated / anonymous. Useful for "Logged in as …" display.
|
|
1319
|
+
*
|
|
1320
|
+
* Not to be confused with server-side `queryIdentity`, which is the
|
|
1321
|
+
* cache/subscription segmentation key (resolved entirely on the server).
|
|
1322
|
+
*/
|
|
1323
|
+
getAuthUserId(): string | null;
|
|
1324
|
+
/**
|
|
1325
|
+
* Call a procedure (query, mutation, or action).
|
|
1326
|
+
*
|
|
1327
|
+
* If the client is not ready (disconnected or still authenticating), the
|
|
1328
|
+
* call is FIFO-queued and dispatched on the next ready state. The promise
|
|
1329
|
+
* still resolves with the eventual server response.
|
|
1330
|
+
*
|
|
1331
|
+
* Pass `onSend` to be notified when the call actually leaves the queue
|
|
1332
|
+
* (used by `useMutation` to flip `state` from "queued" → "loading").
|
|
1333
|
+
*/
|
|
1334
|
+
call(procedure: string, input: unknown, options?: {
|
|
1335
|
+
onSend?: () => void;
|
|
1336
|
+
}): Promise<unknown>;
|
|
1337
|
+
/**
|
|
1338
|
+
* Throttle drain loop. Each iteration: sleep `throttleDelayMs`, then
|
|
1339
|
+
* dispatch up to `throttleEveryN` queued items. Exits as soon as the
|
|
1340
|
+
* queue drains inside a single batch (burst over, back to direct
|
|
1341
|
+
* dispatch on the next `call()`) or the connection goes away
|
|
1342
|
+
* (reconnect path will restart us via `flushQueuedCalls`).
|
|
1343
|
+
*/
|
|
1344
|
+
private runThrottleLoop;
|
|
1345
|
+
/**
|
|
1346
|
+
* Issue the call against an established connection. Caller must ensure
|
|
1347
|
+
* `isReady()` before invoking.
|
|
1348
|
+
*/
|
|
1349
|
+
private dispatchCall;
|
|
1350
|
+
/**
|
|
1351
|
+
* Flush queued calls in FIFO order. Called once `isReady()` becomes
|
|
1352
|
+
* true. With the throttle enabled, dispatch the first batch
|
|
1353
|
+
* synchronously then hand off to the drain loop so a large
|
|
1354
|
+
* post-reconnect flush respects backpressure instead of dumping 10k
|
|
1355
|
+
* frames in one tick.
|
|
1356
|
+
*/
|
|
1357
|
+
private flushQueuedCalls;
|
|
1358
|
+
/**
|
|
1359
|
+
* Re-send `subscribe` for every existing subscription. The subId for each
|
|
1360
|
+
* may legitimately change (e.g. `queryIdentity` was a function of user
|
|
1361
|
+
* identity and the user changed during the disconnect), so we re-key the
|
|
1362
|
+
* unified `subscriptions` Map: snapshot every record, drop them from the
|
|
1363
|
+
* Map, then reinsert under a fresh `_pending:<reqId>` key. Each pending
|
|
1364
|
+
* request's `resolve` rekeys the parked record under the new server-issued
|
|
1365
|
+
* subId so subsequent `sub:update` frames route to the existing
|
|
1366
|
+
* `onUpdate` callback (which the React handle is still holding).
|
|
1367
|
+
*/
|
|
1368
|
+
private resubscribeAll;
|
|
1369
|
+
/**
|
|
1370
|
+
* Subscribe to a live query.
|
|
1371
|
+
*
|
|
1372
|
+
* The client does not compute the subId locally — it sends the
|
|
1373
|
+
* (procedure, input) pair and receives the canonical subId on the
|
|
1374
|
+
* subscribe response. This lets the server's per-procedure
|
|
1375
|
+
* `queryIdentity` override be authoritative without forcing the client
|
|
1376
|
+
* to mirror any of the resolution logic.
|
|
1377
|
+
*
|
|
1378
|
+
* Returns the server-assigned subId and an unsubscribe function.
|
|
1379
|
+
*/
|
|
1380
|
+
subscribe(procedure: string, input: unknown, serializedInput: string, onUpdate: (data: unknown) => void, onGone?: (reason: string | undefined) => void): Promise<{
|
|
1381
|
+
subId: string;
|
|
1382
|
+
unsubscribe: () => void;
|
|
1383
|
+
}>;
|
|
1384
|
+
private findSubByLocalKey;
|
|
1385
|
+
/** Resolve every joiner waiting on this Subscription with the canonical subId. */
|
|
1386
|
+
private resolveJoiners;
|
|
1387
|
+
/** Reject every joiner waiting on this Subscription with the given error. */
|
|
1388
|
+
private rejectJoiners;
|
|
1389
|
+
private unsubscribeByLocalKey;
|
|
1390
|
+
private handleMessage;
|
|
1391
|
+
/**
|
|
1392
|
+
* Called once the client transitions to a "ready" state on a fresh
|
|
1393
|
+
* connection. Replays live-query subscriptions and flushes any queued
|
|
1394
|
+
* calls in FIFO order.
|
|
1395
|
+
*/
|
|
1396
|
+
private afterReady;
|
|
1397
|
+
private handleResponse;
|
|
1398
|
+
private handleSubscriptionUpdate;
|
|
1399
|
+
/**
|
|
1400
|
+
* Handles a `sub:gone` message: the server no longer tracks this
|
|
1401
|
+
* subscription (e.g. it was fully unregistered while we were disconnected
|
|
1402
|
+
* from the sub-manager). Notify the handle and drop the local entry so a
|
|
1403
|
+
* re-subscribe is required to receive further updates.
|
|
1404
|
+
*/
|
|
1405
|
+
private handleSubscriptionGone;
|
|
1406
|
+
private handleClose;
|
|
1407
|
+
private handleError;
|
|
1408
|
+
private startInactivityWatchdog;
|
|
1409
|
+
private stopInactivityWatchdog;
|
|
1410
|
+
/**
|
|
1411
|
+
* Close the current WebSocket and schedule a reconnect via `handleClose`.
|
|
1412
|
+
*
|
|
1413
|
+
* Atomically swaps the old socket's event handlers to no-ops BEFORE
|
|
1414
|
+
* `close()` so a frame in flight at the moment of close cannot fire
|
|
1415
|
+
* `handleMessage` into a half-cleaned state — that was the source of
|
|
1416
|
+
* the "browser says socket is alive but client says disconnected" race.
|
|
1417
|
+
*/
|
|
1418
|
+
private closeAndReconnect;
|
|
1419
|
+
private installEnvironmentListeners;
|
|
1420
|
+
private removeEnvironmentListeners;
|
|
1421
|
+
private scheduleReconnect;
|
|
1422
|
+
private computePublicState;
|
|
1423
|
+
private emitState;
|
|
1424
|
+
private ensureConnected;
|
|
1425
|
+
private send;
|
|
1426
|
+
private cleanup;
|
|
1427
|
+
private generateRequestId;
|
|
1428
|
+
}
|
|
1429
|
+
//#endregion
|
|
1430
|
+
//#region src/db/types_client_rpc.d.ts
|
|
1431
|
+
interface ErrorMessage {
|
|
1432
|
+
type: "error";
|
|
1433
|
+
id?: string;
|
|
1434
|
+
error: string;
|
|
1435
|
+
code?: string;
|
|
1436
|
+
}
|
|
1437
|
+
declare const AuthMessageSchema: z.ZodObject<{
|
|
1438
|
+
type: z.ZodLiteral<"auth">;
|
|
1439
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
1440
|
+
}, z.core.$strip>;
|
|
1441
|
+
declare const CallMessageSchema: z.ZodObject<{
|
|
1442
|
+
type: z.ZodLiteral<"call">;
|
|
1443
|
+
id: z.ZodString;
|
|
1444
|
+
procedure: z.ZodString;
|
|
1445
|
+
input: z.ZodUnknown;
|
|
1446
|
+
}, z.core.$strip>;
|
|
1447
|
+
declare const SubscribeMessageSchema: z.ZodObject<{
|
|
1448
|
+
type: z.ZodLiteral<"subscribe">;
|
|
1449
|
+
id: z.ZodString;
|
|
1450
|
+
procedure: z.ZodString;
|
|
1451
|
+
input: z.ZodUnknown;
|
|
1452
|
+
}, z.core.$strip>;
|
|
1453
|
+
declare const UnsubscribeMessageSchema: z.ZodObject<{
|
|
1454
|
+
type: z.ZodLiteral<"unsubscribe">;
|
|
1455
|
+
subId: z.ZodString;
|
|
1456
|
+
}, z.core.$strip>;
|
|
1457
|
+
declare const ClientMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
1458
|
+
type: z.ZodLiteral<"auth">;
|
|
1459
|
+
data: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodAny>>;
|
|
1460
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1461
|
+
type: z.ZodLiteral<"call">;
|
|
1462
|
+
id: z.ZodString;
|
|
1463
|
+
procedure: z.ZodString;
|
|
1464
|
+
input: z.ZodUnknown;
|
|
1465
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1466
|
+
type: z.ZodLiteral<"subscribe">;
|
|
1467
|
+
id: z.ZodString;
|
|
1468
|
+
procedure: z.ZodString;
|
|
1469
|
+
input: z.ZodUnknown;
|
|
1470
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1471
|
+
type: z.ZodLiteral<"unsubscribe">;
|
|
1472
|
+
subId: z.ZodString;
|
|
1473
|
+
}, z.core.$strip>]>;
|
|
1474
|
+
type AuthMessage = z.infer<typeof AuthMessageSchema>;
|
|
1475
|
+
type CallMessage = z.infer<typeof CallMessageSchema>;
|
|
1476
|
+
type SubscribeMessage = z.infer<typeof SubscribeMessageSchema>;
|
|
1477
|
+
type UnsubscribeMessage = z.infer<typeof UnsubscribeMessageSchema>;
|
|
1478
|
+
type ClientMessage = z.infer<typeof ClientMessageSchema>;
|
|
1479
|
+
declare const ConnectedMessageSchema: z.ZodObject<{
|
|
1480
|
+
type: z.ZodLiteral<"connected">;
|
|
1481
|
+
sessionId: z.ZodString;
|
|
1482
|
+
}, z.core.$strip>;
|
|
1483
|
+
declare const AuthSuccessMessageSchema: z.ZodObject<{
|
|
1484
|
+
type: z.ZodLiteral<"auth:success">;
|
|
1485
|
+
userId: z.ZodString;
|
|
1486
|
+
extra: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
|
|
1487
|
+
}, z.core.$strip>;
|
|
1488
|
+
declare const AuthFailedMessageSchema: z.ZodObject<{
|
|
1489
|
+
type: z.ZodLiteral<"auth:failed">;
|
|
1490
|
+
message: z.ZodString;
|
|
1491
|
+
extra: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1492
|
+
}, z.core.$strip>;
|
|
1493
|
+
declare const ResponseMessageSchema: z.ZodObject<{
|
|
1494
|
+
type: z.ZodLiteral<"response">;
|
|
1495
|
+
id: z.ZodString;
|
|
1496
|
+
success: z.ZodBoolean;
|
|
1497
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
1498
|
+
error: z.ZodOptional<z.ZodString>;
|
|
1499
|
+
code: z.ZodOptional<z.ZodString>;
|
|
1500
|
+
subId: z.ZodOptional<z.ZodString>;
|
|
1501
|
+
}, z.core.$strip>;
|
|
1502
|
+
declare const SubscriptionUpdateMessageSchema: z.ZodObject<{
|
|
1503
|
+
type: z.ZodLiteral<"sub:update">;
|
|
1504
|
+
subId: z.ZodString;
|
|
1505
|
+
data: z.ZodUnknown;
|
|
1506
|
+
dataHash: z.ZodOptional<z.ZodString>;
|
|
1507
|
+
}, z.core.$strip>;
|
|
1508
|
+
/**
|
|
1509
|
+
* Notifies a client that a subscription is no longer tracked on the server
|
|
1510
|
+
* and will not receive further updates. Sent when, during a sub-manager
|
|
1511
|
+
* recovery cycle, the registration record could not be found (e.g. another
|
|
1512
|
+
* app-server instance fully unregistered the sub while we were disconnected).
|
|
1513
|
+
* The client may choose to re-subscribe or surface the state to the user.
|
|
1514
|
+
*/
|
|
1515
|
+
declare const SubscriptionGoneMessageSchema: z.ZodObject<{
|
|
1516
|
+
type: z.ZodLiteral<"sub:gone">;
|
|
1517
|
+
subId: z.ZodString;
|
|
1518
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
1519
|
+
}, z.core.$strip>;
|
|
1520
|
+
/**
|
|
1521
|
+
* Server-driven liveness signal. Sent when the channel has been idle for
|
|
1522
|
+
* the configured app-ping interval (default 15s) and again after every
|
|
1523
|
+
* outbound message. Pure no-op for the client: receiving any message
|
|
1524
|
+
* (including this one) resets the client's inactivity watchdog. The client
|
|
1525
|
+
* does NOT reply.
|
|
1526
|
+
*/
|
|
1527
|
+
declare const ServerPingMessageSchema: z.ZodObject<{
|
|
1528
|
+
type: z.ZodLiteral<"ping">;
|
|
1529
|
+
}, z.core.$strip>;
|
|
1530
|
+
declare const ServerMessageSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
1531
|
+
type: z.ZodLiteral<"connected">;
|
|
1532
|
+
sessionId: z.ZodString;
|
|
1533
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1534
|
+
type: z.ZodLiteral<"auth:success">;
|
|
1535
|
+
userId: z.ZodString;
|
|
1536
|
+
extra: z.ZodOptional<z.ZodObject<{}, z.core.$strip>>;
|
|
1537
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1538
|
+
type: z.ZodLiteral<"auth:failed">;
|
|
1539
|
+
message: z.ZodString;
|
|
1540
|
+
extra: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
1541
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1542
|
+
type: z.ZodLiteral<"response">;
|
|
1543
|
+
id: z.ZodString;
|
|
1544
|
+
success: z.ZodBoolean;
|
|
1545
|
+
data: z.ZodOptional<z.ZodUnknown>;
|
|
1546
|
+
error: z.ZodOptional<z.ZodString>;
|
|
1547
|
+
code: z.ZodOptional<z.ZodString>;
|
|
1548
|
+
subId: z.ZodOptional<z.ZodString>;
|
|
1549
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1550
|
+
type: z.ZodLiteral<"sub:update">;
|
|
1551
|
+
subId: z.ZodString;
|
|
1552
|
+
data: z.ZodUnknown;
|
|
1553
|
+
dataHash: z.ZodOptional<z.ZodString>;
|
|
1554
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1555
|
+
type: z.ZodLiteral<"sub:gone">;
|
|
1556
|
+
subId: z.ZodString;
|
|
1557
|
+
reason: z.ZodOptional<z.ZodString>;
|
|
1558
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
1559
|
+
type: z.ZodLiteral<"ping">;
|
|
1560
|
+
}, z.core.$strip>]>;
|
|
1561
|
+
type ConnectedMessage = z.infer<typeof ConnectedMessageSchema>;
|
|
1562
|
+
type AuthSuccessMessage = z.infer<typeof AuthSuccessMessageSchema>;
|
|
1563
|
+
type AuthFailedMessage = z.infer<typeof AuthFailedMessageSchema>;
|
|
1564
|
+
type ResponseMessage = z.infer<typeof ResponseMessageSchema>;
|
|
1565
|
+
type SubscriptionUpdateMessage = z.infer<typeof SubscriptionUpdateMessageSchema>;
|
|
1566
|
+
type SubscriptionGoneMessage = z.infer<typeof SubscriptionGoneMessageSchema>;
|
|
1567
|
+
type ServerPingMessage = z.infer<typeof ServerPingMessageSchema>;
|
|
1568
|
+
type ServerMessage = z.infer<typeof ServerMessageSchema>;
|
|
1569
|
+
declare class AuthenticationError extends Error {
|
|
1570
|
+
extra: Record<string, unknown>;
|
|
1571
|
+
constructor(message: string, extra?: Record<string, unknown>);
|
|
1572
|
+
}
|
|
1573
|
+
/**
|
|
1574
|
+
* Helper type to check if a procedure is internal.
|
|
1575
|
+
*/
|
|
1576
|
+
type IsInternal<T> = T extends {
|
|
1577
|
+
internal: infer I;
|
|
1578
|
+
} ? (I extends true ? true : false) : false;
|
|
1579
|
+
interface Context {
|
|
1580
|
+
requestId: string;
|
|
1581
|
+
/** Authenticated user info */
|
|
1582
|
+
user: {
|
|
1583
|
+
userId: string;
|
|
1584
|
+
};
|
|
1585
|
+
}
|
|
1586
|
+
//#endregion
|
|
1587
|
+
//#region src/client/client.d.ts
|
|
1588
|
+
interface ClientOptions {
|
|
1589
|
+
/** WebSocket URL (e.g. ws://localhost:3000/ws) */
|
|
1590
|
+
url: string;
|
|
1591
|
+
/** Auth Info callback */
|
|
1592
|
+
token?: () => Promise<string>;
|
|
1593
|
+
/** Optional: reconnection timeout in ms (default: 180000 = 3 minutes) */
|
|
1594
|
+
reconnectionTimeout?: number;
|
|
1595
|
+
/** Reconnection options */
|
|
1596
|
+
reconnect?: WSClientOptions["reconnect"];
|
|
1597
|
+
/**
|
|
1598
|
+
* Inactivity watchdog. The client never sends a ping itself; the server
|
|
1599
|
+
* emits `{type:"ping"}` while idle and we close+reconnect if no inbound
|
|
1600
|
+
* message arrives within `serverInactivityMs` (default 60s).
|
|
1601
|
+
*/
|
|
1602
|
+
heartbeat?: WSClientOptions["heartbeat"];
|
|
1603
|
+
/**
|
|
1604
|
+
* Yields the event loop for `delayMs` after every `everyN` `call()`
|
|
1605
|
+
* invocations. Useful for keeping React renders / GC tasks scheduled
|
|
1606
|
+
* during long synchronous bursts; not load-bearing for the heartbeat.
|
|
1607
|
+
* Default `{ everyN: 100, delayMs: 10 }`. Set `everyN: 0` to disable.
|
|
1608
|
+
*/
|
|
1609
|
+
throttle?: WSClientOptions["throttle"];
|
|
1610
|
+
onConnect?: () => void;
|
|
1611
|
+
onDisConnect?: () => void;
|
|
1612
|
+
}
|
|
1613
|
+
/**
|
|
1614
|
+
* Public state of a live query subscription, exposed via `getState()` and
|
|
1615
|
+
* `onState()` on the handle so React (or any UI) can render a consistent
|
|
1616
|
+
* snapshot via `useSyncExternalStore`.
|
|
1617
|
+
*
|
|
1618
|
+
* - "connecting" — initial subscribe in flight
|
|
1619
|
+
* - "success" — subscribed, last server data is in `data`
|
|
1620
|
+
* - "stale" — was successful, transport dropped; keeping last `data`
|
|
1621
|
+
* until the resubscribe completes
|
|
1622
|
+
* - "loading" — `refetch()` triggered an explicit re-subscribe
|
|
1623
|
+
* - "error" — subscribe failed or server sent `sub:gone`
|
|
1624
|
+
*/
|
|
1625
|
+
type LiveQueryStatus = "connecting" | "success" | "stale" | "loading" | "error";
|
|
1626
|
+
interface LiveQueryState<T> {
|
|
1627
|
+
data: T | undefined;
|
|
1628
|
+
status: LiveQueryStatus;
|
|
1629
|
+
error: Error | null;
|
|
1630
|
+
}
|
|
1631
|
+
interface LiveQueryHandle<T> {
|
|
1632
|
+
/** Get current cached data (legacy convenience getter). */
|
|
1633
|
+
get(): T | undefined;
|
|
1634
|
+
/** Snapshot of `{ data, status, error }`. Stable between updates. */
|
|
1635
|
+
getState(): LiveQueryState<T>;
|
|
1636
|
+
/**
|
|
1637
|
+
* Listen for state changes (data, status or error). Returns an
|
|
1638
|
+
* unsubscribe function that removes only this listener — the underlying
|
|
1639
|
+
* server subscription stays alive as long as any listener is attached.
|
|
1640
|
+
*
|
|
1641
|
+
* Suitable for `useSyncExternalStore`.
|
|
1642
|
+
*/
|
|
1643
|
+
onState(listener: () => void): () => void;
|
|
1644
|
+
/** Listen for data-only changes. Returns listener-removal fn. */
|
|
1645
|
+
onData(callback: (data: T) => void): () => void;
|
|
1646
|
+
/** Force a re-subscribe round-trip. */
|
|
1647
|
+
refetch(): void;
|
|
1648
|
+
/** Unsubscribe from the server (drops listeners too). */
|
|
1649
|
+
unsubscribe(): void;
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* Create a fully typed RPC client with WebSocket transport.
|
|
1653
|
+
*/
|
|
1654
|
+
declare function createClient<AppRouter extends Router<Record<string, AnyProcedure<TContext>>, TContext>, TContext = unknown, TProcedures extends Record<string, AnyProcedure<TContext>> = AppRouter["procedures"]>(options: ClientOptions): ClientFromProcedures<TProcedures, TContext> & WSClientMethods;
|
|
1655
|
+
/**
|
|
1656
|
+
* WebSocket client methods.
|
|
1657
|
+
*/
|
|
1658
|
+
interface WSClientMethods {
|
|
1659
|
+
/** Connect to the WebSocket server */
|
|
1660
|
+
connect(): Promise<void>;
|
|
1661
|
+
/** Disconnect from the server */
|
|
1662
|
+
disconnect(): void;
|
|
1663
|
+
/** Check if connected and authenticated */
|
|
1664
|
+
isReady(): boolean;
|
|
1665
|
+
/** Check if authenticated */
|
|
1666
|
+
isAuthenticated(): boolean;
|
|
1667
|
+
/** Check if anonymouse */
|
|
1668
|
+
isAnonymouse(): boolean;
|
|
1669
|
+
/**
|
|
1670
|
+
* The authenticated user id reported by the server on `auth:success`, or
|
|
1671
|
+
* null when anonymous/unauthenticated. This is the auth-tier identity,
|
|
1672
|
+
* NOT the server-side `queryIdentity` (which is the cache/subscription
|
|
1673
|
+
* segmentation key and is not exposed to the client).
|
|
1674
|
+
*/
|
|
1675
|
+
getAuthUserId(): string | null;
|
|
1676
|
+
/** Subscribe to client connection state transitions. Returns unsubscribe fn. */
|
|
1677
|
+
onState(listener: (s: ClientPublicState) => void): () => void;
|
|
1678
|
+
/** Snapshot of the current public state. */
|
|
1679
|
+
getPublicState(): ClientPublicState;
|
|
1680
|
+
}
|
|
1681
|
+
/**
|
|
1682
|
+
* Client type from procedures.
|
|
1683
|
+
* Filters internal procedures and creates appropriate methods.
|
|
1684
|
+
* Query procedures get an additional liveQuery() method for real-time subscriptions.
|
|
1685
|
+
*/
|
|
1686
|
+
type ClientFromProcedures<TProcedures extends Record<string, AnyProcedure<TContext>>, TContext = unknown> = { [K in keyof TProcedures as IsInternal<TProcedures[K]> extends true ? never : K]: TProcedures[K] extends {
|
|
1687
|
+
procedureType: "query";
|
|
1688
|
+
} ? {
|
|
1689
|
+
query: (input: InputOf<TProcedures[K]>) => Promise<OutputOf<TProcedures[K]>>;
|
|
1690
|
+
liveQuery: (input: InputOf<TProcedures[K]>) => LiveQueryHandle<OutputOf<TProcedures[K]>>;
|
|
1691
|
+
} : TProcedures[K] extends {
|
|
1692
|
+
procedureType: "mutation";
|
|
1693
|
+
} ? {
|
|
1694
|
+
mutate: (input: InputOf<TProcedures[K]>, opts?: CallOptions) => Promise<OutputOf<TProcedures[K]>>;
|
|
1695
|
+
} : TProcedures[K] extends {
|
|
1696
|
+
procedureType: "action";
|
|
1697
|
+
} ? {
|
|
1698
|
+
action: (input: InputOf<TProcedures[K]>, opts?: CallOptions) => Promise<OutputOf<TProcedures[K]>>;
|
|
1699
|
+
} : never };
|
|
1700
|
+
/**
|
|
1701
|
+
* Optional call options forwarded to the transport layer.
|
|
1702
|
+
*/
|
|
1703
|
+
interface CallOptions {
|
|
1704
|
+
/**
|
|
1705
|
+
* Fired the first time the request leaves the queue and is actually
|
|
1706
|
+
* sent on the wire. If the call was already sent immediately (client
|
|
1707
|
+
* was ready at call time), this is invoked synchronously.
|
|
1708
|
+
*
|
|
1709
|
+
* Used by `useMutation` to flip `state` from "queued" → "loading".
|
|
1710
|
+
*/
|
|
1711
|
+
onSend?: () => void;
|
|
1712
|
+
}
|
|
1713
|
+
//#endregion
|
|
1714
|
+
//#region src/client/caller_client.d.ts
|
|
1715
|
+
interface CallerOptions<TContext = unknown> {
|
|
1716
|
+
isInternal?: boolean;
|
|
1717
|
+
inContext: string;
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Create a server-side caller that bypasses HTTP/WebSocket.
|
|
1721
|
+
*
|
|
1722
|
+
* For in-memory calls, input validation is skipped (data is already a JS object).
|
|
1723
|
+
* Query procedures also get a liveQuery() method for server-side use.
|
|
1724
|
+
*/
|
|
1725
|
+
declare function createCaller<AppRouter extends Router<Record<string, AnyProcedure<TContext>>, TContext>, TContext = unknown, TProcedures extends Record<string, AnyProcedure<TContext>> = AppRouter["procedures"]>(options: CallerOptions<any>): CallerFromProcedures<TProcedures, TContext>;
|
|
1726
|
+
/**
|
|
1727
|
+
* Caller type from procedures (includes internal procedures).
|
|
1728
|
+
* Query procedures also have liveQuery() for server-side use.
|
|
1729
|
+
*/
|
|
1730
|
+
type CallerFromProcedures<TProcedures extends Record<string, AnyProcedure<TContext>>, TContext = unknown> = { [K in keyof TProcedures]: TProcedures[K] extends {
|
|
1731
|
+
procedureType: "query";
|
|
1732
|
+
} ? {
|
|
1733
|
+
query: (input: InputOf<TProcedures[K]>, serverCtx: TContext) => Promise<OutputOf<TProcedures[K]>>;
|
|
1734
|
+
liveQuery: (input: InputOf<TProcedures[K]>, serverCtx: TContext) => Promise<LiveResult<OutputOf<TProcedures[K]>>>;
|
|
1735
|
+
} : TProcedures[K] extends {
|
|
1736
|
+
procedureType: "mutation";
|
|
1737
|
+
} ? {
|
|
1738
|
+
mutate: (input: InputOf<TProcedures[K]>, serverCtx: TContext) => Promise<OutputOf<TProcedures[K]>>;
|
|
1739
|
+
} : TProcedures[K] extends {
|
|
1740
|
+
procedureType: "action";
|
|
1741
|
+
} ? {
|
|
1742
|
+
action: (input: InputOf<TProcedures[K]>, serverCtx: TContext) => Promise<OutputOf<TProcedures[K]>>;
|
|
1743
|
+
} : never } & {
|
|
1744
|
+
init: (config: {
|
|
1745
|
+
db: SupaliveDb;
|
|
1746
|
+
}) => Promise<void>;
|
|
1747
|
+
};
|
|
1748
|
+
/**
|
|
1749
|
+
* Caller type from router.
|
|
1750
|
+
*/
|
|
1751
|
+
type CallerFromRouter<TRouter extends Router<any, any>> = CallerFromProcedures<TRouter["procedures"]>;
|
|
1752
|
+
//#endregion
|
|
1753
|
+
export { PublicProcedures as $, CompareOperator as $n, DefineSchemaConfig as $t, ResponseMessageSchema as A, CacheLayer as An, RetryConfig as Ar, ResultOf as At, SubscriptionUpdateMessageSchema as B, UnregisterSubscriptionResult as Bn, QueryBuilder as Bt, ClientMessageSchema as C, DbType as Cn, RawPointReadSchema as Cr, createQueryBuilder as Ct, ErrorMessage as D, RawClient as Dn, RawReadEntrySchema as Dr, DefsToMap as Dt, Context as E, PreparedQueries as En, RawReadEntry as Er, AnyQueryDef as Et, SubscribeMessage as F, RegisterSubscriptionParams as Fn, bytesFromJson as Fr, TxContext as Ft, RPCError as G, UpdateSubscriptionReadSetResult as Gn, matchesPredicate as Gt, UnsubscribeMessageSchema as H, UnregisterSubscriptionsResult as Hn, jsonContains as Ht, SubscribeMessageSchema as I, RegisterSubscriptionParamsSchema as In, normalizeIdToBytes as Ir, IdAndCommitTs as It, ActionProcedures as J, BigIntSchema as Jn, ComputedCodec as Jt, WSClientOptions as K, AndPredicate as Kn, ActionArgs as Kt, SubscriptionGoneMessage as L, RegisterSubscriptionResult as Ln, normalizeToBytes as Lr, JsonContainsOptions as Lt, ServerMessageSchema as M, InvalidateWritesetParams as Mn, WriteEntrySchema as Mr, defineQuery as Mt, ServerPingMessage as N, InvalidateWritesetParamsSchema as Nn, WriteOp as Nr, DbReader as Nt, IsInternal as O, SqlBuilder as On, ReadEntry as Or, ParamsOf as Ot, ServerPingMessageSchema as P, InvalidateWritesetResult as Pn, WriteOpSchema as Pr, DbWriter as Pt, ProcedureNames as Q, CommitTs as Qn, DeclarativeIndex as Qt, SubscriptionGoneMessageSchema as R, UnregisterSubscriptionParams as Rn, JsonHasKeyMultiOptions as Rt, ClientMessage as S, DbQueryResult as Sn, RawPointRead as Sr, createMutationBuilder as St, ConnectedMessageSchema as T, PooledClient as Tn, RawRangeReadSchema as Tr, sleep as Tt, ClientPublicState as U, UpdateSubscriptionReadSetParams as Un, jsonPathExists as Ut, UnsubscribeMessage as V, UnregisterSubscriptionsParams as Vn, buildPredicateSql as Vt, HeartbeatOptions as W, UpdateSubscriptionReadSetParamsSchema as Wn, jsonPathExtract as Wt, ContextRegistry as X, CachedPgMetadataSchema as Xn, ComputedField as Xt, AppRouter as Y, CachedPgMetadata as Yn, ComputedDataType as Yt, MutationProcedures as Z, CommitLogEntry as Zn, ComputedFieldConfig as Zt, AuthSuccessMessage as _, schemaRegistry as _n, QueryCacheMetadata as _r, QueryCtx as _t, CallOptions as a, OverrideField as an, MutationResult as ar, ActionConfig as at, CallMessage as b, trackSchema as bn, RangeRead as br, TypeOf as bt, LiveQueryHandle as c, ReturnLiveQuery as cn, OccConflictError as cr, ActionProcedure as ct, WSClientMethods as d, SchemaColumnMapping as dn, PointRead as dr, MutationConfig as dt, IndexDefinition as en, CompareOperatorSchema as er, QueryProcedures as et, createClient as f, SchemaColumnsOptions as fn, PointReadSchema as fr, MutationCtx as ft, AuthMessageSchema as g, defineSchema as gn, QueryCacheEntrySchema as gr, QueryConfig as gt, AuthMessage as h, defineComputedField as hn, QueryCacheEntry as hr, OutputOf as ht, createCaller as i, MutationArgs as in, LiveResult as ir, router as it, ServerMessage as j, AffectedSubscription as jn, WriteEntry as jr, _resetGlobalDefs as jt, ResponseMessage as k, TxDatabase as kn, ReadEntrySchema as kr, QueryDefinition as kt, LiveQueryState as l, ReturnQuery as ln, OrPredicate as lr, AnyProcedure as lt, AuthFailedMessageSchema as m, StoredSchemaColumnsOptions as mn, PredicateSchema as mr, MutationProcedure as mt, CallerFromRouter as n, InsertData as nn, LeafPredicate as nr, Router as nt, ClientFromProcedures as o, Prettify as on, NO_RETRY as or, ActionCtx as ot, AuthFailedMessage as p, SchemaDefinition as pn, Predicate as pr, MutationFn as pt, WsClientManager as q, AndPredicateSchema as qn, ColumnCodec as qt, CallerOptions as r, Model as rn, LeafPredicateSchema as rr, getContextRegistry as rt, ClientOptions as s, QueryArgs as sn, OccAbortError as sr, ActionFn as st, CallerFromProcedures as t, InferSchema as tn, DEFAULT_RETRY as tr, RegisteredProcedure as tt, LiveQueryStatus as u, SchemaCodecs as un, OrPredicateSchema as ur, ContextOf as ut, AuthSuccessMessageSchema as v, shouldTrackSchema as vn, QueryCacheMetadataSchema as vr, QueryFn as vt, ConnectedMessage as w, LazyCommitTsParam as wn, RawRangeRead as wr, SupaliveDb as wt, CallMessageSchema as x, Database as xn, RangeReadSchema as xr, createActionBuilder as xt, AuthenticationError as y, tableNameToId as yn, QuerySpec as yr, QueryProcedure as yt, SubscriptionUpdateMessage as z, UnregisterSubscriptionParamsSchema as zn, JsonOpOptions as zt };
|
|
1754
|
+
//# sourceMappingURL=index-DouKwYL6.d.ts.map
|