@kividb/client 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +136 -0
- package/dist/index.cjs +830 -0
- package/dist/index.d.cts +493 -0
- package/dist/index.d.ts +493 -0
- package/dist/index.js +792 -0
- package/package.json +51 -0
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,493 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Wire shapes shared across the client. These mirror what the kividb services
|
|
3
|
+
* actually return — see apps/auth, apps/data-api, apps/realtime. Keep them in
|
|
4
|
+
* sync with the server protocol, not with what we wish it were.
|
|
5
|
+
*/
|
|
6
|
+
/** A signed-in session as returned by the auth service token endpoints. */
|
|
7
|
+
interface Session {
|
|
8
|
+
access_token: string;
|
|
9
|
+
token_type: "bearer";
|
|
10
|
+
/** Lifetime of the access token in seconds (currently 3600). */
|
|
11
|
+
expires_in: number;
|
|
12
|
+
/** Opaque, rotates on every refresh. No expiry until revoked. */
|
|
13
|
+
refresh_token: string;
|
|
14
|
+
user: User;
|
|
15
|
+
}
|
|
16
|
+
/** The public projection of a user the auth service is willing to expose. */
|
|
17
|
+
interface User {
|
|
18
|
+
id: string;
|
|
19
|
+
email: string | null;
|
|
20
|
+
email_confirmed_at: string | null;
|
|
21
|
+
last_sign_in_at: string | null;
|
|
22
|
+
user_metadata: Record<string, unknown>;
|
|
23
|
+
created_at: string;
|
|
24
|
+
}
|
|
25
|
+
type OAuthProvider = "github" | "google";
|
|
26
|
+
type Row = Record<string, unknown>;
|
|
27
|
+
/**
|
|
28
|
+
* Every public method resolves to this instead of throwing, so callers can
|
|
29
|
+
* destructure `{ data, error }` the way they would with supabase-js. Network
|
|
30
|
+
* faults and non-2xx responses both land in `error`.
|
|
31
|
+
*/
|
|
32
|
+
interface KividbResponse<T> {
|
|
33
|
+
data: T | null;
|
|
34
|
+
error: KividbError | null;
|
|
35
|
+
}
|
|
36
|
+
/** Normalized error. `status` is 0 for transport failures (never reached the service). */
|
|
37
|
+
interface KividbError {
|
|
38
|
+
message: string;
|
|
39
|
+
status: number;
|
|
40
|
+
/** Extra fields the service attached, e.g. the OAuth `reason` code. */
|
|
41
|
+
details?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
/** Persistence hook so a session survives reloads. Defaults to in-memory only. */
|
|
44
|
+
interface SessionStore {
|
|
45
|
+
get(): Session | null | Promise<Session | null>;
|
|
46
|
+
set(session: Session | null): void | Promise<void>;
|
|
47
|
+
}
|
|
48
|
+
interface ClientOptions {
|
|
49
|
+
/**
|
|
50
|
+
* Override the project slug. By default it is read from the anon key's `ref`
|
|
51
|
+
* claim, which is correct for normal keys — only set this for unusual setups.
|
|
52
|
+
*/
|
|
53
|
+
project?: string;
|
|
54
|
+
/**
|
|
55
|
+
* Per-service base URL overrides. Normally you don't set these: the three
|
|
56
|
+
* are derived from the single `url` passed to createClient (gateway model,
|
|
57
|
+
* `{url}/auth`, `{url}/rest`, `{url}/realtime`). Override one when hitting a
|
|
58
|
+
* service directly — e.g. local dev with no gateway: `rest: "http://localhost:4001"`.
|
|
59
|
+
*/
|
|
60
|
+
rest?: string;
|
|
61
|
+
auth?: string;
|
|
62
|
+
realtime?: string;
|
|
63
|
+
storage?: string;
|
|
64
|
+
/** Where to persist the session. In-memory if omitted. */
|
|
65
|
+
store?: SessionStore;
|
|
66
|
+
/** Automatically refresh the access token shortly before it expires. Default true. */
|
|
67
|
+
autoRefresh?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
type AuthEvent = "SIGNED_IN" | "SIGNED_OUT" | "TOKEN_REFRESHED";
|
|
71
|
+
type AuthListener = (event: AuthEvent, session: Session | null) => void;
|
|
72
|
+
/**
|
|
73
|
+
* Single source of truth for "who is signed in right now". The auth client
|
|
74
|
+
* writes to it; the REST and realtime clients read from it to pick the bearer
|
|
75
|
+
* token. Keeping it separate avoids a circular dependency between those three.
|
|
76
|
+
*/
|
|
77
|
+
declare class SessionManager {
|
|
78
|
+
private readonly store?;
|
|
79
|
+
private current;
|
|
80
|
+
private readonly listeners;
|
|
81
|
+
constructor(store?: SessionStore | undefined);
|
|
82
|
+
/** Load any persisted session on startup. Safe to call more than once. */
|
|
83
|
+
hydrate(): Promise<Session | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Synchronous hydrate for stores that read synchronously (cookies,
|
|
86
|
+
* localStorage). SSR needs the session in memory before the first request in
|
|
87
|
+
* the same tick — an awaited hydrate would be too late. No-ops for async stores.
|
|
88
|
+
*/
|
|
89
|
+
hydrateSync(): void;
|
|
90
|
+
get(): Session | null;
|
|
91
|
+
/** The token data requests should send: the user's, or null to fall back to the anon key. */
|
|
92
|
+
accessToken(): string | null;
|
|
93
|
+
set(session: Session | null, event: AuthEvent): Promise<void>;
|
|
94
|
+
onChange(listener: AuthListener): () => void;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Wraps the auth service (apps/auth). Every route is scoped by project slug:
|
|
99
|
+
* `{auth}/{project}/...`. Methods that mint a session also store it via the
|
|
100
|
+
* SessionManager, so a successful sign-in immediately upgrades subsequent data
|
|
101
|
+
* requests from the anon key to the user's token.
|
|
102
|
+
*/
|
|
103
|
+
declare class AuthClient {
|
|
104
|
+
private readonly base;
|
|
105
|
+
private readonly project;
|
|
106
|
+
private readonly session;
|
|
107
|
+
private readonly autoRefresh;
|
|
108
|
+
constructor(base: string, project: string, session: SessionManager, autoRefresh?: boolean);
|
|
109
|
+
private url;
|
|
110
|
+
/** Register an email/password user. Returns a session only if autoconfirm is on server-side. */
|
|
111
|
+
signUp(params: {
|
|
112
|
+
email: string;
|
|
113
|
+
password: string;
|
|
114
|
+
data?: Record<string, unknown>;
|
|
115
|
+
}): Promise<KividbResponse<Session | {
|
|
116
|
+
user: User;
|
|
117
|
+
confirmation_sent: true;
|
|
118
|
+
}>>;
|
|
119
|
+
signInWithPassword(params: {
|
|
120
|
+
email: string;
|
|
121
|
+
password: string;
|
|
122
|
+
}): Promise<KividbResponse<Session>>;
|
|
123
|
+
/** Passwordless — triggers a magic-link email. The link resolves via `verifyOtp`. */
|
|
124
|
+
signInWithOtp(params: {
|
|
125
|
+
email: string;
|
|
126
|
+
}): Promise<KividbResponse<{
|
|
127
|
+
message: string;
|
|
128
|
+
}>>;
|
|
129
|
+
/**
|
|
130
|
+
* Build the URL the browser should navigate to in order to start an OAuth
|
|
131
|
+
* flow. We return the URL rather than redirecting so the caller controls
|
|
132
|
+
* navigation (and so this works outside a browser). `redirectTo` is where the
|
|
133
|
+
* provider bounces back with a one-time `?code=` to feed to `exchangeCodeForSession`.
|
|
134
|
+
*/
|
|
135
|
+
getOAuthUrl(params: {
|
|
136
|
+
provider: OAuthProvider;
|
|
137
|
+
redirectTo: string;
|
|
138
|
+
/** Pass a signed-in user's access token to LINK this provider instead of logging in. */
|
|
139
|
+
linkToken?: string;
|
|
140
|
+
}): string;
|
|
141
|
+
/** Trade the one-time `?code=` from an OAuth redirect for a real session. */
|
|
142
|
+
exchangeCodeForSession(code: string): Promise<KividbResponse<Session>>;
|
|
143
|
+
/** Rotate the refresh token for a fresh access token. Defaults to the stored session's. */
|
|
144
|
+
refreshSession(refreshToken?: string): Promise<KividbResponse<Session>>;
|
|
145
|
+
signOut(): Promise<KividbResponse<null>>;
|
|
146
|
+
/** The currently stored session (in-memory / from the store). No network call. */
|
|
147
|
+
getSession(): Session | null;
|
|
148
|
+
/**
|
|
149
|
+
* Fetch the live user record for the signed-in session. This is also the
|
|
150
|
+
* canonical server-side "is this token still valid?" check (there is no local
|
|
151
|
+
* JWKS verification yet — see README). On a 401 it transparently rotates the
|
|
152
|
+
* refresh token once and retries, which is what middleware leans on to keep a
|
|
153
|
+
* session alive across requests.
|
|
154
|
+
*/
|
|
155
|
+
getUser(): Promise<KividbResponse<User>>;
|
|
156
|
+
updateUser(params: {
|
|
157
|
+
password?: string;
|
|
158
|
+
data?: Record<string, unknown>;
|
|
159
|
+
}): Promise<KividbResponse<User>>;
|
|
160
|
+
resetPasswordForEmail(email: string): Promise<KividbResponse<{
|
|
161
|
+
message: string;
|
|
162
|
+
}>>;
|
|
163
|
+
/** Consume an emailed one-time token (confirmation / recovery / magiclink) for a session. */
|
|
164
|
+
verifyOtp(params: {
|
|
165
|
+
type: "confirmation" | "recovery" | "magiclink";
|
|
166
|
+
token: string;
|
|
167
|
+
}): Promise<KividbResponse<Session>>;
|
|
168
|
+
/** Subscribe to sign-in / sign-out / refresh transitions. Returns an unsubscribe fn. */
|
|
169
|
+
onAuthStateChange(listener: AuthListener): () => void;
|
|
170
|
+
private token;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* Cookie plumbing for SSR. The auth service returns tokens in the response
|
|
175
|
+
* body (it never sets cookies itself), so the SDK is responsible for putting
|
|
176
|
+
* the session somewhere both the server and the browser can read it. A cookie
|
|
177
|
+
* is that shared place: the browser client writes it, the server client reads
|
|
178
|
+
* it on the next request.
|
|
179
|
+
*
|
|
180
|
+
* The adapter shape mirrors @supabase/ssr so the same Next.js wiring (middleware
|
|
181
|
+
* request/response cookies, next/headers in RSC, route handlers) drops in.
|
|
182
|
+
*/
|
|
183
|
+
interface CookieOptions {
|
|
184
|
+
path?: string;
|
|
185
|
+
domain?: string;
|
|
186
|
+
maxAge?: number;
|
|
187
|
+
expires?: Date;
|
|
188
|
+
secure?: boolean;
|
|
189
|
+
httpOnly?: boolean;
|
|
190
|
+
sameSite?: "lax" | "strict" | "none";
|
|
191
|
+
}
|
|
192
|
+
interface CookieMethods {
|
|
193
|
+
getAll(): {
|
|
194
|
+
name: string;
|
|
195
|
+
value: string;
|
|
196
|
+
}[];
|
|
197
|
+
setAll(cookies: {
|
|
198
|
+
name: string;
|
|
199
|
+
value: string;
|
|
200
|
+
options?: CookieOptions;
|
|
201
|
+
}[]): void;
|
|
202
|
+
}
|
|
203
|
+
/** Cookie name carrying the JSON session for a given project. */
|
|
204
|
+
declare function sessionCookieName(project: string): string;
|
|
205
|
+
|
|
206
|
+
interface Context {
|
|
207
|
+
rest: string;
|
|
208
|
+
project: string;
|
|
209
|
+
anonKey: string;
|
|
210
|
+
session: SessionManager;
|
|
211
|
+
}
|
|
212
|
+
/** Entry point returned by `client.from(table)`. Picks the HTTP verb. */
|
|
213
|
+
declare class FromBuilder {
|
|
214
|
+
private readonly ctx;
|
|
215
|
+
private readonly table;
|
|
216
|
+
constructor(ctx: Context, table: string);
|
|
217
|
+
select(columns?: string): FilterBuilder;
|
|
218
|
+
insert(values: Row | Row[]): FilterBuilder;
|
|
219
|
+
update(values: Row): FilterBuilder;
|
|
220
|
+
delete(): FilterBuilder;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Chainable filters that resolve to `{ data, error }` when awaited (it's a
|
|
224
|
+
* thenable, like supabase-js). The data-api always RETURNs the affected rows,
|
|
225
|
+
* so insert/update/delete come back with their rows too — no extra `.select()`
|
|
226
|
+
* needed. Filters apply to GET/PATCH/DELETE; they are ignored by the server on
|
|
227
|
+
* POST.
|
|
228
|
+
*/
|
|
229
|
+
declare class FilterBuilder implements PromiseLike<KividbResponse<Row[]>> {
|
|
230
|
+
private readonly ctx;
|
|
231
|
+
private readonly table;
|
|
232
|
+
private readonly method;
|
|
233
|
+
private readonly reserved;
|
|
234
|
+
private readonly body?;
|
|
235
|
+
private readonly filters;
|
|
236
|
+
private readonly orders;
|
|
237
|
+
private limitValue?;
|
|
238
|
+
private offsetValue?;
|
|
239
|
+
constructor(ctx: Context, table: string, method: string, reserved: Record<string, string>, body?: (Row | Row[]) | undefined);
|
|
240
|
+
eq(column: string, value: unknown): this;
|
|
241
|
+
neq(column: string, value: unknown): this;
|
|
242
|
+
gt(column: string, value: unknown): this;
|
|
243
|
+
gte(column: string, value: unknown): this;
|
|
244
|
+
lt(column: string, value: unknown): this;
|
|
245
|
+
lte(column: string, value: unknown): this;
|
|
246
|
+
like(column: string, pattern: string): this;
|
|
247
|
+
ilike(column: string, pattern: string): this;
|
|
248
|
+
/** Only `null`, `true`, `false` are accepted by the server for `is`. */
|
|
249
|
+
is(column: string, value: null | boolean): this;
|
|
250
|
+
order(column: string, opts?: {
|
|
251
|
+
ascending?: boolean;
|
|
252
|
+
}): this;
|
|
253
|
+
limit(count: number): this;
|
|
254
|
+
offset(count: number): this;
|
|
255
|
+
/** Inclusive range helper, like supabase-js. `range(0, 9)` → first 10 rows. */
|
|
256
|
+
range(from: number, to: number): this;
|
|
257
|
+
private filter;
|
|
258
|
+
private buildUrl;
|
|
259
|
+
private execute;
|
|
260
|
+
then<TResult1 = KividbResponse<Row[]>, TResult2 = never>(onfulfilled?: ((value: KividbResponse<Row[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): PromiseLike<TResult1 | TResult2>;
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Realtime client for apps/realtime. One WebSocket per project carries many
|
|
265
|
+
* topics (channels) multiplexed over it — matching the server, which keys all
|
|
266
|
+
* routing off the per-message `topic`. Auth rides on the connection URL as
|
|
267
|
+
* `?token=`, so a channel cannot outlive a token change without reconnecting.
|
|
268
|
+
*/
|
|
269
|
+
interface PostgresChange {
|
|
270
|
+
eventType: "INSERT" | "UPDATE" | "DELETE";
|
|
271
|
+
schema: string;
|
|
272
|
+
table: string;
|
|
273
|
+
new?: Record<string, unknown>;
|
|
274
|
+
old?: Record<string, unknown>;
|
|
275
|
+
}
|
|
276
|
+
type PostgresEvent = "INSERT" | "UPDATE" | "DELETE" | "*";
|
|
277
|
+
type BroadcastHandler = (msg: {
|
|
278
|
+
event: string;
|
|
279
|
+
payload: unknown;
|
|
280
|
+
}) => void;
|
|
281
|
+
type PresenceHandler = (state: Record<string, unknown>) => void;
|
|
282
|
+
type PostgresHandler = (change: PostgresChange) => void;
|
|
283
|
+
interface BroadcastBinding {
|
|
284
|
+
kind: "broadcast";
|
|
285
|
+
event: string;
|
|
286
|
+
cb: BroadcastHandler;
|
|
287
|
+
}
|
|
288
|
+
interface PresenceBinding {
|
|
289
|
+
kind: "presence";
|
|
290
|
+
cb: PresenceHandler;
|
|
291
|
+
}
|
|
292
|
+
interface PostgresBinding {
|
|
293
|
+
kind: "postgres_changes";
|
|
294
|
+
table: string;
|
|
295
|
+
event: PostgresEvent;
|
|
296
|
+
cb: PostgresHandler;
|
|
297
|
+
}
|
|
298
|
+
type Binding = BroadcastBinding | PresenceBinding | PostgresBinding;
|
|
299
|
+
declare class RealtimeChannel {
|
|
300
|
+
readonly topic: string;
|
|
301
|
+
private readonly client;
|
|
302
|
+
/** @internal */ readonly bindings: Binding[];
|
|
303
|
+
private subscribed;
|
|
304
|
+
constructor(topic: string, client: RealtimeClient);
|
|
305
|
+
/** Listen for a custom broadcast event. Pass `event: "*"` for every event. */
|
|
306
|
+
on(type: "broadcast", filter: {
|
|
307
|
+
event: string;
|
|
308
|
+
}, cb: BroadcastHandler): this;
|
|
309
|
+
/** Listen for presence sync (the full tracked-state map). */
|
|
310
|
+
on(type: "presence", filter: {
|
|
311
|
+
event: "sync";
|
|
312
|
+
}, cb: PresenceHandler): this;
|
|
313
|
+
/** Listen for row changes on a table. RLS is enforced server-side per row. */
|
|
314
|
+
on(type: "postgres_changes", filter: {
|
|
315
|
+
table: string;
|
|
316
|
+
event?: PostgresEvent;
|
|
317
|
+
}, cb: PostgresHandler): this;
|
|
318
|
+
/** Open the connection (if needed) and register this channel's topic. */
|
|
319
|
+
subscribe(): this;
|
|
320
|
+
/** Send a broadcast to every other subscriber on this topic (no self-echo). */
|
|
321
|
+
send(message: {
|
|
322
|
+
event: string;
|
|
323
|
+
payload: unknown;
|
|
324
|
+
}): void;
|
|
325
|
+
/** Advertise presence state for this client on the topic. */
|
|
326
|
+
track(payload?: Record<string, unknown>): void;
|
|
327
|
+
untrack(): void;
|
|
328
|
+
unsubscribe(): void;
|
|
329
|
+
/** @internal The subscribe frame the server expects for this channel. */
|
|
330
|
+
_subscribeFrame(): {
|
|
331
|
+
type: "subscribe";
|
|
332
|
+
topic: string;
|
|
333
|
+
presence: boolean;
|
|
334
|
+
postgres_changes: {
|
|
335
|
+
table: string;
|
|
336
|
+
event: PostgresEvent;
|
|
337
|
+
}[];
|
|
338
|
+
};
|
|
339
|
+
/** @internal */ get isSubscribed(): boolean;
|
|
340
|
+
}
|
|
341
|
+
declare class RealtimeClient {
|
|
342
|
+
private readonly base;
|
|
343
|
+
private readonly project;
|
|
344
|
+
private readonly anonKey;
|
|
345
|
+
private readonly session;
|
|
346
|
+
private socket;
|
|
347
|
+
private readonly channels;
|
|
348
|
+
private readonly outbox;
|
|
349
|
+
private reconnectAttempts;
|
|
350
|
+
private closedByUser;
|
|
351
|
+
constructor(base: string, project: string, anonKey: string, session: SessionManager);
|
|
352
|
+
channel(topic: string): RealtimeChannel;
|
|
353
|
+
/** Tear everything down. Call on app unmount / sign-out. */
|
|
354
|
+
disconnect(): void;
|
|
355
|
+
/** @internal */
|
|
356
|
+
_attach(channel: RealtimeChannel): void;
|
|
357
|
+
/** @internal */
|
|
358
|
+
_detach(channel: RealtimeChannel): void;
|
|
359
|
+
/** @internal Queues until the socket is open, then flushes in order. */
|
|
360
|
+
_send(frame: unknown): void;
|
|
361
|
+
private connect;
|
|
362
|
+
private scheduleReconnect;
|
|
363
|
+
private dispatch;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Object storage client — `kdb.storage.from(bucket)`. Mirrors supabase-js's
|
|
368
|
+
* storage surface. Requests carry the signed-in user's token when there is one,
|
|
369
|
+
* falling back to the anon key, so bucket RLS applies exactly as it does to data
|
|
370
|
+
* requests. Public and render URLs are built locally (no round-trip) for use in
|
|
371
|
+
* `<img>`/`<a>` tags.
|
|
372
|
+
*/
|
|
373
|
+
interface StorageObjectInfo {
|
|
374
|
+
id: string;
|
|
375
|
+
name: string;
|
|
376
|
+
size: number | null;
|
|
377
|
+
mimeType: string | null;
|
|
378
|
+
checksum: string | null;
|
|
379
|
+
metadata: Record<string, unknown>;
|
|
380
|
+
version: number;
|
|
381
|
+
createdAt: string;
|
|
382
|
+
updatedAt: string;
|
|
383
|
+
}
|
|
384
|
+
type UploadBody = Blob | ArrayBuffer | ArrayBufferView | string;
|
|
385
|
+
interface UploadOptions {
|
|
386
|
+
/** Overrides the content type (defaults to a Blob's own type, else octet-stream). */
|
|
387
|
+
contentType?: string;
|
|
388
|
+
}
|
|
389
|
+
interface TransformOptions {
|
|
390
|
+
width?: number;
|
|
391
|
+
height?: number;
|
|
392
|
+
resize?: "cover" | "contain" | "fill" | "inside" | "outside";
|
|
393
|
+
format?: "webp" | "jpeg" | "png" | "avif";
|
|
394
|
+
quality?: number;
|
|
395
|
+
}
|
|
396
|
+
interface SignedUrl {
|
|
397
|
+
url: string;
|
|
398
|
+
token: string;
|
|
399
|
+
exp: number;
|
|
400
|
+
expiresAt: string;
|
|
401
|
+
}
|
|
402
|
+
interface Ctx {
|
|
403
|
+
storage: string;
|
|
404
|
+
project: string;
|
|
405
|
+
anonKey: string;
|
|
406
|
+
session: SessionManager;
|
|
407
|
+
}
|
|
408
|
+
declare class BucketApi {
|
|
409
|
+
private readonly ctx;
|
|
410
|
+
private readonly bucket;
|
|
411
|
+
constructor(ctx: Ctx, bucket: string);
|
|
412
|
+
private token;
|
|
413
|
+
private objectUrl;
|
|
414
|
+
/** Upload (or overwrite) an object. */
|
|
415
|
+
upload(path: string, body: UploadBody, options?: UploadOptions): Promise<KividbResponse<StorageObjectInfo>>;
|
|
416
|
+
/** Download an object's bytes. */
|
|
417
|
+
download(path: string): Promise<KividbResponse<Blob>>;
|
|
418
|
+
/** Delete one or more objects. */
|
|
419
|
+
remove(paths: string[]): Promise<KividbResponse<{
|
|
420
|
+
removed: number;
|
|
421
|
+
}>>;
|
|
422
|
+
/** List objects in the bucket, optionally under a path prefix. */
|
|
423
|
+
list(prefix?: string): Promise<KividbResponse<StorageObjectInfo[]>>;
|
|
424
|
+
/** Mint a time-boxed signed URL for a private object (default 1 hour). */
|
|
425
|
+
createSignedUrl(path: string, expiresIn?: number): Promise<KividbResponse<SignedUrl>>;
|
|
426
|
+
/** The token-less public URL for an object in a public bucket. */
|
|
427
|
+
getPublicUrl(path: string): string;
|
|
428
|
+
/** A transform (render) URL — resize/reformat an image on the fly. */
|
|
429
|
+
getRenderUrl(path: string, transform?: TransformOptions): string;
|
|
430
|
+
}
|
|
431
|
+
declare class StorageClient {
|
|
432
|
+
private readonly ctx;
|
|
433
|
+
constructor(ctx: Ctx);
|
|
434
|
+
/** Operate on a bucket. */
|
|
435
|
+
from(bucket: string): BucketApi;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
/**
|
|
439
|
+
* Read the project slug out of an anon key. The key is a kividb JWT whose `ref`
|
|
440
|
+
* claim is the project it's scoped to, so the SDK can recover the slug without a
|
|
441
|
+
* separate config value. This is an UNVERIFIED decode — we only read a public
|
|
442
|
+
* claim to know which project paths to build; the server still verifies the
|
|
443
|
+
* signature on every request.
|
|
444
|
+
*/
|
|
445
|
+
declare function projectFromAnonKey(anonKey: string): string;
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* The kividb client. One per (url, anon key) pair.
|
|
449
|
+
*
|
|
450
|
+
* const kdb = createClient("https://database.akivi.se", anonKey);
|
|
451
|
+
* const { data } = await kdb.from("posts").select("*").eq("published", true);
|
|
452
|
+
* await kdb.auth.signInWithPassword({ email, password });
|
|
453
|
+
* kdb.channel("room:1").on("broadcast", { event: "msg" }, console.log).subscribe();
|
|
454
|
+
*
|
|
455
|
+
* `url` is the gateway origin fronting all services. The project slug is read
|
|
456
|
+
* from the anon key's `ref` claim (override with `options.project`). `anonKey`
|
|
457
|
+
* is the project's long-lived anon JWT — data requests use it until a user signs
|
|
458
|
+
* in, after which they automatically switch to that user's access token.
|
|
459
|
+
*/
|
|
460
|
+
declare class KividbClient {
|
|
461
|
+
readonly url: string;
|
|
462
|
+
private readonly anonKey;
|
|
463
|
+
readonly auth: AuthClient;
|
|
464
|
+
readonly realtime: RealtimeClient;
|
|
465
|
+
readonly storage: StorageClient;
|
|
466
|
+
readonly project: string;
|
|
467
|
+
private readonly endpoints;
|
|
468
|
+
private readonly session;
|
|
469
|
+
constructor(url: string, anonKey: string, options?: ClientOptions);
|
|
470
|
+
/** Start a query against a table. */
|
|
471
|
+
from(table: string): FromBuilder;
|
|
472
|
+
/** Open (or reuse) a realtime channel for a topic. */
|
|
473
|
+
channel(topic: string): RealtimeChannel;
|
|
474
|
+
}
|
|
475
|
+
declare function createClient(url: string, anonKey: string, options?: ClientOptions): KividbClient;
|
|
476
|
+
/**
|
|
477
|
+
* Browser client for SSR setups: persists the session to `document.cookie` so
|
|
478
|
+
* the server can read it on the next request. Use this in client components.
|
|
479
|
+
*/
|
|
480
|
+
declare function createBrowserClient(url: string, anonKey: string, options?: Omit<ClientOptions, "store">): KividbClient;
|
|
481
|
+
/**
|
|
482
|
+
* Server client for SSR setups: reads (and writes) the session through a cookie
|
|
483
|
+
* adapter you supply — Next.js `cookies()` in RSC, or the request/response
|
|
484
|
+
* cookies in middleware and route handlers. Mirrors @supabase/ssr's wiring.
|
|
485
|
+
*
|
|
486
|
+
* There is no local token verification yet, so `auth.getUser()` is a network
|
|
487
|
+
* call to the auth service — that is the canonical server-side auth check.
|
|
488
|
+
*/
|
|
489
|
+
declare function createServerClient(url: string, anonKey: string, options: Omit<ClientOptions, "store"> & {
|
|
490
|
+
cookies: CookieMethods;
|
|
491
|
+
}): KividbClient;
|
|
492
|
+
|
|
493
|
+
export { AuthClient, type AuthEvent, type AuthListener, type ClientOptions, type CookieMethods, type CookieOptions, FilterBuilder, FromBuilder, KividbClient, type KividbError, type KividbResponse, type OAuthProvider, type PostgresChange, RealtimeChannel, RealtimeClient, type Row, type Session, type SessionStore, type SignedUrl, StorageClient, type StorageObjectInfo, type TransformOptions, type UploadBody, type UploadOptions, type User, createBrowserClient, createClient, createServerClient, projectFromAnonKey, sessionCookieName };
|