@kividb/client 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -1,11 +1,9 @@
1
1
  # @kividb/client
2
2
 
3
3
  The JavaScript/TypeScript client SDK for kividb — a thin, typed wrapper over the
4
- `data-api`, `auth`, and `realtime` services. Works in browsers, React Native,
5
- and Node 22+ (uses global `fetch` and `WebSocket`, no runtime dependencies).
6
-
7
- > Status: initial scaffold. Covers the full data, auth, and realtime surface the
8
- > services expose today. Storage and edge-function helpers are not built yet.
4
+ `data-api`, `auth`, `realtime`, and `storage` services. Works in browsers,
5
+ React Native, and Node 22+ (uses global `fetch` and `WebSocket`, no runtime
6
+ dependencies).
9
7
 
10
8
  ## Install
11
9
 
@@ -32,6 +30,7 @@ const kdb = createClient("http://localhost", ANON_KEY, {
32
30
  auth: "http://localhost:4000",
33
31
  rest: "http://localhost:4001",
34
32
  realtime: "ws://localhost:4002",
33
+ storage: "http://localhost:4004",
35
34
  });
36
35
  ```
37
36
 
@@ -134,3 +133,74 @@ channel.unsubscribe();
134
133
  One WebSocket is shared per project across all channels. It reconnects with
135
134
  backoff and re-subscribes automatically; `DELETE` postgres events are delivered
136
135
  only to `service_role` tokens (a documented v1 server limitation).
136
+
137
+ ## Migrations
138
+
139
+ Create and evolve your schema from code instead of the dashboard. Requires the
140
+ **service key** (server-side only — never ship it to a browser):
141
+
142
+ ```ts
143
+ const kdb = createClient(KIVIDB_URL, process.env.KIVIDB_SERVICE_KEY!);
144
+
145
+ await kdb.migrations.apply([
146
+ {
147
+ name: "0001_messages",
148
+ sql: `
149
+ create table messages (
150
+ id uuid primary key default gen_random_uuid(),
151
+ room text not null,
152
+ body text not null,
153
+ created_at timestamptz not null default now()
154
+ );
155
+ alter table messages enable row level security;
156
+ `,
157
+ },
158
+ ]);
159
+
160
+ const { data } = await kdb.migrations.list(); // the applied-migrations ledger
161
+ ```
162
+
163
+ `apply` is idempotent: each migration is recorded by name in a per-project
164
+ ledger, so re-running the same list skips what's already applied — keep one
165
+ array in your repo, append to it, and run it on every deploy. Applied
166
+ migrations are immutable (changing an applied name's SQL is a 409; add a new
167
+ one instead). Each migration runs in its own transaction as the project owner
168
+ role, with your project schema as the `search_path` — remember to enable RLS
169
+ on new tables, and don't put `begin`/`commit` inside the SQL.
170
+
171
+ ## Storage
172
+
173
+ Objects live in buckets. Object requests carry the signed-in user's token (or
174
+ the anon key), so storage RLS applies exactly like data requests:
175
+
176
+ ```ts
177
+ await kdb.storage.from("avatars").upload("user-42/photo.png", file);
178
+ const { data: blob } = await kdb.storage.from("avatars").download("user-42/photo.png");
179
+ const { data: objects } = await kdb.storage.from("avatars").list("user-42/");
180
+ await kdb.storage.from("avatars").remove(["user-42/photo.png"]);
181
+
182
+ const { data: signed } = await kdb.storage.from("private-docs").createSignedUrl("report.pdf", 3600);
183
+ kdb.storage.from("avatars").getPublicUrl("user-42/photo.png"); // public buckets
184
+ kdb.storage.from("avatars").getRenderUrl("user-42/photo.png", { width: 128, format: "webp" });
185
+ ```
186
+
187
+ ### Buckets
188
+
189
+ Creating and deleting buckets requires the **service key** (server-side only);
190
+ listing and reading bucket metadata work with any key:
191
+
192
+ ```ts
193
+ const kdb = createClient(KIVIDB_URL, process.env.KIVIDB_SERVICE_KEY!);
194
+
195
+ await kdb.storage.createBucket("avatars", { public: true });
196
+ await kdb.storage.createBucket("attachments", {
197
+ allowedMimeTypes: ["image/png", "image/jpeg", "application/pdf"],
198
+ maxObjectSize: 10_000_000, // bytes
199
+ });
200
+
201
+ const { data: buckets } = await kdb.storage.listBuckets();
202
+ const { data: bucket } = await kdb.storage.getBucket("attachments");
203
+ await kdb.storage.deleteBucket("attachments"); // 409 unless the bucket is empty
204
+ ```
205
+
206
+ Bucket names are 2–63 chars: lowercase letters, digits, `.`, `_` or `-`.
package/dist/index.cjs CHANGED
@@ -24,6 +24,7 @@ __export(index_exports, {
24
24
  FilterBuilder: () => FilterBuilder,
25
25
  FromBuilder: () => FromBuilder,
26
26
  KividbClient: () => KividbClient,
27
+ MigrationsClient: () => MigrationsClient,
27
28
  RealtimeChannel: () => RealtimeChannel,
28
29
  RealtimeClient: () => RealtimeClient,
29
30
  StorageClient: () => StorageClient,
@@ -302,6 +303,34 @@ function base64UrlDecode(segment) {
302
303
  return new TextDecoder().decode(bytes);
303
304
  }
304
305
 
306
+ // src/migrations.ts
307
+ var MigrationsClient = class {
308
+ constructor(cfg) {
309
+ this.cfg = cfg;
310
+ }
311
+ cfg;
312
+ get endpoint() {
313
+ return `${this.cfg.rest}/${this.cfg.project}/-/migrations`;
314
+ }
315
+ /**
316
+ * Apply migrations in order, skipping ones already applied. On a failure the
317
+ * error's `details` carry `failed` (the migration that broke) plus the
318
+ * `applied`/`skipped` progress before it; already-applied migrations stay
319
+ * applied and skip on the next run.
320
+ */
321
+ apply(migrations) {
322
+ return request(this.endpoint, {
323
+ method: "POST",
324
+ body: JSON.stringify({ migrations }),
325
+ token: this.cfg.key
326
+ });
327
+ }
328
+ /** The applied-migrations ledger, oldest first. */
329
+ list() {
330
+ return request(this.endpoint, { token: this.cfg.key });
331
+ }
332
+ };
333
+
305
334
  // src/postgrest.ts
306
335
  var FromBuilder = class {
307
336
  constructor(ctx, table) {
@@ -732,6 +761,42 @@ var StorageClient = class {
732
761
  from(bucket) {
733
762
  return new BucketApi(this.ctx, bucket);
734
763
  }
764
+ token() {
765
+ return this.ctx.session.accessToken() ?? this.ctx.anonKey;
766
+ }
767
+ bucketsUrl(name) {
768
+ const base = `${this.ctx.storage}/${this.ctx.project}/buckets`;
769
+ return name ? `${base}/${encodeURIComponent(name)}` : base;
770
+ }
771
+ /** All buckets in the project (any key; bucket metadata is readable). */
772
+ listBuckets() {
773
+ return request(this.bucketsUrl(), { token: this.token() });
774
+ }
775
+ /** One bucket's metadata, or a 404 error if it doesn't exist. */
776
+ getBucket(name) {
777
+ return request(this.bucketsUrl(name), { token: this.token() });
778
+ }
779
+ /**
780
+ * Create a bucket. Requires the service_role key. Names are 2–63 chars of
781
+ * lowercase letters, digits, ".", "_" or "-".
782
+ */
783
+ createBucket(name, options = {}) {
784
+ return request(this.bucketsUrl(), {
785
+ method: "POST",
786
+ token: this.token(),
787
+ body: JSON.stringify({ name, ...options })
788
+ });
789
+ }
790
+ /**
791
+ * Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
792
+ * first). Requires the service_role key.
793
+ */
794
+ deleteBucket(name) {
795
+ return request(this.bucketsUrl(name), {
796
+ method: "DELETE",
797
+ token: this.token()
798
+ });
799
+ }
735
800
  };
736
801
 
737
802
  // src/index.ts
@@ -770,6 +835,11 @@ var KividbClient = class {
770
835
  anonKey,
771
836
  session: this.session
772
837
  });
838
+ this.migrations = new MigrationsClient({
839
+ rest: this.endpoints.rest,
840
+ project: this.project,
841
+ key: anonKey
842
+ });
773
843
  this.session.hydrateSync();
774
844
  void this.session.hydrate();
775
845
  }
@@ -778,6 +848,8 @@ var KividbClient = class {
778
848
  auth;
779
849
  realtime;
780
850
  storage;
851
+ /** Schema migrations — requires the client to hold the service key. */
852
+ migrations;
781
853
  project;
782
854
  endpoints;
783
855
  session;
@@ -819,6 +891,7 @@ function createServerClient(url, anonKey, options) {
819
891
  FilterBuilder,
820
892
  FromBuilder,
821
893
  KividbClient,
894
+ MigrationsClient,
822
895
  RealtimeChannel,
823
896
  RealtimeClient,
824
897
  StorageClient,
package/dist/index.d.cts CHANGED
@@ -203,6 +203,58 @@ interface CookieMethods {
203
203
  /** Cookie name carrying the JSON session for a given project. */
204
204
  declare function sessionCookieName(project: string): string;
205
205
 
206
+ /**
207
+ * Schema migrations, applied through the data API's service_role-only
208
+ * `/:project/-/migrations` endpoint. Create the client with the project's
209
+ * **service key** (never ship that key to a browser):
210
+ *
211
+ * const kdb = createClient(url, serviceKey);
212
+ * await kdb.migrations.apply([
213
+ * { name: "0001_messages", sql: `create table messages (…); alter table messages enable row level security;` },
214
+ * ]);
215
+ *
216
+ * Applying is idempotent: each migration is recorded in a per-project ledger
217
+ * by name, so re-running the same list skips what's already applied. Applied
218
+ * migrations are immutable — changing the SQL of an applied name is a 409;
219
+ * add a new migration instead.
220
+ */
221
+ /** A named schema migration. Names must be unique and are applied in order. */
222
+ interface Migration {
223
+ name: string;
224
+ sql: string;
225
+ }
226
+ interface ApplyMigrationsResult {
227
+ /** Names applied by this call, in order. */
228
+ applied: string[];
229
+ /** Names already in the ledger (identical SQL), skipped. */
230
+ skipped: string[];
231
+ }
232
+ /** A ledger entry for an applied migration. */
233
+ interface AppliedMigration {
234
+ name: string;
235
+ /** sha256 of the SQL as applied. */
236
+ checksum: string;
237
+ applied_at: string;
238
+ }
239
+ declare class MigrationsClient {
240
+ private readonly cfg;
241
+ constructor(cfg: {
242
+ rest: string;
243
+ project: string;
244
+ key: string;
245
+ });
246
+ private get endpoint();
247
+ /**
248
+ * Apply migrations in order, skipping ones already applied. On a failure the
249
+ * error's `details` carry `failed` (the migration that broke) plus the
250
+ * `applied`/`skipped` progress before it; already-applied migrations stay
251
+ * applied and skip on the next run.
252
+ */
253
+ apply(migrations: Migration[]): Promise<KividbResponse<ApplyMigrationsResult>>;
254
+ /** The applied-migrations ledger, oldest first. */
255
+ list(): Promise<KividbResponse<AppliedMigration[]>>;
256
+ }
257
+
206
258
  interface Context {
207
259
  rest: string;
208
260
  project: string;
@@ -399,6 +451,24 @@ interface SignedUrl {
399
451
  exp: number;
400
452
  expiresAt: string;
401
453
  }
454
+ /** A bucket as the storage service returns it. */
455
+ interface BucketInfo {
456
+ id: string;
457
+ name: string;
458
+ public: boolean;
459
+ allowedMimeTypes: string[] | null;
460
+ maxObjectSize: number | null;
461
+ createdAt: string;
462
+ updatedAt: string;
463
+ }
464
+ interface CreateBucketOptions {
465
+ /** Public buckets serve objects at a token-less URL. Default false. */
466
+ public?: boolean;
467
+ /** Restrict uploads to these mime types (e.g. ["image/*"]). Null = any. */
468
+ allowedMimeTypes?: string[] | null;
469
+ /** Per-object size cap in bytes. Null = the service default. */
470
+ maxObjectSize?: number | null;
471
+ }
402
472
  interface Ctx {
403
473
  storage: string;
404
474
  project: string;
@@ -433,6 +503,22 @@ declare class StorageClient {
433
503
  constructor(ctx: Ctx);
434
504
  /** Operate on a bucket. */
435
505
  from(bucket: string): BucketApi;
506
+ private token;
507
+ private bucketsUrl;
508
+ /** All buckets in the project (any key; bucket metadata is readable). */
509
+ listBuckets(): Promise<KividbResponse<BucketInfo[]>>;
510
+ /** One bucket's metadata, or a 404 error if it doesn't exist. */
511
+ getBucket(name: string): Promise<KividbResponse<BucketInfo>>;
512
+ /**
513
+ * Create a bucket. Requires the service_role key. Names are 2–63 chars of
514
+ * lowercase letters, digits, ".", "_" or "-".
515
+ */
516
+ createBucket(name: string, options?: CreateBucketOptions): Promise<KividbResponse<BucketInfo>>;
517
+ /**
518
+ * Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
519
+ * first). Requires the service_role key.
520
+ */
521
+ deleteBucket(name: string): Promise<KividbResponse<null>>;
436
522
  }
437
523
 
438
524
  /**
@@ -463,6 +549,8 @@ declare class KividbClient {
463
549
  readonly auth: AuthClient;
464
550
  readonly realtime: RealtimeClient;
465
551
  readonly storage: StorageClient;
552
+ /** Schema migrations — requires the client to hold the service key. */
553
+ readonly migrations: MigrationsClient;
466
554
  readonly project: string;
467
555
  private readonly endpoints;
468
556
  private readonly session;
@@ -490,4 +578,4 @@ declare function createServerClient(url: string, anonKey: string, options: Omit<
490
578
  cookies: CookieMethods;
491
579
  }): KividbClient;
492
580
 
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 };
581
+ export { type AppliedMigration, type ApplyMigrationsResult, AuthClient, type AuthEvent, type AuthListener, type BucketInfo, type ClientOptions, type CookieMethods, type CookieOptions, type CreateBucketOptions, FilterBuilder, FromBuilder, KividbClient, type KividbError, type KividbResponse, type Migration, MigrationsClient, 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 };
package/dist/index.d.ts CHANGED
@@ -203,6 +203,58 @@ interface CookieMethods {
203
203
  /** Cookie name carrying the JSON session for a given project. */
204
204
  declare function sessionCookieName(project: string): string;
205
205
 
206
+ /**
207
+ * Schema migrations, applied through the data API's service_role-only
208
+ * `/:project/-/migrations` endpoint. Create the client with the project's
209
+ * **service key** (never ship that key to a browser):
210
+ *
211
+ * const kdb = createClient(url, serviceKey);
212
+ * await kdb.migrations.apply([
213
+ * { name: "0001_messages", sql: `create table messages (…); alter table messages enable row level security;` },
214
+ * ]);
215
+ *
216
+ * Applying is idempotent: each migration is recorded in a per-project ledger
217
+ * by name, so re-running the same list skips what's already applied. Applied
218
+ * migrations are immutable — changing the SQL of an applied name is a 409;
219
+ * add a new migration instead.
220
+ */
221
+ /** A named schema migration. Names must be unique and are applied in order. */
222
+ interface Migration {
223
+ name: string;
224
+ sql: string;
225
+ }
226
+ interface ApplyMigrationsResult {
227
+ /** Names applied by this call, in order. */
228
+ applied: string[];
229
+ /** Names already in the ledger (identical SQL), skipped. */
230
+ skipped: string[];
231
+ }
232
+ /** A ledger entry for an applied migration. */
233
+ interface AppliedMigration {
234
+ name: string;
235
+ /** sha256 of the SQL as applied. */
236
+ checksum: string;
237
+ applied_at: string;
238
+ }
239
+ declare class MigrationsClient {
240
+ private readonly cfg;
241
+ constructor(cfg: {
242
+ rest: string;
243
+ project: string;
244
+ key: string;
245
+ });
246
+ private get endpoint();
247
+ /**
248
+ * Apply migrations in order, skipping ones already applied. On a failure the
249
+ * error's `details` carry `failed` (the migration that broke) plus the
250
+ * `applied`/`skipped` progress before it; already-applied migrations stay
251
+ * applied and skip on the next run.
252
+ */
253
+ apply(migrations: Migration[]): Promise<KividbResponse<ApplyMigrationsResult>>;
254
+ /** The applied-migrations ledger, oldest first. */
255
+ list(): Promise<KividbResponse<AppliedMigration[]>>;
256
+ }
257
+
206
258
  interface Context {
207
259
  rest: string;
208
260
  project: string;
@@ -399,6 +451,24 @@ interface SignedUrl {
399
451
  exp: number;
400
452
  expiresAt: string;
401
453
  }
454
+ /** A bucket as the storage service returns it. */
455
+ interface BucketInfo {
456
+ id: string;
457
+ name: string;
458
+ public: boolean;
459
+ allowedMimeTypes: string[] | null;
460
+ maxObjectSize: number | null;
461
+ createdAt: string;
462
+ updatedAt: string;
463
+ }
464
+ interface CreateBucketOptions {
465
+ /** Public buckets serve objects at a token-less URL. Default false. */
466
+ public?: boolean;
467
+ /** Restrict uploads to these mime types (e.g. ["image/*"]). Null = any. */
468
+ allowedMimeTypes?: string[] | null;
469
+ /** Per-object size cap in bytes. Null = the service default. */
470
+ maxObjectSize?: number | null;
471
+ }
402
472
  interface Ctx {
403
473
  storage: string;
404
474
  project: string;
@@ -433,6 +503,22 @@ declare class StorageClient {
433
503
  constructor(ctx: Ctx);
434
504
  /** Operate on a bucket. */
435
505
  from(bucket: string): BucketApi;
506
+ private token;
507
+ private bucketsUrl;
508
+ /** All buckets in the project (any key; bucket metadata is readable). */
509
+ listBuckets(): Promise<KividbResponse<BucketInfo[]>>;
510
+ /** One bucket's metadata, or a 404 error if it doesn't exist. */
511
+ getBucket(name: string): Promise<KividbResponse<BucketInfo>>;
512
+ /**
513
+ * Create a bucket. Requires the service_role key. Names are 2–63 chars of
514
+ * lowercase letters, digits, ".", "_" or "-".
515
+ */
516
+ createBucket(name: string, options?: CreateBucketOptions): Promise<KividbResponse<BucketInfo>>;
517
+ /**
518
+ * Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
519
+ * first). Requires the service_role key.
520
+ */
521
+ deleteBucket(name: string): Promise<KividbResponse<null>>;
436
522
  }
437
523
 
438
524
  /**
@@ -463,6 +549,8 @@ declare class KividbClient {
463
549
  readonly auth: AuthClient;
464
550
  readonly realtime: RealtimeClient;
465
551
  readonly storage: StorageClient;
552
+ /** Schema migrations — requires the client to hold the service key. */
553
+ readonly migrations: MigrationsClient;
466
554
  readonly project: string;
467
555
  private readonly endpoints;
468
556
  private readonly session;
@@ -490,4 +578,4 @@ declare function createServerClient(url: string, anonKey: string, options: Omit<
490
578
  cookies: CookieMethods;
491
579
  }): KividbClient;
492
580
 
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 };
581
+ export { type AppliedMigration, type ApplyMigrationsResult, AuthClient, type AuthEvent, type AuthListener, type BucketInfo, type ClientOptions, type CookieMethods, type CookieOptions, type CreateBucketOptions, FilterBuilder, FromBuilder, KividbClient, type KividbError, type KividbResponse, type Migration, MigrationsClient, 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 };
package/dist/index.js CHANGED
@@ -265,6 +265,34 @@ function base64UrlDecode(segment) {
265
265
  return new TextDecoder().decode(bytes);
266
266
  }
267
267
 
268
+ // src/migrations.ts
269
+ var MigrationsClient = class {
270
+ constructor(cfg) {
271
+ this.cfg = cfg;
272
+ }
273
+ cfg;
274
+ get endpoint() {
275
+ return `${this.cfg.rest}/${this.cfg.project}/-/migrations`;
276
+ }
277
+ /**
278
+ * Apply migrations in order, skipping ones already applied. On a failure the
279
+ * error's `details` carry `failed` (the migration that broke) plus the
280
+ * `applied`/`skipped` progress before it; already-applied migrations stay
281
+ * applied and skip on the next run.
282
+ */
283
+ apply(migrations) {
284
+ return request(this.endpoint, {
285
+ method: "POST",
286
+ body: JSON.stringify({ migrations }),
287
+ token: this.cfg.key
288
+ });
289
+ }
290
+ /** The applied-migrations ledger, oldest first. */
291
+ list() {
292
+ return request(this.endpoint, { token: this.cfg.key });
293
+ }
294
+ };
295
+
268
296
  // src/postgrest.ts
269
297
  var FromBuilder = class {
270
298
  constructor(ctx, table) {
@@ -695,6 +723,42 @@ var StorageClient = class {
695
723
  from(bucket) {
696
724
  return new BucketApi(this.ctx, bucket);
697
725
  }
726
+ token() {
727
+ return this.ctx.session.accessToken() ?? this.ctx.anonKey;
728
+ }
729
+ bucketsUrl(name) {
730
+ const base = `${this.ctx.storage}/${this.ctx.project}/buckets`;
731
+ return name ? `${base}/${encodeURIComponent(name)}` : base;
732
+ }
733
+ /** All buckets in the project (any key; bucket metadata is readable). */
734
+ listBuckets() {
735
+ return request(this.bucketsUrl(), { token: this.token() });
736
+ }
737
+ /** One bucket's metadata, or a 404 error if it doesn't exist. */
738
+ getBucket(name) {
739
+ return request(this.bucketsUrl(name), { token: this.token() });
740
+ }
741
+ /**
742
+ * Create a bucket. Requires the service_role key. Names are 2–63 chars of
743
+ * lowercase letters, digits, ".", "_" or "-".
744
+ */
745
+ createBucket(name, options = {}) {
746
+ return request(this.bucketsUrl(), {
747
+ method: "POST",
748
+ token: this.token(),
749
+ body: JSON.stringify({ name, ...options })
750
+ });
751
+ }
752
+ /**
753
+ * Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
754
+ * first). Requires the service_role key.
755
+ */
756
+ deleteBucket(name) {
757
+ return request(this.bucketsUrl(name), {
758
+ method: "DELETE",
759
+ token: this.token()
760
+ });
761
+ }
698
762
  };
699
763
 
700
764
  // src/index.ts
@@ -733,6 +797,11 @@ var KividbClient = class {
733
797
  anonKey,
734
798
  session: this.session
735
799
  });
800
+ this.migrations = new MigrationsClient({
801
+ rest: this.endpoints.rest,
802
+ project: this.project,
803
+ key: anonKey
804
+ });
736
805
  this.session.hydrateSync();
737
806
  void this.session.hydrate();
738
807
  }
@@ -741,6 +810,8 @@ var KividbClient = class {
741
810
  auth;
742
811
  realtime;
743
812
  storage;
813
+ /** Schema migrations — requires the client to hold the service key. */
814
+ migrations;
744
815
  project;
745
816
  endpoints;
746
817
  session;
@@ -781,6 +852,7 @@ export {
781
852
  FilterBuilder,
782
853
  FromBuilder,
783
854
  KividbClient,
855
+ MigrationsClient,
784
856
  RealtimeChannel,
785
857
  RealtimeClient,
786
858
  StorageClient,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kividb/client",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "JavaScript/TypeScript client SDK for kividb — typed database queries, auth, realtime, and storage",
5
5
  "license": "MIT",
6
6
  "repository": {