@keeprer/js 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/README.md +111 -0
- package/dist/index.d.ts +136 -0
- package/dist/index.js +260 -0
- package/package.json +38 -0
package/README.md
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# @keeprer/js
|
|
2
|
+
|
|
3
|
+
Official TypeScript / JavaScript client for [Keeprer](https://keeprer.space) — The Lightweight No-Code Database & Headless Backend.
|
|
4
|
+
|
|
5
|
+
## 📦 Features
|
|
6
|
+
|
|
7
|
+
- ⚡ **Zero Dependencies**: Powered by native `fetch`.
|
|
8
|
+
- 🛡️ **Full TypeScript Support**: Auto-complete and type inference.
|
|
9
|
+
- 🎯 **Fluent Supabase-style API**: Chain filters like `.eq()`, `.gt()`, `.sort()`, `.limit()`.
|
|
10
|
+
- 🔐 **Scoped API Keys**: Supports `pk_` (publishable/read-only) and `sk_` (secret/read-write).
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
## 🚀 Quick Start
|
|
15
|
+
|
|
16
|
+
### Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @keeprer/js
|
|
20
|
+
# or yarn add @keeprer/js
|
|
21
|
+
# or pnpm add @keeprer/js
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Initialize Client
|
|
25
|
+
|
|
26
|
+
```typescript
|
|
27
|
+
import { createClient } from "@keeprer/js"
|
|
28
|
+
|
|
29
|
+
const keeprer = createClient("https://keeprer.space", "pk_xxxxxxxxxxxx")
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
## 📖 Usage Examples
|
|
35
|
+
|
|
36
|
+
### 1. Query Records (Select & Filter)
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
// Query products where status is active and price > 100
|
|
40
|
+
const { data, total, error } = await keeprer
|
|
41
|
+
.from("products")
|
|
42
|
+
.select()
|
|
43
|
+
.eq("status", "active")
|
|
44
|
+
.gt("price", 100)
|
|
45
|
+
.sort("-created_at")
|
|
46
|
+
.limit(20)
|
|
47
|
+
|
|
48
|
+
console.log(data) // [{ id: "...", name: "Shirt", price: 350, ... }]
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### 2. Insert Records (Create)
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
// Insert single row
|
|
55
|
+
const { data: item, error } = await keeprer
|
|
56
|
+
.from("products")
|
|
57
|
+
.insert({
|
|
58
|
+
name: "เสื้อยืด Keeprer",
|
|
59
|
+
price: 350,
|
|
60
|
+
status: "in_stock",
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
// Batch insert up to 500 rows
|
|
64
|
+
const { data: items } = await keeprer
|
|
65
|
+
.from("products")
|
|
66
|
+
.insert([
|
|
67
|
+
{ name: "Item 1", price: 100 },
|
|
68
|
+
{ name: "Item 2", price: 200 },
|
|
69
|
+
])
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
### 3. Update Record (Patch)
|
|
73
|
+
|
|
74
|
+
```typescript
|
|
75
|
+
const { data: updated, error } = await keeprer
|
|
76
|
+
.from("products")
|
|
77
|
+
.update("row_uuid_here", {
|
|
78
|
+
price: 290,
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 4. Delete Record (Delete)
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
const { success, error } = await keeprer
|
|
86
|
+
.from("products")
|
|
87
|
+
.delete("row_uuid_here")
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### 5. Inspect Schema
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
const { table, fields } = await keeprer
|
|
94
|
+
.from("products")
|
|
95
|
+
.schema()
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
---
|
|
99
|
+
|
|
100
|
+
## 🔑 Security Best Practices
|
|
101
|
+
|
|
102
|
+
- **Frontend (React, Next.js client, Vue, Mobile apps)**:
|
|
103
|
+
Always use a publishable key starting with `pk_...` or toggle the table to **Public** mode in Keeprer.
|
|
104
|
+
- **Backend (Node.js, Express, Next.js Server Actions, Python)**:
|
|
105
|
+
Use a secret key starting with `sk_...` kept securely in environment variables.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 📄 License
|
|
110
|
+
|
|
111
|
+
MIT © Keeprer Team
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
export interface KeeprerClientOptions {
|
|
2
|
+
baseUrl: string;
|
|
3
|
+
apiKey?: string;
|
|
4
|
+
fetch?: typeof globalThis.fetch;
|
|
5
|
+
}
|
|
6
|
+
export interface KeeprerError {
|
|
7
|
+
message: string;
|
|
8
|
+
status?: number;
|
|
9
|
+
code?: string;
|
|
10
|
+
}
|
|
11
|
+
export interface QueryResponse<T = Record<string, unknown>> {
|
|
12
|
+
data: T[];
|
|
13
|
+
total: number;
|
|
14
|
+
hasMore: boolean;
|
|
15
|
+
cursor: number | null;
|
|
16
|
+
error: KeeprerError | null;
|
|
17
|
+
}
|
|
18
|
+
export interface SingleResponse<T = Record<string, unknown>> {
|
|
19
|
+
data: T | null;
|
|
20
|
+
error: KeeprerError | null;
|
|
21
|
+
}
|
|
22
|
+
export interface DeleteResponse {
|
|
23
|
+
success: boolean;
|
|
24
|
+
error: KeeprerError | null;
|
|
25
|
+
}
|
|
26
|
+
export interface ColumnSchema {
|
|
27
|
+
id: string;
|
|
28
|
+
name: string;
|
|
29
|
+
key: string;
|
|
30
|
+
type: string;
|
|
31
|
+
options?: string[];
|
|
32
|
+
}
|
|
33
|
+
export interface TableSchemaResponse {
|
|
34
|
+
table: {
|
|
35
|
+
id: string;
|
|
36
|
+
name: string;
|
|
37
|
+
is_public: boolean;
|
|
38
|
+
};
|
|
39
|
+
fields: ColumnSchema[];
|
|
40
|
+
error: KeeprerError | null;
|
|
41
|
+
}
|
|
42
|
+
export declare class QueryBuilder<T = Record<string, unknown>> implements PromiseLike<QueryResponse<T>> {
|
|
43
|
+
private client;
|
|
44
|
+
private tableId;
|
|
45
|
+
private filters;
|
|
46
|
+
private sortField;
|
|
47
|
+
private limitCount;
|
|
48
|
+
private offsetCount;
|
|
49
|
+
constructor(client: KeeprerClient, tableId: string);
|
|
50
|
+
select(_columns?: string): this;
|
|
51
|
+
eq(column: string, value: unknown): this;
|
|
52
|
+
neq(column: string, value: unknown): this;
|
|
53
|
+
contains(column: string, value: unknown): this;
|
|
54
|
+
gt(column: string, value: number | string): this;
|
|
55
|
+
gte(column: string, value: number | string): this;
|
|
56
|
+
lt(column: string, value: number | string): this;
|
|
57
|
+
lte(column: string, value: number | string): this;
|
|
58
|
+
sort(field: string): this;
|
|
59
|
+
order(field: string, options?: {
|
|
60
|
+
ascending?: boolean;
|
|
61
|
+
}): this;
|
|
62
|
+
limit(count: number): this;
|
|
63
|
+
offset(count: number): this;
|
|
64
|
+
execute(): Promise<QueryResponse<T>>;
|
|
65
|
+
then<TResult1 = QueryResponse<T>, TResult2 = never>(onfulfilled?: ((value: QueryResponse<T>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
66
|
+
}
|
|
67
|
+
export declare class TableClient<T = Record<string, unknown>> {
|
|
68
|
+
private client;
|
|
69
|
+
private tableId;
|
|
70
|
+
constructor(client: KeeprerClient, tableId: string);
|
|
71
|
+
/**
|
|
72
|
+
* Start a query chain.
|
|
73
|
+
* e.g. `client.from("products").select().eq("status", "active")`
|
|
74
|
+
*/
|
|
75
|
+
select(columns?: string): QueryBuilder<T>;
|
|
76
|
+
/**
|
|
77
|
+
* Fetch a single row by its ID.
|
|
78
|
+
*/
|
|
79
|
+
get(id: string): Promise<SingleResponse<T>>;
|
|
80
|
+
/**
|
|
81
|
+
* Insert one or multiple rows.
|
|
82
|
+
* e.g. `client.from("products").insert({ name: "Shoes", price: 500 })`
|
|
83
|
+
*/
|
|
84
|
+
insert(rowOrRows: Partial<T> | Partial<T>[]): Promise<SingleResponse<T | T[]>>;
|
|
85
|
+
/**
|
|
86
|
+
* Update an existing row by ID.
|
|
87
|
+
* e.g. `client.from("products").update("row_123", { price: 450 })`
|
|
88
|
+
*/
|
|
89
|
+
update(id: string, values: Partial<T>): Promise<SingleResponse<T>>;
|
|
90
|
+
/**
|
|
91
|
+
* Delete a row by ID.
|
|
92
|
+
* e.g. `client.from("products").delete("row_123")`
|
|
93
|
+
*/
|
|
94
|
+
delete(id: string): Promise<DeleteResponse>;
|
|
95
|
+
/**
|
|
96
|
+
* Fetch table column schema and metadata.
|
|
97
|
+
*/
|
|
98
|
+
schema(): Promise<TableSchemaResponse>;
|
|
99
|
+
}
|
|
100
|
+
export declare class KeeprerClient {
|
|
101
|
+
private baseUrl;
|
|
102
|
+
private apiKey?;
|
|
103
|
+
private customFetch;
|
|
104
|
+
constructor(options: KeeprerClientOptions | string, apiKey?: string);
|
|
105
|
+
/**
|
|
106
|
+
* Access a table by its Table ID or name.
|
|
107
|
+
*/
|
|
108
|
+
from<T = Record<string, unknown>>(tableId: string): TableClient<T>;
|
|
109
|
+
/**
|
|
110
|
+
* Export the entire workspace data as JSON.
|
|
111
|
+
*/
|
|
112
|
+
exportWorkspace(workspaceId: string): Promise<{
|
|
113
|
+
data: any;
|
|
114
|
+
error: KeeprerError | null;
|
|
115
|
+
}>;
|
|
116
|
+
/**
|
|
117
|
+
* Internal HTTP request handler.
|
|
118
|
+
*/
|
|
119
|
+
request(path: string, options?: RequestInit): Promise<{
|
|
120
|
+
data?: any;
|
|
121
|
+
error: KeeprerError | null;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Factory function to create a new Keeprer client instance.
|
|
126
|
+
*
|
|
127
|
+
* @example
|
|
128
|
+
* ```typescript
|
|
129
|
+
* import { createClient } from "@keeprer/js"
|
|
130
|
+
*
|
|
131
|
+
* const keeprer = createClient("https://keeprer.space", "pk_xxxxxxxxxxxx")
|
|
132
|
+
* const { data, total } = await keeprer.from("products").select().eq("status", "active")
|
|
133
|
+
* ```
|
|
134
|
+
*/
|
|
135
|
+
export declare function createClient(baseUrlOrOptions: string | KeeprerClientOptions, apiKey?: string): KeeprerClient;
|
|
136
|
+
export default createClient;
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
// Keeprer Client SDK (@keeprer/js)
|
|
2
|
+
//
|
|
3
|
+
// A lightweight, zero-dependency, type-safe client library for Keeprer Headless Database.
|
|
4
|
+
// Designed with a fluent Supabase-style query builder interface.
|
|
5
|
+
//
|
|
6
|
+
// Usage:
|
|
7
|
+
// import { createClient } from "@keeprer/js"
|
|
8
|
+
// const keeprer = createClient("https://keeprer.space", "pk_xxxxxxxxxxxx")
|
|
9
|
+
// const { data, total } = await keeprer.from("products").select().eq("status", "active").limit(10)
|
|
10
|
+
export class QueryBuilder {
|
|
11
|
+
client;
|
|
12
|
+
tableId;
|
|
13
|
+
filters = [];
|
|
14
|
+
sortField = null;
|
|
15
|
+
limitCount = 100;
|
|
16
|
+
offsetCount = 0;
|
|
17
|
+
constructor(client, tableId) {
|
|
18
|
+
this.client = client;
|
|
19
|
+
this.tableId = tableId;
|
|
20
|
+
}
|
|
21
|
+
select(_columns) {
|
|
22
|
+
// Keeprer returns all columns by default, columns parameter reserved for projections
|
|
23
|
+
return this;
|
|
24
|
+
}
|
|
25
|
+
eq(column, value) {
|
|
26
|
+
this.filters.push(`${column}.eq.${encodeURIComponent(String(value))}`);
|
|
27
|
+
return this;
|
|
28
|
+
}
|
|
29
|
+
neq(column, value) {
|
|
30
|
+
this.filters.push(`${column}.neq.${encodeURIComponent(String(value))}`);
|
|
31
|
+
return this;
|
|
32
|
+
}
|
|
33
|
+
contains(column, value) {
|
|
34
|
+
this.filters.push(`${column}.contains.${encodeURIComponent(String(value))}`);
|
|
35
|
+
return this;
|
|
36
|
+
}
|
|
37
|
+
gt(column, value) {
|
|
38
|
+
this.filters.push(`${column}.gt.${encodeURIComponent(String(value))}`);
|
|
39
|
+
return this;
|
|
40
|
+
}
|
|
41
|
+
gte(column, value) {
|
|
42
|
+
this.filters.push(`${column}.gte.${encodeURIComponent(String(value))}`);
|
|
43
|
+
return this;
|
|
44
|
+
}
|
|
45
|
+
lt(column, value) {
|
|
46
|
+
this.filters.push(`${column}.lt.${encodeURIComponent(String(value))}`);
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
lte(column, value) {
|
|
50
|
+
this.filters.push(`${column}.lte.${encodeURIComponent(String(value))}`);
|
|
51
|
+
return this;
|
|
52
|
+
}
|
|
53
|
+
sort(field) {
|
|
54
|
+
this.sortField = field;
|
|
55
|
+
return this;
|
|
56
|
+
}
|
|
57
|
+
order(field, options) {
|
|
58
|
+
this.sortField = options?.ascending === false ? `-${field}` : field;
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
limit(count) {
|
|
62
|
+
this.limitCount = Math.max(1, Math.min(1000, count));
|
|
63
|
+
return this;
|
|
64
|
+
}
|
|
65
|
+
offset(count) {
|
|
66
|
+
this.offsetCount = Math.max(0, count);
|
|
67
|
+
return this;
|
|
68
|
+
}
|
|
69
|
+
async execute() {
|
|
70
|
+
const params = new URLSearchParams();
|
|
71
|
+
if (this.filters.length > 0) {
|
|
72
|
+
params.set("where", this.filters.join(","));
|
|
73
|
+
}
|
|
74
|
+
if (this.sortField) {
|
|
75
|
+
params.set("sort", this.sortField);
|
|
76
|
+
}
|
|
77
|
+
params.set("limit", String(this.limitCount));
|
|
78
|
+
params.set("offset", String(this.offsetCount));
|
|
79
|
+
const path = `/v1/t/${encodeURIComponent(this.tableId)}/rows?${params.toString()}`;
|
|
80
|
+
const res = await this.client.request(path, { method: "GET" });
|
|
81
|
+
if (res.error) {
|
|
82
|
+
return { data: [], total: 0, hasMore: false, cursor: null, error: res.error };
|
|
83
|
+
}
|
|
84
|
+
return {
|
|
85
|
+
data: res.data?.rows || [],
|
|
86
|
+
total: res.data?.total || 0,
|
|
87
|
+
hasMore: !!res.data?.hasMore,
|
|
88
|
+
cursor: res.data?.cursor ?? null,
|
|
89
|
+
error: null,
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
then(onfulfilled, onrejected) {
|
|
93
|
+
return this.execute().then(onfulfilled, onrejected);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
export class TableClient {
|
|
97
|
+
client;
|
|
98
|
+
tableId;
|
|
99
|
+
constructor(client, tableId) {
|
|
100
|
+
this.client = client;
|
|
101
|
+
this.tableId = tableId;
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Start a query chain.
|
|
105
|
+
* e.g. `client.from("products").select().eq("status", "active")`
|
|
106
|
+
*/
|
|
107
|
+
select(columns) {
|
|
108
|
+
const q = new QueryBuilder(this.client, this.tableId);
|
|
109
|
+
return q.select(columns);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* Fetch a single row by its ID.
|
|
113
|
+
*/
|
|
114
|
+
async get(id) {
|
|
115
|
+
const res = await this.client.request(`/v1/t/${encodeURIComponent(this.tableId)}/rows/${encodeURIComponent(id)}`, {
|
|
116
|
+
method: "GET",
|
|
117
|
+
});
|
|
118
|
+
if (res.error)
|
|
119
|
+
return { data: null, error: res.error };
|
|
120
|
+
return { data: res.data, error: null };
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Insert one or multiple rows.
|
|
124
|
+
* e.g. `client.from("products").insert({ name: "Shoes", price: 500 })`
|
|
125
|
+
*/
|
|
126
|
+
async insert(rowOrRows) {
|
|
127
|
+
const payload = Array.isArray(rowOrRows) ? { rows: rowOrRows } : rowOrRows;
|
|
128
|
+
const res = await this.client.request(`/v1/t/${encodeURIComponent(this.tableId)}/rows`, {
|
|
129
|
+
method: "POST",
|
|
130
|
+
body: JSON.stringify(payload),
|
|
131
|
+
});
|
|
132
|
+
if (res.error)
|
|
133
|
+
return { data: null, error: res.error };
|
|
134
|
+
return { data: res.data, error: null };
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Update an existing row by ID.
|
|
138
|
+
* e.g. `client.from("products").update("row_123", { price: 450 })`
|
|
139
|
+
*/
|
|
140
|
+
async update(id, values) {
|
|
141
|
+
const res = await this.client.request(`/v1/t/${encodeURIComponent(this.tableId)}/rows/${encodeURIComponent(id)}`, {
|
|
142
|
+
method: "PATCH",
|
|
143
|
+
body: JSON.stringify(values),
|
|
144
|
+
});
|
|
145
|
+
if (res.error)
|
|
146
|
+
return { data: null, error: res.error };
|
|
147
|
+
return { data: res.data, error: null };
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Delete a row by ID.
|
|
151
|
+
* e.g. `client.from("products").delete("row_123")`
|
|
152
|
+
*/
|
|
153
|
+
async delete(id) {
|
|
154
|
+
const res = await this.client.request(`/v1/t/${encodeURIComponent(this.tableId)}/rows/${encodeURIComponent(id)}`, {
|
|
155
|
+
method: "DELETE",
|
|
156
|
+
});
|
|
157
|
+
if (res.error)
|
|
158
|
+
return { success: false, error: res.error };
|
|
159
|
+
return { success: true, error: null };
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Fetch table column schema and metadata.
|
|
163
|
+
*/
|
|
164
|
+
async schema() {
|
|
165
|
+
const res = await this.client.request(`/v1/t/${encodeURIComponent(this.tableId)}/schema`, {
|
|
166
|
+
method: "GET",
|
|
167
|
+
});
|
|
168
|
+
if (res.error) {
|
|
169
|
+
return { table: { id: this.tableId, name: "", is_public: false }, fields: [], error: res.error };
|
|
170
|
+
}
|
|
171
|
+
return { table: res.data.table, fields: res.data.fields, error: null };
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
export class KeeprerClient {
|
|
175
|
+
baseUrl;
|
|
176
|
+
apiKey;
|
|
177
|
+
customFetch;
|
|
178
|
+
constructor(options, apiKey) {
|
|
179
|
+
if (typeof options === "string") {
|
|
180
|
+
this.baseUrl = options.replace(/\/+$/, "");
|
|
181
|
+
this.apiKey = apiKey;
|
|
182
|
+
this.customFetch = globalThis.fetch.bind(globalThis);
|
|
183
|
+
}
|
|
184
|
+
else {
|
|
185
|
+
this.baseUrl = options.baseUrl.replace(/\/+$/, "");
|
|
186
|
+
this.apiKey = options.apiKey || apiKey;
|
|
187
|
+
this.customFetch = options.fetch || globalThis.fetch.bind(globalThis);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Access a table by its Table ID or name.
|
|
192
|
+
*/
|
|
193
|
+
from(tableId) {
|
|
194
|
+
return new TableClient(this, tableId);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* Export the entire workspace data as JSON.
|
|
198
|
+
*/
|
|
199
|
+
async exportWorkspace(workspaceId) {
|
|
200
|
+
const res = await this.request(`/v1/workspaces/${encodeURIComponent(workspaceId)}/export`, { method: "GET" });
|
|
201
|
+
return { data: res.data, error: res.error };
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Internal HTTP request handler.
|
|
205
|
+
*/
|
|
206
|
+
async request(path, options = {}) {
|
|
207
|
+
const url = `${this.baseUrl}${path.startsWith("/") ? path : `/${path}`}`;
|
|
208
|
+
const headers = {
|
|
209
|
+
Accept: "application/json",
|
|
210
|
+
...(this.apiKey ? { Authorization: `Bearer ${this.apiKey}` } : {}),
|
|
211
|
+
...options.headers,
|
|
212
|
+
};
|
|
213
|
+
if (options.body && !headers["Content-Type"]) {
|
|
214
|
+
headers["Content-Type"] = "application/json";
|
|
215
|
+
}
|
|
216
|
+
try {
|
|
217
|
+
const response = await this.customFetch(url, {
|
|
218
|
+
...options,
|
|
219
|
+
headers,
|
|
220
|
+
});
|
|
221
|
+
if (response.status === 204) {
|
|
222
|
+
return { error: null };
|
|
223
|
+
}
|
|
224
|
+
const json = await response.json().catch(() => ({}));
|
|
225
|
+
if (!response.ok) {
|
|
226
|
+
return {
|
|
227
|
+
error: {
|
|
228
|
+
message: json.error || response.statusText || "Request failed",
|
|
229
|
+
status: response.status,
|
|
230
|
+
code: json.code,
|
|
231
|
+
},
|
|
232
|
+
};
|
|
233
|
+
}
|
|
234
|
+
return { data: json, error: null };
|
|
235
|
+
}
|
|
236
|
+
catch (err) {
|
|
237
|
+
return {
|
|
238
|
+
error: {
|
|
239
|
+
message: err.message || "Network error",
|
|
240
|
+
status: 0,
|
|
241
|
+
},
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Factory function to create a new Keeprer client instance.
|
|
248
|
+
*
|
|
249
|
+
* @example
|
|
250
|
+
* ```typescript
|
|
251
|
+
* import { createClient } from "@keeprer/js"
|
|
252
|
+
*
|
|
253
|
+
* const keeprer = createClient("https://keeprer.space", "pk_xxxxxxxxxxxx")
|
|
254
|
+
* const { data, total } = await keeprer.from("products").select().eq("status", "active")
|
|
255
|
+
* ```
|
|
256
|
+
*/
|
|
257
|
+
export function createClient(baseUrlOrOptions, apiKey) {
|
|
258
|
+
return new KeeprerClient(baseUrlOrOptions, apiKey);
|
|
259
|
+
}
|
|
260
|
+
export default createClient;
|
package/package.json
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@keeprer/js",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Official TypeScript & JavaScript client for Keeprer Headless Database",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"module": "dist/index.js",
|
|
8
|
+
"types": "dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"files": [
|
|
17
|
+
"dist",
|
|
18
|
+
"README.md"
|
|
19
|
+
],
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc ../../lib/sdk/index.ts --declaration --target es2022 --module esnext --moduleResolution bundler --outDir dist"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"keeprer",
|
|
25
|
+
"database",
|
|
26
|
+
"headless",
|
|
27
|
+
"no-code",
|
|
28
|
+
"supabase",
|
|
29
|
+
"rest",
|
|
30
|
+
"sdk"
|
|
31
|
+
],
|
|
32
|
+
"author": "Keeprer Team",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "https://github.com/ikarisz/Keeprer"
|
|
37
|
+
}
|
|
38
|
+
}
|