@firekid/forgedb 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/README.md +191 -0
- package/dist/index.d.mts +131 -0
- package/dist/index.d.ts +131 -0
- package/dist/index.js +226 -0
- package/dist/index.mjs +188 -0
- package/package.json +29 -0
package/README.md
ADDED
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
# @firekid/forgedb
|
|
2
|
+
|
|
3
|
+
[](https://npmjs.com/package/@firekid/forgedb)
|
|
4
|
+
[](LICENSE)
|
|
5
|
+
|
|
6
|
+
Official JavaScript/TypeScript client for [ForgeDB](https://forgedb.name.ng). Powered by [`@firekid/hurl`](https://npmjs.com/package/@firekid/hurl) — zero extra dependencies.
|
|
7
|
+
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
## Install
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @firekid/forgedb
|
|
14
|
+
pnpm add @firekid/forgedb
|
|
15
|
+
yarn add @firekid/forgedb
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
---
|
|
19
|
+
|
|
20
|
+
## Quick Start
|
|
21
|
+
|
|
22
|
+
```ts
|
|
23
|
+
import { createClient } from '@firekid/forgedb'
|
|
24
|
+
|
|
25
|
+
const db = createClient({
|
|
26
|
+
projectId: 'your-project-id',
|
|
27
|
+
apiKey: 'sk_live_...',
|
|
28
|
+
})
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Get your `projectId` and `apiKey` from the [ForgeDB dashboard](https://forgedb.name.ng/app/keys).
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Selecting Rows
|
|
36
|
+
|
|
37
|
+
```ts
|
|
38
|
+
const { rows, total, totalPages } = await db.from('users').select()
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Filter
|
|
42
|
+
|
|
43
|
+
```ts
|
|
44
|
+
// Equality shorthand
|
|
45
|
+
const { rows } = await db.from('users').where('active', true).select()
|
|
46
|
+
|
|
47
|
+
// With operator — supports: = | != | > | < | >= | <= | like | in
|
|
48
|
+
const { rows } = await db.from('users').where('age', '>', 18).select()
|
|
49
|
+
|
|
50
|
+
// Chain multiple filters (AND)
|
|
51
|
+
const { rows } = await db.from('users')
|
|
52
|
+
.where('active', true)
|
|
53
|
+
.where('age', '>=', 18)
|
|
54
|
+
.select()
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
### Pagination
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
const { rows } = await db.from('users').page(2).limit(20).select()
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Search
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
const { rows } = await db.from('users').search('john').select()
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Sort
|
|
70
|
+
|
|
71
|
+
```ts
|
|
72
|
+
const { rows } = await db.from('users').orderBy('createdAt', 'desc').select()
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### Get by ID
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
const user = await db.from('users').selectById(1)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
---
|
|
82
|
+
|
|
83
|
+
## Mutating Rows
|
|
84
|
+
|
|
85
|
+
### Insert
|
|
86
|
+
|
|
87
|
+
```ts
|
|
88
|
+
const user = await db.from('users').insert({
|
|
89
|
+
name: 'John Doe',
|
|
90
|
+
email: 'john@example.com',
|
|
91
|
+
})
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Update
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
const user = await db.from('users').update(1, { name: 'Jane Doe' })
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
### Delete
|
|
101
|
+
|
|
102
|
+
```ts
|
|
103
|
+
await db.from('users').delete(1)
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Bulk Delete
|
|
107
|
+
|
|
108
|
+
```ts
|
|
109
|
+
await db.from('users').bulkDelete([1, 2, 3])
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
---
|
|
113
|
+
|
|
114
|
+
## Raw SQL
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
// Single statement
|
|
118
|
+
const result = await db.sql('SELECT * FROM users WHERE age > 18')
|
|
119
|
+
console.log(result.rows)
|
|
120
|
+
|
|
121
|
+
// Multiple statements
|
|
122
|
+
const result = await db.sql(`
|
|
123
|
+
INSERT INTO logs (event) VALUES ('signup');
|
|
124
|
+
SELECT COUNT(*) as total FROM users;
|
|
125
|
+
`)
|
|
126
|
+
console.log(result.statements) // 2
|
|
127
|
+
console.log(result.message) // "2 statements executed · 1 row affected"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## TypeScript
|
|
133
|
+
|
|
134
|
+
```ts
|
|
135
|
+
interface User {
|
|
136
|
+
id: number
|
|
137
|
+
name: string
|
|
138
|
+
email: string
|
|
139
|
+
age: number
|
|
140
|
+
active: boolean
|
|
141
|
+
createdAt: string
|
|
142
|
+
updatedAt: string
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
const { rows } = await db.from<User>('users').select()
|
|
146
|
+
// rows → User[]
|
|
147
|
+
|
|
148
|
+
const user = await db.from<User>('users').selectById(1)
|
|
149
|
+
// user → User
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
---
|
|
153
|
+
|
|
154
|
+
## Environments
|
|
155
|
+
|
|
156
|
+
The client automatically detects the environment from your API key:
|
|
157
|
+
|
|
158
|
+
| Key prefix | Environment |
|
|
159
|
+
|-------------------|-------------|
|
|
160
|
+
| `sk_live_` / `fk_live_` | `prod` |
|
|
161
|
+
| `sk_test_` / `fk_test_` | `test` |
|
|
162
|
+
|
|
163
|
+
```ts
|
|
164
|
+
console.log(db.environment) // 'prod' or 'test'
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
---
|
|
168
|
+
|
|
169
|
+
## Error Handling
|
|
170
|
+
|
|
171
|
+
```ts
|
|
172
|
+
import { createClient, ForgeDBError } from '@firekid/forgedb'
|
|
173
|
+
|
|
174
|
+
try {
|
|
175
|
+
await db.from('users').insert({ name: 'John' })
|
|
176
|
+
} catch (err) {
|
|
177
|
+
if (err instanceof ForgeDBError) {
|
|
178
|
+
console.log(err.message) // human-readable message
|
|
179
|
+
console.log(err.code) // e.g. 'VALIDATION_ERROR'
|
|
180
|
+
console.log(err.status) // HTTP status code
|
|
181
|
+
console.log(err.line) // SQL line (for query errors)
|
|
182
|
+
console.log(err.token) // offending token (for query errors)
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
189
|
+
## License
|
|
190
|
+
|
|
191
|
+
MIT © [Firekid](https://github.com/Firekid-is-him)
|
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import hurl from '@firekid/hurl';
|
|
2
|
+
|
|
3
|
+
interface ForgeDBConfig {
|
|
4
|
+
/** Your ForgeDB project ID */
|
|
5
|
+
projectId: string;
|
|
6
|
+
/** Your API key — sk_live_... / fk_live_... / sk_test_... / fk_test_... */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** Override the API base URL (optional) */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Row {
|
|
12
|
+
id: number;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface SelectResult<T> {
|
|
18
|
+
rows: T[];
|
|
19
|
+
total: number;
|
|
20
|
+
totalPages: number;
|
|
21
|
+
}
|
|
22
|
+
interface SqlResult {
|
|
23
|
+
rows: Record<string, unknown>[];
|
|
24
|
+
total: number;
|
|
25
|
+
rowsAffected: number;
|
|
26
|
+
executionTime: number;
|
|
27
|
+
message?: string;
|
|
28
|
+
statements?: number;
|
|
29
|
+
}
|
|
30
|
+
type FilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'like' | 'in';
|
|
31
|
+
declare class ForgeDBError extends Error {
|
|
32
|
+
readonly code: string;
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly line?: number;
|
|
35
|
+
readonly token?: string;
|
|
36
|
+
constructor(message: string, code: string, status: number, meta?: {
|
|
37
|
+
line?: number;
|
|
38
|
+
token?: string;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
declare class QueryBuilder<T extends Row = Row> {
|
|
42
|
+
private readonly http;
|
|
43
|
+
private readonly projectId;
|
|
44
|
+
private readonly env;
|
|
45
|
+
private readonly table;
|
|
46
|
+
private _filters;
|
|
47
|
+
private _page?;
|
|
48
|
+
private _limit?;
|
|
49
|
+
private _search?;
|
|
50
|
+
private _sort?;
|
|
51
|
+
private _order?;
|
|
52
|
+
constructor(http: ReturnType<typeof hurl.create>, projectId: string, env: string, table: string);
|
|
53
|
+
/** Filter rows — chain multiple for AND. Shorthand: .where('active', true) or .where('age', '>', 18) */
|
|
54
|
+
where(column: string, operatorOrValue: FilterOperator | unknown, value?: unknown): this;
|
|
55
|
+
page(n: number): this;
|
|
56
|
+
limit(n: number): this;
|
|
57
|
+
search(query: string): this;
|
|
58
|
+
orderBy(column: string, direction?: 'asc' | 'desc'): this;
|
|
59
|
+
private get basePath();
|
|
60
|
+
private buildQuery;
|
|
61
|
+
/** Fetch all rows matching the current filters */
|
|
62
|
+
select(): Promise<SelectResult<T>>;
|
|
63
|
+
/** Fetch a single row by ID */
|
|
64
|
+
selectById(id: number | string): Promise<T>;
|
|
65
|
+
/** Insert a new row */
|
|
66
|
+
insert(data: Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>): Promise<T>;
|
|
67
|
+
/** Update a row by ID */
|
|
68
|
+
update(id: number | string, data: Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>): Promise<T>;
|
|
69
|
+
/** Delete a row by ID */
|
|
70
|
+
delete(id: number | string): Promise<{
|
|
71
|
+
success: boolean;
|
|
72
|
+
}>;
|
|
73
|
+
/** Delete multiple rows by IDs */
|
|
74
|
+
bulkDelete(ids: number[]): Promise<{
|
|
75
|
+
success: boolean;
|
|
76
|
+
deleted: number;
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
79
|
+
declare class ForgeDBClient {
|
|
80
|
+
private readonly http;
|
|
81
|
+
private readonly _projectId;
|
|
82
|
+
private readonly _env;
|
|
83
|
+
constructor(config: ForgeDBConfig);
|
|
84
|
+
/**
|
|
85
|
+
* Select a table to query.
|
|
86
|
+
* @example
|
|
87
|
+
* const { rows } = await db.from('users').select()
|
|
88
|
+
* const user = await db.from<User>('users').where('active', true).limit(10).select()
|
|
89
|
+
*/
|
|
90
|
+
from<T extends Row = Row>(table: string): QueryBuilder<T>;
|
|
91
|
+
/**
|
|
92
|
+
* Run a raw SQL query. Supports multiple statements separated by ;
|
|
93
|
+
* @example
|
|
94
|
+
* const result = await db.sql('SELECT * FROM users WHERE age > 18')
|
|
95
|
+
*/
|
|
96
|
+
sql(query: string): Promise<SqlResult>;
|
|
97
|
+
get environment(): 'prod' | 'test';
|
|
98
|
+
get projectId(): string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create a ForgeDB client.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* import { createClient } from '@firekid/forgedb'
|
|
105
|
+
*
|
|
106
|
+
* const db = createClient({
|
|
107
|
+
* projectId: 'abc123',
|
|
108
|
+
* apiKey: 'sk_live_...',
|
|
109
|
+
* })
|
|
110
|
+
*
|
|
111
|
+
* // Select
|
|
112
|
+
* const { rows } = await db.from('users').select()
|
|
113
|
+
*
|
|
114
|
+
* // Filter + paginate
|
|
115
|
+
* const { rows } = await db.from('users').where('age', '>', 18).page(1).limit(20).select()
|
|
116
|
+
*
|
|
117
|
+
* // Insert
|
|
118
|
+
* const user = await db.from('users').insert({ name: 'John', email: 'john@example.com' })
|
|
119
|
+
*
|
|
120
|
+
* // Update
|
|
121
|
+
* await db.from('users').update(1, { name: 'Jane' })
|
|
122
|
+
*
|
|
123
|
+
* // Delete
|
|
124
|
+
* await db.from('users').delete(1)
|
|
125
|
+
*
|
|
126
|
+
* // Raw SQL
|
|
127
|
+
* const result = await db.sql('SELECT COUNT(*) as total FROM users')
|
|
128
|
+
*/
|
|
129
|
+
declare function createClient(config: ForgeDBConfig): ForgeDBClient;
|
|
130
|
+
|
|
131
|
+
export { type FilterOperator, ForgeDBClient, type ForgeDBConfig, ForgeDBError, QueryBuilder, type Row, type SelectResult, type SqlResult, createClient, createClient as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import hurl from '@firekid/hurl';
|
|
2
|
+
|
|
3
|
+
interface ForgeDBConfig {
|
|
4
|
+
/** Your ForgeDB project ID */
|
|
5
|
+
projectId: string;
|
|
6
|
+
/** Your API key — sk_live_... / fk_live_... / sk_test_... / fk_test_... */
|
|
7
|
+
apiKey: string;
|
|
8
|
+
/** Override the API base URL (optional) */
|
|
9
|
+
baseUrl?: string;
|
|
10
|
+
}
|
|
11
|
+
interface Row {
|
|
12
|
+
id: number;
|
|
13
|
+
createdAt: string;
|
|
14
|
+
updatedAt: string;
|
|
15
|
+
[key: string]: unknown;
|
|
16
|
+
}
|
|
17
|
+
interface SelectResult<T> {
|
|
18
|
+
rows: T[];
|
|
19
|
+
total: number;
|
|
20
|
+
totalPages: number;
|
|
21
|
+
}
|
|
22
|
+
interface SqlResult {
|
|
23
|
+
rows: Record<string, unknown>[];
|
|
24
|
+
total: number;
|
|
25
|
+
rowsAffected: number;
|
|
26
|
+
executionTime: number;
|
|
27
|
+
message?: string;
|
|
28
|
+
statements?: number;
|
|
29
|
+
}
|
|
30
|
+
type FilterOperator = '=' | '!=' | '>' | '<' | '>=' | '<=' | 'like' | 'in';
|
|
31
|
+
declare class ForgeDBError extends Error {
|
|
32
|
+
readonly code: string;
|
|
33
|
+
readonly status: number;
|
|
34
|
+
readonly line?: number;
|
|
35
|
+
readonly token?: string;
|
|
36
|
+
constructor(message: string, code: string, status: number, meta?: {
|
|
37
|
+
line?: number;
|
|
38
|
+
token?: string;
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
declare class QueryBuilder<T extends Row = Row> {
|
|
42
|
+
private readonly http;
|
|
43
|
+
private readonly projectId;
|
|
44
|
+
private readonly env;
|
|
45
|
+
private readonly table;
|
|
46
|
+
private _filters;
|
|
47
|
+
private _page?;
|
|
48
|
+
private _limit?;
|
|
49
|
+
private _search?;
|
|
50
|
+
private _sort?;
|
|
51
|
+
private _order?;
|
|
52
|
+
constructor(http: ReturnType<typeof hurl.create>, projectId: string, env: string, table: string);
|
|
53
|
+
/** Filter rows — chain multiple for AND. Shorthand: .where('active', true) or .where('age', '>', 18) */
|
|
54
|
+
where(column: string, operatorOrValue: FilterOperator | unknown, value?: unknown): this;
|
|
55
|
+
page(n: number): this;
|
|
56
|
+
limit(n: number): this;
|
|
57
|
+
search(query: string): this;
|
|
58
|
+
orderBy(column: string, direction?: 'asc' | 'desc'): this;
|
|
59
|
+
private get basePath();
|
|
60
|
+
private buildQuery;
|
|
61
|
+
/** Fetch all rows matching the current filters */
|
|
62
|
+
select(): Promise<SelectResult<T>>;
|
|
63
|
+
/** Fetch a single row by ID */
|
|
64
|
+
selectById(id: number | string): Promise<T>;
|
|
65
|
+
/** Insert a new row */
|
|
66
|
+
insert(data: Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>): Promise<T>;
|
|
67
|
+
/** Update a row by ID */
|
|
68
|
+
update(id: number | string, data: Partial<Omit<T, 'id' | 'createdAt' | 'updatedAt'>>): Promise<T>;
|
|
69
|
+
/** Delete a row by ID */
|
|
70
|
+
delete(id: number | string): Promise<{
|
|
71
|
+
success: boolean;
|
|
72
|
+
}>;
|
|
73
|
+
/** Delete multiple rows by IDs */
|
|
74
|
+
bulkDelete(ids: number[]): Promise<{
|
|
75
|
+
success: boolean;
|
|
76
|
+
deleted: number;
|
|
77
|
+
}>;
|
|
78
|
+
}
|
|
79
|
+
declare class ForgeDBClient {
|
|
80
|
+
private readonly http;
|
|
81
|
+
private readonly _projectId;
|
|
82
|
+
private readonly _env;
|
|
83
|
+
constructor(config: ForgeDBConfig);
|
|
84
|
+
/**
|
|
85
|
+
* Select a table to query.
|
|
86
|
+
* @example
|
|
87
|
+
* const { rows } = await db.from('users').select()
|
|
88
|
+
* const user = await db.from<User>('users').where('active', true).limit(10).select()
|
|
89
|
+
*/
|
|
90
|
+
from<T extends Row = Row>(table: string): QueryBuilder<T>;
|
|
91
|
+
/**
|
|
92
|
+
* Run a raw SQL query. Supports multiple statements separated by ;
|
|
93
|
+
* @example
|
|
94
|
+
* const result = await db.sql('SELECT * FROM users WHERE age > 18')
|
|
95
|
+
*/
|
|
96
|
+
sql(query: string): Promise<SqlResult>;
|
|
97
|
+
get environment(): 'prod' | 'test';
|
|
98
|
+
get projectId(): string;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Create a ForgeDB client.
|
|
102
|
+
*
|
|
103
|
+
* @example
|
|
104
|
+
* import { createClient } from '@firekid/forgedb'
|
|
105
|
+
*
|
|
106
|
+
* const db = createClient({
|
|
107
|
+
* projectId: 'abc123',
|
|
108
|
+
* apiKey: 'sk_live_...',
|
|
109
|
+
* })
|
|
110
|
+
*
|
|
111
|
+
* // Select
|
|
112
|
+
* const { rows } = await db.from('users').select()
|
|
113
|
+
*
|
|
114
|
+
* // Filter + paginate
|
|
115
|
+
* const { rows } = await db.from('users').where('age', '>', 18).page(1).limit(20).select()
|
|
116
|
+
*
|
|
117
|
+
* // Insert
|
|
118
|
+
* const user = await db.from('users').insert({ name: 'John', email: 'john@example.com' })
|
|
119
|
+
*
|
|
120
|
+
* // Update
|
|
121
|
+
* await db.from('users').update(1, { name: 'Jane' })
|
|
122
|
+
*
|
|
123
|
+
* // Delete
|
|
124
|
+
* await db.from('users').delete(1)
|
|
125
|
+
*
|
|
126
|
+
* // Raw SQL
|
|
127
|
+
* const result = await db.sql('SELECT COUNT(*) as total FROM users')
|
|
128
|
+
*/
|
|
129
|
+
declare function createClient(config: ForgeDBConfig): ForgeDBClient;
|
|
130
|
+
|
|
131
|
+
export { type FilterOperator, ForgeDBClient, type ForgeDBConfig, ForgeDBError, QueryBuilder, type Row, type SelectResult, type SqlResult, createClient, createClient as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// src/index.ts
|
|
31
|
+
var index_exports = {};
|
|
32
|
+
__export(index_exports, {
|
|
33
|
+
ForgeDBClient: () => ForgeDBClient,
|
|
34
|
+
ForgeDBError: () => ForgeDBError,
|
|
35
|
+
QueryBuilder: () => QueryBuilder,
|
|
36
|
+
createClient: () => createClient,
|
|
37
|
+
default: () => index_default
|
|
38
|
+
});
|
|
39
|
+
module.exports = __toCommonJS(index_exports);
|
|
40
|
+
var import_hurl = __toESM(require("@firekid/hurl"));
|
|
41
|
+
var DEFAULT_BASE_URL = "https://api.forgedb.name.ng";
|
|
42
|
+
var ForgeDBError = class extends Error {
|
|
43
|
+
constructor(message, code, status, meta) {
|
|
44
|
+
super(message);
|
|
45
|
+
this.name = "ForgeDBError";
|
|
46
|
+
this.code = code;
|
|
47
|
+
this.status = status;
|
|
48
|
+
this.line = meta?.line;
|
|
49
|
+
this.token = meta?.token;
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function wrapError(err) {
|
|
53
|
+
if (err instanceof import_hurl.HurlError) {
|
|
54
|
+
const body = err.data;
|
|
55
|
+
throw new ForgeDBError(
|
|
56
|
+
body?.error ?? err.message,
|
|
57
|
+
body?.code ?? err.type,
|
|
58
|
+
err.status ?? 500,
|
|
59
|
+
{ line: body?.line, token: body?.token }
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
throw err;
|
|
63
|
+
}
|
|
64
|
+
var QueryBuilder = class {
|
|
65
|
+
constructor(http, projectId, env, table) {
|
|
66
|
+
this.http = http;
|
|
67
|
+
this.projectId = projectId;
|
|
68
|
+
this.env = env;
|
|
69
|
+
this.table = table;
|
|
70
|
+
this._filters = [];
|
|
71
|
+
}
|
|
72
|
+
/** Filter rows — chain multiple for AND. Shorthand: .where('active', true) or .where('age', '>', 18) */
|
|
73
|
+
where(column, operatorOrValue, value) {
|
|
74
|
+
if (value === void 0) {
|
|
75
|
+
this._filters.push({ column, op: "=", value: operatorOrValue });
|
|
76
|
+
} else {
|
|
77
|
+
this._filters.push({ column, op: operatorOrValue, value });
|
|
78
|
+
}
|
|
79
|
+
return this;
|
|
80
|
+
}
|
|
81
|
+
page(n) {
|
|
82
|
+
this._page = n;
|
|
83
|
+
return this;
|
|
84
|
+
}
|
|
85
|
+
limit(n) {
|
|
86
|
+
this._limit = n;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
search(query) {
|
|
90
|
+
this._search = query;
|
|
91
|
+
return this;
|
|
92
|
+
}
|
|
93
|
+
orderBy(column, direction = "asc") {
|
|
94
|
+
this._sort = column;
|
|
95
|
+
this._order = direction;
|
|
96
|
+
return this;
|
|
97
|
+
}
|
|
98
|
+
get basePath() {
|
|
99
|
+
return `/v1/${this.projectId}/${this.env}/${this.table}`;
|
|
100
|
+
}
|
|
101
|
+
buildQuery() {
|
|
102
|
+
const q = {};
|
|
103
|
+
if (this._page) q["page"] = this._page;
|
|
104
|
+
if (this._limit) q["limit"] = this._limit;
|
|
105
|
+
if (this._search) q["search"] = this._search;
|
|
106
|
+
if (this._sort) q["sort"] = this._sort;
|
|
107
|
+
if (this._order) q["order"] = this._order;
|
|
108
|
+
this._filters.forEach((f, i) => {
|
|
109
|
+
q[`filter[${i}][col]`] = f.column;
|
|
110
|
+
q[`filter[${i}][op]`] = f.op;
|
|
111
|
+
q[`filter[${i}][val]`] = String(f.value);
|
|
112
|
+
});
|
|
113
|
+
return q;
|
|
114
|
+
}
|
|
115
|
+
/** Fetch all rows matching the current filters */
|
|
116
|
+
async select() {
|
|
117
|
+
try {
|
|
118
|
+
const res = await this.http.get(this.basePath, { query: this.buildQuery() });
|
|
119
|
+
return res.data;
|
|
120
|
+
} catch (e) {
|
|
121
|
+
wrapError(e);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
/** Fetch a single row by ID */
|
|
125
|
+
async selectById(id) {
|
|
126
|
+
try {
|
|
127
|
+
const res = await this.http.get(`${this.basePath}/${id}`);
|
|
128
|
+
return res.data.row;
|
|
129
|
+
} catch (e) {
|
|
130
|
+
wrapError(e);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/** Insert a new row */
|
|
134
|
+
async insert(data) {
|
|
135
|
+
try {
|
|
136
|
+
const res = await this.http.post(this.basePath, data);
|
|
137
|
+
return res.data.row;
|
|
138
|
+
} catch (e) {
|
|
139
|
+
wrapError(e);
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
/** Update a row by ID */
|
|
143
|
+
async update(id, data) {
|
|
144
|
+
try {
|
|
145
|
+
const res = await this.http.put(`${this.basePath}/${id}`, data);
|
|
146
|
+
return res.data.row;
|
|
147
|
+
} catch (e) {
|
|
148
|
+
wrapError(e);
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/** Delete a row by ID */
|
|
152
|
+
async delete(id) {
|
|
153
|
+
try {
|
|
154
|
+
const res = await this.http.delete(`${this.basePath}/${id}`);
|
|
155
|
+
return res.data;
|
|
156
|
+
} catch (e) {
|
|
157
|
+
wrapError(e);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Delete multiple rows by IDs */
|
|
161
|
+
async bulkDelete(ids) {
|
|
162
|
+
try {
|
|
163
|
+
const res = await this.http.delete(
|
|
164
|
+
`${this.basePath}/bulk-delete`,
|
|
165
|
+
{ body: { ids } }
|
|
166
|
+
);
|
|
167
|
+
return res.data;
|
|
168
|
+
} catch (e) {
|
|
169
|
+
wrapError(e);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
var ForgeDBClient = class {
|
|
174
|
+
constructor(config) {
|
|
175
|
+
this._projectId = config.projectId;
|
|
176
|
+
this._env = config.apiKey.includes("_test_") ? "test" : "prod";
|
|
177
|
+
this.http = import_hurl.default.create({
|
|
178
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
|
|
179
|
+
auth: { type: "bearer", token: config.apiKey },
|
|
180
|
+
timeout: 15e3,
|
|
181
|
+
retry: { count: 2, backoff: "exponential", on: [500, 502, 503, 504] }
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Select a table to query.
|
|
186
|
+
* @example
|
|
187
|
+
* const { rows } = await db.from('users').select()
|
|
188
|
+
* const user = await db.from<User>('users').where('active', true).limit(10).select()
|
|
189
|
+
*/
|
|
190
|
+
from(table) {
|
|
191
|
+
return new QueryBuilder(this.http, this._projectId, this._env, table);
|
|
192
|
+
}
|
|
193
|
+
/**
|
|
194
|
+
* Run a raw SQL query. Supports multiple statements separated by ;
|
|
195
|
+
* @example
|
|
196
|
+
* const result = await db.sql('SELECT * FROM users WHERE age > 18')
|
|
197
|
+
*/
|
|
198
|
+
async sql(query) {
|
|
199
|
+
try {
|
|
200
|
+
const res = await this.http.post(
|
|
201
|
+
`/v1/${this._projectId}/${this._env}/query`,
|
|
202
|
+
{ sql: query }
|
|
203
|
+
);
|
|
204
|
+
return res.data;
|
|
205
|
+
} catch (e) {
|
|
206
|
+
wrapError(e);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
get environment() {
|
|
210
|
+
return this._env;
|
|
211
|
+
}
|
|
212
|
+
get projectId() {
|
|
213
|
+
return this._projectId;
|
|
214
|
+
}
|
|
215
|
+
};
|
|
216
|
+
function createClient(config) {
|
|
217
|
+
return new ForgeDBClient(config);
|
|
218
|
+
}
|
|
219
|
+
var index_default = createClient;
|
|
220
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
221
|
+
0 && (module.exports = {
|
|
222
|
+
ForgeDBClient,
|
|
223
|
+
ForgeDBError,
|
|
224
|
+
QueryBuilder,
|
|
225
|
+
createClient
|
|
226
|
+
});
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import hurl, { HurlError } from "@firekid/hurl";
|
|
3
|
+
var DEFAULT_BASE_URL = "https://api.forgedb.name.ng";
|
|
4
|
+
var ForgeDBError = class extends Error {
|
|
5
|
+
constructor(message, code, status, meta) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "ForgeDBError";
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.status = status;
|
|
10
|
+
this.line = meta?.line;
|
|
11
|
+
this.token = meta?.token;
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function wrapError(err) {
|
|
15
|
+
if (err instanceof HurlError) {
|
|
16
|
+
const body = err.data;
|
|
17
|
+
throw new ForgeDBError(
|
|
18
|
+
body?.error ?? err.message,
|
|
19
|
+
body?.code ?? err.type,
|
|
20
|
+
err.status ?? 500,
|
|
21
|
+
{ line: body?.line, token: body?.token }
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
throw err;
|
|
25
|
+
}
|
|
26
|
+
var QueryBuilder = class {
|
|
27
|
+
constructor(http, projectId, env, table) {
|
|
28
|
+
this.http = http;
|
|
29
|
+
this.projectId = projectId;
|
|
30
|
+
this.env = env;
|
|
31
|
+
this.table = table;
|
|
32
|
+
this._filters = [];
|
|
33
|
+
}
|
|
34
|
+
/** Filter rows — chain multiple for AND. Shorthand: .where('active', true) or .where('age', '>', 18) */
|
|
35
|
+
where(column, operatorOrValue, value) {
|
|
36
|
+
if (value === void 0) {
|
|
37
|
+
this._filters.push({ column, op: "=", value: operatorOrValue });
|
|
38
|
+
} else {
|
|
39
|
+
this._filters.push({ column, op: operatorOrValue, value });
|
|
40
|
+
}
|
|
41
|
+
return this;
|
|
42
|
+
}
|
|
43
|
+
page(n) {
|
|
44
|
+
this._page = n;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
limit(n) {
|
|
48
|
+
this._limit = n;
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
search(query) {
|
|
52
|
+
this._search = query;
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
orderBy(column, direction = "asc") {
|
|
56
|
+
this._sort = column;
|
|
57
|
+
this._order = direction;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
get basePath() {
|
|
61
|
+
return `/v1/${this.projectId}/${this.env}/${this.table}`;
|
|
62
|
+
}
|
|
63
|
+
buildQuery() {
|
|
64
|
+
const q = {};
|
|
65
|
+
if (this._page) q["page"] = this._page;
|
|
66
|
+
if (this._limit) q["limit"] = this._limit;
|
|
67
|
+
if (this._search) q["search"] = this._search;
|
|
68
|
+
if (this._sort) q["sort"] = this._sort;
|
|
69
|
+
if (this._order) q["order"] = this._order;
|
|
70
|
+
this._filters.forEach((f, i) => {
|
|
71
|
+
q[`filter[${i}][col]`] = f.column;
|
|
72
|
+
q[`filter[${i}][op]`] = f.op;
|
|
73
|
+
q[`filter[${i}][val]`] = String(f.value);
|
|
74
|
+
});
|
|
75
|
+
return q;
|
|
76
|
+
}
|
|
77
|
+
/** Fetch all rows matching the current filters */
|
|
78
|
+
async select() {
|
|
79
|
+
try {
|
|
80
|
+
const res = await this.http.get(this.basePath, { query: this.buildQuery() });
|
|
81
|
+
return res.data;
|
|
82
|
+
} catch (e) {
|
|
83
|
+
wrapError(e);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/** Fetch a single row by ID */
|
|
87
|
+
async selectById(id) {
|
|
88
|
+
try {
|
|
89
|
+
const res = await this.http.get(`${this.basePath}/${id}`);
|
|
90
|
+
return res.data.row;
|
|
91
|
+
} catch (e) {
|
|
92
|
+
wrapError(e);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
/** Insert a new row */
|
|
96
|
+
async insert(data) {
|
|
97
|
+
try {
|
|
98
|
+
const res = await this.http.post(this.basePath, data);
|
|
99
|
+
return res.data.row;
|
|
100
|
+
} catch (e) {
|
|
101
|
+
wrapError(e);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/** Update a row by ID */
|
|
105
|
+
async update(id, data) {
|
|
106
|
+
try {
|
|
107
|
+
const res = await this.http.put(`${this.basePath}/${id}`, data);
|
|
108
|
+
return res.data.row;
|
|
109
|
+
} catch (e) {
|
|
110
|
+
wrapError(e);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Delete a row by ID */
|
|
114
|
+
async delete(id) {
|
|
115
|
+
try {
|
|
116
|
+
const res = await this.http.delete(`${this.basePath}/${id}`);
|
|
117
|
+
return res.data;
|
|
118
|
+
} catch (e) {
|
|
119
|
+
wrapError(e);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
/** Delete multiple rows by IDs */
|
|
123
|
+
async bulkDelete(ids) {
|
|
124
|
+
try {
|
|
125
|
+
const res = await this.http.delete(
|
|
126
|
+
`${this.basePath}/bulk-delete`,
|
|
127
|
+
{ body: { ids } }
|
|
128
|
+
);
|
|
129
|
+
return res.data;
|
|
130
|
+
} catch (e) {
|
|
131
|
+
wrapError(e);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
};
|
|
135
|
+
var ForgeDBClient = class {
|
|
136
|
+
constructor(config) {
|
|
137
|
+
this._projectId = config.projectId;
|
|
138
|
+
this._env = config.apiKey.includes("_test_") ? "test" : "prod";
|
|
139
|
+
this.http = hurl.create({
|
|
140
|
+
baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,
|
|
141
|
+
auth: { type: "bearer", token: config.apiKey },
|
|
142
|
+
timeout: 15e3,
|
|
143
|
+
retry: { count: 2, backoff: "exponential", on: [500, 502, 503, 504] }
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Select a table to query.
|
|
148
|
+
* @example
|
|
149
|
+
* const { rows } = await db.from('users').select()
|
|
150
|
+
* const user = await db.from<User>('users').where('active', true).limit(10).select()
|
|
151
|
+
*/
|
|
152
|
+
from(table) {
|
|
153
|
+
return new QueryBuilder(this.http, this._projectId, this._env, table);
|
|
154
|
+
}
|
|
155
|
+
/**
|
|
156
|
+
* Run a raw SQL query. Supports multiple statements separated by ;
|
|
157
|
+
* @example
|
|
158
|
+
* const result = await db.sql('SELECT * FROM users WHERE age > 18')
|
|
159
|
+
*/
|
|
160
|
+
async sql(query) {
|
|
161
|
+
try {
|
|
162
|
+
const res = await this.http.post(
|
|
163
|
+
`/v1/${this._projectId}/${this._env}/query`,
|
|
164
|
+
{ sql: query }
|
|
165
|
+
);
|
|
166
|
+
return res.data;
|
|
167
|
+
} catch (e) {
|
|
168
|
+
wrapError(e);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
get environment() {
|
|
172
|
+
return this._env;
|
|
173
|
+
}
|
|
174
|
+
get projectId() {
|
|
175
|
+
return this._projectId;
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
function createClient(config) {
|
|
179
|
+
return new ForgeDBClient(config);
|
|
180
|
+
}
|
|
181
|
+
var index_default = createClient;
|
|
182
|
+
export {
|
|
183
|
+
ForgeDBClient,
|
|
184
|
+
ForgeDBError,
|
|
185
|
+
QueryBuilder,
|
|
186
|
+
createClient,
|
|
187
|
+
index_default as default
|
|
188
|
+
};
|
package/package.json
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@firekid/forgedb",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Official JavaScript/TypeScript client for ForgeDB",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"module": "dist/index.mjs",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"import": "./dist/index.mjs",
|
|
12
|
+
"require": "./dist/index.js"
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"files": ["dist", "README.md"],
|
|
16
|
+
"scripts": {
|
|
17
|
+
"build": "tsup src/index.ts --format cjs,esm --dts --clean"
|
|
18
|
+
},
|
|
19
|
+
"keywords": ["forgedb", "database", "firekid", "sdk", "client"],
|
|
20
|
+
"author": "Firekid",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"dependencies": {
|
|
23
|
+
"@firekid/hurl": "latest"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.0.0"
|
|
28
|
+
}
|
|
29
|
+
}
|