@kividb/client 0.1.1 → 0.1.4
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 +45 -5
- package/dist/index.cjs +49 -3
- package/dist/index.d.cts +44 -3
- package/dist/index.d.ts +44 -3
- package/dist/index.js +49 -3
- package/package.json +1 -1
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 `
|
|
5
|
-
and Node 22+ (uses global `fetch` and `WebSocket`, no runtime
|
|
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
|
|
|
@@ -168,3 +167,44 @@ migrations are immutable (changing an applied name's SQL is a 409; add a new
|
|
|
168
167
|
one instead). Each migration runs in its own transaction as the project owner
|
|
169
168
|
role, with your project schema as the `search_path` — remember to enable RLS
|
|
170
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
|
+
// signed *render* URL — a private-bucket thumbnail usable in an <img> tag:
|
|
184
|
+
const { data: thumb } = await kdb.storage
|
|
185
|
+
.from("private-docs")
|
|
186
|
+
.createSignedUrl("photo.png", 3600, { transform: { width: 128, format: "webp" } });
|
|
187
|
+
kdb.storage.from("avatars").getPublicUrl("user-42/photo.png"); // public buckets
|
|
188
|
+
kdb.storage.from("avatars").getRenderUrl("user-42/photo.png", { width: 128, format: "webp" });
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Buckets
|
|
192
|
+
|
|
193
|
+
Creating and deleting buckets requires the **service key** (server-side only);
|
|
194
|
+
listing and reading bucket metadata work with any key:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
const kdb = createClient(KIVIDB_URL, process.env.KIVIDB_SERVICE_KEY!);
|
|
198
|
+
|
|
199
|
+
await kdb.storage.createBucket("avatars", { public: true });
|
|
200
|
+
await kdb.storage.createBucket("attachments", {
|
|
201
|
+
allowedMimeTypes: ["image/png", "image/jpeg", "application/pdf"],
|
|
202
|
+
maxObjectSize: 10_000_000, // bytes
|
|
203
|
+
});
|
|
204
|
+
|
|
205
|
+
const { data: buckets } = await kdb.storage.listBuckets();
|
|
206
|
+
const { data: bucket } = await kdb.storage.getBucket("attachments");
|
|
207
|
+
await kdb.storage.deleteBucket("attachments"); // 409 unless the bucket is empty
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Bucket names are 2–63 chars: lowercase letters, digits, `.`, `_` or `-`.
|
package/dist/index.cjs
CHANGED
|
@@ -725,9 +725,14 @@ var BucketApi = class {
|
|
|
725
725
|
{ token: this.token() }
|
|
726
726
|
);
|
|
727
727
|
}
|
|
728
|
-
/**
|
|
729
|
-
|
|
730
|
-
|
|
728
|
+
/**
|
|
729
|
+
* Mint a time-boxed signed URL for a private object (default 1 hour). Pass
|
|
730
|
+
* `transform` to get a signed RENDER URL instead — a private-bucket
|
|
731
|
+
* thumbnail that works in an `<img>` tag. The signature covers the object
|
|
732
|
+
* (not the transform), so one token serves any rendition of it.
|
|
733
|
+
*/
|
|
734
|
+
async createSignedUrl(path, expiresIn = 3600, options = {}) {
|
|
735
|
+
const res = await request(
|
|
731
736
|
`${this.ctx.storage}/${this.ctx.project}/sign/${encodeURIComponent(this.bucket)}/${encodePath(path)}`,
|
|
732
737
|
{
|
|
733
738
|
method: "POST",
|
|
@@ -735,6 +740,11 @@ var BucketApi = class {
|
|
|
735
740
|
body: JSON.stringify({ expiresIn })
|
|
736
741
|
}
|
|
737
742
|
);
|
|
743
|
+
if (!res.data || !options.transform) return res;
|
|
744
|
+
const rendered = new URL(this.getRenderUrl(path, options.transform));
|
|
745
|
+
rendered.searchParams.set("exp", String(res.data.exp));
|
|
746
|
+
rendered.searchParams.set("token", res.data.token);
|
|
747
|
+
return { data: { ...res.data, url: rendered.toString() }, error: null };
|
|
738
748
|
}
|
|
739
749
|
/** The token-less public URL for an object in a public bucket. */
|
|
740
750
|
getPublicUrl(path) {
|
|
@@ -761,6 +771,42 @@ var StorageClient = class {
|
|
|
761
771
|
from(bucket) {
|
|
762
772
|
return new BucketApi(this.ctx, bucket);
|
|
763
773
|
}
|
|
774
|
+
token() {
|
|
775
|
+
return this.ctx.session.accessToken() ?? this.ctx.anonKey;
|
|
776
|
+
}
|
|
777
|
+
bucketsUrl(name) {
|
|
778
|
+
const base = `${this.ctx.storage}/${this.ctx.project}/buckets`;
|
|
779
|
+
return name ? `${base}/${encodeURIComponent(name)}` : base;
|
|
780
|
+
}
|
|
781
|
+
/** All buckets in the project (any key; bucket metadata is readable). */
|
|
782
|
+
listBuckets() {
|
|
783
|
+
return request(this.bucketsUrl(), { token: this.token() });
|
|
784
|
+
}
|
|
785
|
+
/** One bucket's metadata, or a 404 error if it doesn't exist. */
|
|
786
|
+
getBucket(name) {
|
|
787
|
+
return request(this.bucketsUrl(name), { token: this.token() });
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Create a bucket. Requires the service_role key. Names are 2–63 chars of
|
|
791
|
+
* lowercase letters, digits, ".", "_" or "-".
|
|
792
|
+
*/
|
|
793
|
+
createBucket(name, options = {}) {
|
|
794
|
+
return request(this.bucketsUrl(), {
|
|
795
|
+
method: "POST",
|
|
796
|
+
token: this.token(),
|
|
797
|
+
body: JSON.stringify({ name, ...options })
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
/**
|
|
801
|
+
* Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
|
|
802
|
+
* first). Requires the service_role key.
|
|
803
|
+
*/
|
|
804
|
+
deleteBucket(name) {
|
|
805
|
+
return request(this.bucketsUrl(name), {
|
|
806
|
+
method: "DELETE",
|
|
807
|
+
token: this.token()
|
|
808
|
+
});
|
|
809
|
+
}
|
|
764
810
|
};
|
|
765
811
|
|
|
766
812
|
// src/index.ts
|
package/dist/index.d.cts
CHANGED
|
@@ -451,6 +451,24 @@ interface SignedUrl {
|
|
|
451
451
|
exp: number;
|
|
452
452
|
expiresAt: string;
|
|
453
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
|
+
}
|
|
454
472
|
interface Ctx {
|
|
455
473
|
storage: string;
|
|
456
474
|
project: string;
|
|
@@ -473,8 +491,15 @@ declare class BucketApi {
|
|
|
473
491
|
}>>;
|
|
474
492
|
/** List objects in the bucket, optionally under a path prefix. */
|
|
475
493
|
list(prefix?: string): Promise<KividbResponse<StorageObjectInfo[]>>;
|
|
476
|
-
/**
|
|
477
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Mint a time-boxed signed URL for a private object (default 1 hour). Pass
|
|
496
|
+
* `transform` to get a signed RENDER URL instead — a private-bucket
|
|
497
|
+
* thumbnail that works in an `<img>` tag. The signature covers the object
|
|
498
|
+
* (not the transform), so one token serves any rendition of it.
|
|
499
|
+
*/
|
|
500
|
+
createSignedUrl(path: string, expiresIn?: number, options?: {
|
|
501
|
+
transform?: TransformOptions;
|
|
502
|
+
}): Promise<KividbResponse<SignedUrl>>;
|
|
478
503
|
/** The token-less public URL for an object in a public bucket. */
|
|
479
504
|
getPublicUrl(path: string): string;
|
|
480
505
|
/** A transform (render) URL — resize/reformat an image on the fly. */
|
|
@@ -485,6 +510,22 @@ declare class StorageClient {
|
|
|
485
510
|
constructor(ctx: Ctx);
|
|
486
511
|
/** Operate on a bucket. */
|
|
487
512
|
from(bucket: string): BucketApi;
|
|
513
|
+
private token;
|
|
514
|
+
private bucketsUrl;
|
|
515
|
+
/** All buckets in the project (any key; bucket metadata is readable). */
|
|
516
|
+
listBuckets(): Promise<KividbResponse<BucketInfo[]>>;
|
|
517
|
+
/** One bucket's metadata, or a 404 error if it doesn't exist. */
|
|
518
|
+
getBucket(name: string): Promise<KividbResponse<BucketInfo>>;
|
|
519
|
+
/**
|
|
520
|
+
* Create a bucket. Requires the service_role key. Names are 2–63 chars of
|
|
521
|
+
* lowercase letters, digits, ".", "_" or "-".
|
|
522
|
+
*/
|
|
523
|
+
createBucket(name: string, options?: CreateBucketOptions): Promise<KividbResponse<BucketInfo>>;
|
|
524
|
+
/**
|
|
525
|
+
* Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
|
|
526
|
+
* first). Requires the service_role key.
|
|
527
|
+
*/
|
|
528
|
+
deleteBucket(name: string): Promise<KividbResponse<null>>;
|
|
488
529
|
}
|
|
489
530
|
|
|
490
531
|
/**
|
|
@@ -544,4 +585,4 @@ declare function createServerClient(url: string, anonKey: string, options: Omit<
|
|
|
544
585
|
cookies: CookieMethods;
|
|
545
586
|
}): KividbClient;
|
|
546
587
|
|
|
547
|
-
export { type AppliedMigration, type ApplyMigrationsResult, AuthClient, type AuthEvent, type AuthListener, type ClientOptions, type CookieMethods, type CookieOptions, 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 };
|
|
588
|
+
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
|
@@ -451,6 +451,24 @@ interface SignedUrl {
|
|
|
451
451
|
exp: number;
|
|
452
452
|
expiresAt: string;
|
|
453
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
|
+
}
|
|
454
472
|
interface Ctx {
|
|
455
473
|
storage: string;
|
|
456
474
|
project: string;
|
|
@@ -473,8 +491,15 @@ declare class BucketApi {
|
|
|
473
491
|
}>>;
|
|
474
492
|
/** List objects in the bucket, optionally under a path prefix. */
|
|
475
493
|
list(prefix?: string): Promise<KividbResponse<StorageObjectInfo[]>>;
|
|
476
|
-
/**
|
|
477
|
-
|
|
494
|
+
/**
|
|
495
|
+
* Mint a time-boxed signed URL for a private object (default 1 hour). Pass
|
|
496
|
+
* `transform` to get a signed RENDER URL instead — a private-bucket
|
|
497
|
+
* thumbnail that works in an `<img>` tag. The signature covers the object
|
|
498
|
+
* (not the transform), so one token serves any rendition of it.
|
|
499
|
+
*/
|
|
500
|
+
createSignedUrl(path: string, expiresIn?: number, options?: {
|
|
501
|
+
transform?: TransformOptions;
|
|
502
|
+
}): Promise<KividbResponse<SignedUrl>>;
|
|
478
503
|
/** The token-less public URL for an object in a public bucket. */
|
|
479
504
|
getPublicUrl(path: string): string;
|
|
480
505
|
/** A transform (render) URL — resize/reformat an image on the fly. */
|
|
@@ -485,6 +510,22 @@ declare class StorageClient {
|
|
|
485
510
|
constructor(ctx: Ctx);
|
|
486
511
|
/** Operate on a bucket. */
|
|
487
512
|
from(bucket: string): BucketApi;
|
|
513
|
+
private token;
|
|
514
|
+
private bucketsUrl;
|
|
515
|
+
/** All buckets in the project (any key; bucket metadata is readable). */
|
|
516
|
+
listBuckets(): Promise<KividbResponse<BucketInfo[]>>;
|
|
517
|
+
/** One bucket's metadata, or a 404 error if it doesn't exist. */
|
|
518
|
+
getBucket(name: string): Promise<KividbResponse<BucketInfo>>;
|
|
519
|
+
/**
|
|
520
|
+
* Create a bucket. Requires the service_role key. Names are 2–63 chars of
|
|
521
|
+
* lowercase letters, digits, ".", "_" or "-".
|
|
522
|
+
*/
|
|
523
|
+
createBucket(name: string, options?: CreateBucketOptions): Promise<KividbResponse<BucketInfo>>;
|
|
524
|
+
/**
|
|
525
|
+
* Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
|
|
526
|
+
* first). Requires the service_role key.
|
|
527
|
+
*/
|
|
528
|
+
deleteBucket(name: string): Promise<KividbResponse<null>>;
|
|
488
529
|
}
|
|
489
530
|
|
|
490
531
|
/**
|
|
@@ -544,4 +585,4 @@ declare function createServerClient(url: string, anonKey: string, options: Omit<
|
|
|
544
585
|
cookies: CookieMethods;
|
|
545
586
|
}): KividbClient;
|
|
546
587
|
|
|
547
|
-
export { type AppliedMigration, type ApplyMigrationsResult, AuthClient, type AuthEvent, type AuthListener, type ClientOptions, type CookieMethods, type CookieOptions, 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 };
|
|
588
|
+
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
|
@@ -687,9 +687,14 @@ var BucketApi = class {
|
|
|
687
687
|
{ token: this.token() }
|
|
688
688
|
);
|
|
689
689
|
}
|
|
690
|
-
/**
|
|
691
|
-
|
|
692
|
-
|
|
690
|
+
/**
|
|
691
|
+
* Mint a time-boxed signed URL for a private object (default 1 hour). Pass
|
|
692
|
+
* `transform` to get a signed RENDER URL instead — a private-bucket
|
|
693
|
+
* thumbnail that works in an `<img>` tag. The signature covers the object
|
|
694
|
+
* (not the transform), so one token serves any rendition of it.
|
|
695
|
+
*/
|
|
696
|
+
async createSignedUrl(path, expiresIn = 3600, options = {}) {
|
|
697
|
+
const res = await request(
|
|
693
698
|
`${this.ctx.storage}/${this.ctx.project}/sign/${encodeURIComponent(this.bucket)}/${encodePath(path)}`,
|
|
694
699
|
{
|
|
695
700
|
method: "POST",
|
|
@@ -697,6 +702,11 @@ var BucketApi = class {
|
|
|
697
702
|
body: JSON.stringify({ expiresIn })
|
|
698
703
|
}
|
|
699
704
|
);
|
|
705
|
+
if (!res.data || !options.transform) return res;
|
|
706
|
+
const rendered = new URL(this.getRenderUrl(path, options.transform));
|
|
707
|
+
rendered.searchParams.set("exp", String(res.data.exp));
|
|
708
|
+
rendered.searchParams.set("token", res.data.token);
|
|
709
|
+
return { data: { ...res.data, url: rendered.toString() }, error: null };
|
|
700
710
|
}
|
|
701
711
|
/** The token-less public URL for an object in a public bucket. */
|
|
702
712
|
getPublicUrl(path) {
|
|
@@ -723,6 +733,42 @@ var StorageClient = class {
|
|
|
723
733
|
from(bucket) {
|
|
724
734
|
return new BucketApi(this.ctx, bucket);
|
|
725
735
|
}
|
|
736
|
+
token() {
|
|
737
|
+
return this.ctx.session.accessToken() ?? this.ctx.anonKey;
|
|
738
|
+
}
|
|
739
|
+
bucketsUrl(name) {
|
|
740
|
+
const base = `${this.ctx.storage}/${this.ctx.project}/buckets`;
|
|
741
|
+
return name ? `${base}/${encodeURIComponent(name)}` : base;
|
|
742
|
+
}
|
|
743
|
+
/** All buckets in the project (any key; bucket metadata is readable). */
|
|
744
|
+
listBuckets() {
|
|
745
|
+
return request(this.bucketsUrl(), { token: this.token() });
|
|
746
|
+
}
|
|
747
|
+
/** One bucket's metadata, or a 404 error if it doesn't exist. */
|
|
748
|
+
getBucket(name) {
|
|
749
|
+
return request(this.bucketsUrl(name), { token: this.token() });
|
|
750
|
+
}
|
|
751
|
+
/**
|
|
752
|
+
* Create a bucket. Requires the service_role key. Names are 2–63 chars of
|
|
753
|
+
* lowercase letters, digits, ".", "_" or "-".
|
|
754
|
+
*/
|
|
755
|
+
createBucket(name, options = {}) {
|
|
756
|
+
return request(this.bucketsUrl(), {
|
|
757
|
+
method: "POST",
|
|
758
|
+
token: this.token(),
|
|
759
|
+
body: JSON.stringify({ name, ...options })
|
|
760
|
+
});
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* Delete an empty bucket (a non-empty bucket is a 409 — remove its objects
|
|
764
|
+
* first). Requires the service_role key.
|
|
765
|
+
*/
|
|
766
|
+
deleteBucket(name) {
|
|
767
|
+
return request(this.bucketsUrl(name), {
|
|
768
|
+
method: "DELETE",
|
|
769
|
+
token: this.token()
|
|
770
|
+
});
|
|
771
|
+
}
|
|
726
772
|
};
|
|
727
773
|
|
|
728
774
|
// src/index.ts
|