@better-i18n/sdk 2.0.1 → 3.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 +163 -67
- package/dist/client.d.ts +16 -3
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +27 -5
- package/dist/client.js.map +1 -1
- package/dist/content-api.d.ts +2 -11
- package/dist/content-api.d.ts.map +1 -1
- package/dist/content-api.js +2 -79
- package/dist/content-api.js.map +1 -1
- package/dist/http.d.ts +21 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +78 -0
- package/dist/http.js.map +1 -0
- package/dist/index.d.ts +5 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -1
- package/dist/query-builder.d.ts +134 -0
- package/dist/query-builder.d.ts.map +1 -0
- package/dist/query-builder.js +237 -0
- package/dist/query-builder.js.map +1 -0
- package/dist/types.d.ts +46 -17
- package/dist/types.d.ts.map +1 -1
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -8,8 +8,9 @@ Content SDK for [Better i18n](https://better-i18n.com). A lightweight, typed cli
|
|
|
8
8
|
- 🔒 **Type-Safe** — Full TypeScript types with generic custom fields
|
|
9
9
|
- 🌍 **Language-Aware** — Fetch localized content by language code
|
|
10
10
|
- 📄 **Pagination Built-in** — Paginated listing with total count and `hasMore`
|
|
11
|
-
- 🔍 **Filtering & Sorting** — Filter by status,
|
|
12
|
-
- ⚡ **
|
|
11
|
+
- 🔍 **Filtering, Search & Sorting** — Filter by status, custom fields, full-text search
|
|
12
|
+
- ⚡ **Chainable Query Builder** — Supabase-style `from().eq().order().limit()` API
|
|
13
|
+
- 🛡️ **Error-Safe** — `{ data, error }` pattern — never throws on API errors
|
|
13
14
|
|
|
14
15
|
## Installation
|
|
15
16
|
|
|
@@ -27,78 +28,144 @@ const client = createClient({
|
|
|
27
28
|
apiKey: process.env.BETTER_I18N_API_KEY!,
|
|
28
29
|
});
|
|
29
30
|
|
|
30
|
-
// List
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log(post.title, post.body);
|
|
31
|
+
// List published blog posts (chainable API)
|
|
32
|
+
const { data: posts, error, total, hasMore } = await client
|
|
33
|
+
.from("blog-posts")
|
|
34
|
+
.eq("status", "published")
|
|
35
|
+
.order("publishedAt", { ascending: false })
|
|
36
|
+
.limit(10)
|
|
37
|
+
.language("en");
|
|
38
|
+
|
|
39
|
+
// Get a single entry
|
|
40
|
+
const { data: post, error: postError } = await client
|
|
41
|
+
.from("blog-posts")
|
|
42
|
+
.expand("author", "category")
|
|
43
|
+
.language("fr")
|
|
44
|
+
.single("hello-world");
|
|
45
|
+
|
|
46
|
+
if (post) {
|
|
47
|
+
console.log(post.title, post.body);
|
|
48
|
+
}
|
|
47
49
|
```
|
|
48
50
|
|
|
49
|
-
##
|
|
51
|
+
## Chainable Query Builder
|
|
50
52
|
|
|
51
|
-
|
|
52
|
-
| --- | --- |
|
|
53
|
-
| `getModels()` | List all content models with entry counts |
|
|
54
|
-
| `getEntries(modelSlug, options?)` | Paginated list of entries for a model |
|
|
55
|
-
| `getEntry(modelSlug, entrySlug, options?)` | Full content entry with all fields |
|
|
53
|
+
The `from()` method returns an immutable, chainable query builder — inspired by Supabase JS.
|
|
56
54
|
|
|
57
|
-
|
|
55
|
+
Every chain method returns a **new** builder instance, so you can safely reuse base queries:
|
|
58
56
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
57
|
+
```typescript
|
|
58
|
+
const publishedPosts = client
|
|
59
|
+
.from("blog-posts")
|
|
60
|
+
.eq("status", "published");
|
|
61
|
+
|
|
62
|
+
// Reuse the base query
|
|
63
|
+
const recentPosts = await publishedPosts
|
|
64
|
+
.order("publishedAt", { ascending: false })
|
|
65
|
+
.limit(5);
|
|
66
|
+
|
|
67
|
+
const popularPosts = await publishedPosts
|
|
68
|
+
.order("title", { ascending: true })
|
|
69
|
+
.limit(10);
|
|
70
|
+
```
|
|
69
71
|
|
|
70
|
-
###
|
|
72
|
+
### Chain Methods
|
|
71
73
|
|
|
72
|
-
|
|
|
73
|
-
| --- | --- | --- |
|
|
74
|
-
| `
|
|
75
|
-
| `
|
|
76
|
-
|
|
|
74
|
+
| Method | Description | Example |
|
|
75
|
+
| --- | --- | --- |
|
|
76
|
+
| `.select(...fields)` | Choose which fields to include | `.select("title", "body")` |
|
|
77
|
+
| `.eq(field, value)` | Filter by built-in field (status, etc.) | `.eq("status", "published")` |
|
|
78
|
+
| `.filter(field, value)` | Filter by custom field value | `.filter("category", "engineering")` |
|
|
79
|
+
| `.search(term)` | Full-text search on entry titles | `.search("kubernetes")` |
|
|
80
|
+
| `.language(code)` | Set language for localized content | `.language("fr")` |
|
|
81
|
+
| `.order(field, opts?)` | Set sort field and direction | `.order("publishedAt", { ascending: false })` |
|
|
82
|
+
| `.limit(n)` | Max entries per page (1-100) | `.limit(10)` |
|
|
83
|
+
| `.page(n)` | Page number (1-based) | `.page(2)` |
|
|
84
|
+
| `.expand(...fields)` | Expand relation fields | `.expand("author", "category")` |
|
|
85
|
+
|
|
86
|
+
### Terminal Methods
|
|
87
|
+
|
|
88
|
+
| Method | Description | Returns |
|
|
89
|
+
| --- | --- | --- |
|
|
90
|
+
| `.single(slug)` | Fetch a single entry by slug | `{ data, error }` |
|
|
91
|
+
| `await builder` | Execute list query (thenable) | `{ data, error, total, hasMore }` |
|
|
77
92
|
|
|
78
93
|
### Response Types
|
|
79
94
|
|
|
80
|
-
|
|
95
|
+
**List query returns `QueryResult<T[]>`:**
|
|
81
96
|
|
|
82
97
|
```typescript
|
|
83
98
|
{
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
99
|
+
data: ContentEntryListItem[] | null; // null on error
|
|
100
|
+
error: Error | null; // null on success
|
|
101
|
+
total: number; // total matching entries
|
|
102
|
+
hasMore: boolean; // more pages available
|
|
87
103
|
}
|
|
88
104
|
```
|
|
89
105
|
|
|
90
|
-
|
|
106
|
+
**Single query returns `SingleQueryResult<ContentEntry>`:**
|
|
91
107
|
|
|
92
108
|
```typescript
|
|
93
109
|
{
|
|
94
|
-
|
|
95
|
-
|
|
110
|
+
data: ContentEntry | null; // null on error
|
|
111
|
+
error: Error | null; // null on success
|
|
96
112
|
}
|
|
97
113
|
```
|
|
98
114
|
|
|
115
|
+
### Examples
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
// Full-text search
|
|
119
|
+
const { data: results } = await client
|
|
120
|
+
.from("blog-posts")
|
|
121
|
+
.search("kubernetes")
|
|
122
|
+
.limit(5);
|
|
123
|
+
|
|
124
|
+
// Custom field filtering
|
|
125
|
+
const { data: techPosts } = await client
|
|
126
|
+
.from("blog-posts")
|
|
127
|
+
.filter("category", "engineering")
|
|
128
|
+
.eq("status", "published")
|
|
129
|
+
.language("en");
|
|
130
|
+
|
|
131
|
+
// Select specific fields + expand relations
|
|
132
|
+
const { data: entries } = await client
|
|
133
|
+
.from("blog-posts")
|
|
134
|
+
.select("title", "body")
|
|
135
|
+
.expand("author")
|
|
136
|
+
.order("publishedAt", { ascending: false });
|
|
137
|
+
|
|
138
|
+
// Pagination
|
|
139
|
+
const { data: page2, hasMore } = await client
|
|
140
|
+
.from("blog-posts")
|
|
141
|
+
.eq("status", "published")
|
|
142
|
+
.limit(20)
|
|
143
|
+
.page(2);
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
## Error Handling
|
|
147
|
+
|
|
148
|
+
The chainable API uses the `{ data, error }` pattern — it never throws on API errors:
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const { data, error } = await client
|
|
152
|
+
.from("blog-posts")
|
|
153
|
+
.eq("status", "published")
|
|
154
|
+
.limit(10);
|
|
155
|
+
|
|
156
|
+
if (error) {
|
|
157
|
+
console.error("Failed to fetch posts:", error.message);
|
|
158
|
+
return;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// data is guaranteed non-null here
|
|
162
|
+
console.log(`Found ${data.length} posts`);
|
|
163
|
+
```
|
|
164
|
+
|
|
99
165
|
## Typed Custom Fields
|
|
100
166
|
|
|
101
|
-
|
|
167
|
+
Custom fields are returned flat — directly on the entry object (no `customFields` wrapper).
|
|
168
|
+
Use the generic type parameter for type-safe access:
|
|
102
169
|
|
|
103
170
|
```typescript
|
|
104
171
|
interface BlogFields {
|
|
@@ -106,37 +173,65 @@ interface BlogFields {
|
|
|
106
173
|
category: string | null;
|
|
107
174
|
}
|
|
108
175
|
|
|
109
|
-
const post = await client
|
|
110
|
-
|
|
111
|
-
|
|
176
|
+
const { data: post } = await client
|
|
177
|
+
.from("blog-posts")
|
|
178
|
+
.single<BlogFields>("hello-world");
|
|
179
|
+
|
|
180
|
+
if (post) {
|
|
181
|
+
post.readingTime; // string | null (typed!)
|
|
182
|
+
post.category; // string | null (typed!)
|
|
183
|
+
}
|
|
112
184
|
```
|
|
113
185
|
|
|
114
186
|
## Expanding Relations
|
|
115
187
|
|
|
116
|
-
Use `expand` to resolve related entries in a single request
|
|
188
|
+
Use `expand` to resolve related entries in a single request:
|
|
117
189
|
|
|
118
190
|
```typescript
|
|
119
|
-
const {
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
191
|
+
const { data: posts } = await client
|
|
192
|
+
.from("blog-posts")
|
|
193
|
+
.expand("author", "category")
|
|
194
|
+
.eq("status", "published");
|
|
195
|
+
|
|
196
|
+
if (posts) {
|
|
197
|
+
posts[0].relations?.author?.title; // "Alice Johnson"
|
|
198
|
+
posts[0].relations?.author?.avatar; // "https://..."
|
|
199
|
+
posts[0].relations?.category?.title; // "Engineering"
|
|
200
|
+
}
|
|
128
201
|
```
|
|
129
202
|
|
|
130
|
-
Each expanded relation is a `RelationValue` object:
|
|
203
|
+
Each expanded relation is a `RelationValue` object with custom fields spread directly:
|
|
131
204
|
|
|
132
205
|
```typescript
|
|
133
|
-
|
|
206
|
+
type RelationValue = {
|
|
134
207
|
id: string;
|
|
135
208
|
slug: string;
|
|
136
209
|
title: string;
|
|
137
210
|
modelSlug: string;
|
|
138
|
-
|
|
139
|
-
|
|
211
|
+
} & Record<string, string | null>;
|
|
212
|
+
```
|
|
213
|
+
|
|
214
|
+
## Legacy API
|
|
215
|
+
|
|
216
|
+
The method-based API is still available for backward compatibility:
|
|
217
|
+
|
|
218
|
+
```typescript
|
|
219
|
+
// List content models
|
|
220
|
+
const models = await client.getModels();
|
|
221
|
+
|
|
222
|
+
// List entries (throws on error)
|
|
223
|
+
const { items, total, hasMore } = await client.getEntries("blog-posts", {
|
|
224
|
+
status: "published",
|
|
225
|
+
sort: "publishedAt",
|
|
226
|
+
order: "desc",
|
|
227
|
+
language: "en",
|
|
228
|
+
limit: 10,
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
// Get single entry (throws on error)
|
|
232
|
+
const post = await client.getEntry("blog-posts", "hello-world", {
|
|
233
|
+
language: "fr",
|
|
234
|
+
});
|
|
140
235
|
```
|
|
141
236
|
|
|
142
237
|
## Configuration
|
|
@@ -146,6 +241,7 @@ interface RelationValue {
|
|
|
146
241
|
| `project` | Yes | Project identifier in `org/project` format (e.g., `"acme/web-app"`) |
|
|
147
242
|
| `apiKey` | Yes | API key from [dashboard](https://dash.better-i18n.com) |
|
|
148
243
|
| `apiBase` | No | API base URL (default: `https://content.better-i18n.com`) |
|
|
244
|
+
| `debug` | No | Enable debug logging for request/response inspection |
|
|
149
245
|
|
|
150
246
|
## Documentation
|
|
151
247
|
|
package/dist/client.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { ClientConfig, ContentClient } from "./types.js";
|
|
|
2
2
|
/**
|
|
3
3
|
* Creates a Better i18n content client.
|
|
4
4
|
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
5
|
+
* Supports both a **Supabase-style chainable API** (`from()`) and the
|
|
6
|
+
* legacy method-based API (`getEntries`, `getEntry`, `getModels`).
|
|
7
7
|
*
|
|
8
8
|
* @example
|
|
9
9
|
* ```typescript
|
|
@@ -12,9 +12,22 @@ import type { ClientConfig, ContentClient } from "./types.js";
|
|
|
12
12
|
* apiKey: "bi18n_...",
|
|
13
13
|
* });
|
|
14
14
|
*
|
|
15
|
+
* // Chainable API (recommended)
|
|
16
|
+
* const { data, error } = await client
|
|
17
|
+
* .from("blog-posts")
|
|
18
|
+
* .eq("status", "published")
|
|
19
|
+
* .order("publishedAt", { ascending: false })
|
|
20
|
+
* .limit(10);
|
|
21
|
+
*
|
|
22
|
+
* // Single entry
|
|
23
|
+
* const { data: post } = await client
|
|
24
|
+
* .from("blog-posts")
|
|
25
|
+
* .language("fr")
|
|
26
|
+
* .single("hello-world");
|
|
27
|
+
*
|
|
28
|
+
* // Legacy API (still works)
|
|
15
29
|
* const models = await client.getModels();
|
|
16
30
|
* const posts = await client.getEntries("blog-posts", { language: "fr" });
|
|
17
|
-
* const post = await client.getEntry("blog-posts", "hello-world");
|
|
18
31
|
* ```
|
|
19
32
|
*/
|
|
20
33
|
export declare function createClient(config: ClientConfig): ContentClient;
|
package/dist/client.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAM9D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CA6BhE"}
|
package/dist/client.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { createHttpClient } from "./http.js";
|
|
2
|
+
import { ContentQueryBuilder } from "./query-builder.js";
|
|
2
3
|
const DEFAULT_API_BASE = "https://content.better-i18n.com";
|
|
3
4
|
/**
|
|
4
5
|
* Creates a Better i18n content client.
|
|
5
6
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
7
|
+
* Supports both a **Supabase-style chainable API** (`from()`) and the
|
|
8
|
+
* legacy method-based API (`getEntries`, `getEntry`, `getModels`).
|
|
8
9
|
*
|
|
9
10
|
* @example
|
|
10
11
|
* ```typescript
|
|
@@ -13,9 +14,22 @@ const DEFAULT_API_BASE = "https://content.better-i18n.com";
|
|
|
13
14
|
* apiKey: "bi18n_...",
|
|
14
15
|
* });
|
|
15
16
|
*
|
|
17
|
+
* // Chainable API (recommended)
|
|
18
|
+
* const { data, error } = await client
|
|
19
|
+
* .from("blog-posts")
|
|
20
|
+
* .eq("status", "published")
|
|
21
|
+
* .order("publishedAt", { ascending: false })
|
|
22
|
+
* .limit(10);
|
|
23
|
+
*
|
|
24
|
+
* // Single entry
|
|
25
|
+
* const { data: post } = await client
|
|
26
|
+
* .from("blog-posts")
|
|
27
|
+
* .language("fr")
|
|
28
|
+
* .single("hello-world");
|
|
29
|
+
*
|
|
30
|
+
* // Legacy API (still works)
|
|
16
31
|
* const models = await client.getModels();
|
|
17
32
|
* const posts = await client.getEntries("blog-posts", { language: "fr" });
|
|
18
|
-
* const post = await client.getEntry("blog-posts", "hello-world");
|
|
19
33
|
* ```
|
|
20
34
|
*/
|
|
21
35
|
export function createClient(config) {
|
|
@@ -30,6 +44,14 @@ export function createClient(config) {
|
|
|
30
44
|
"Set apiKey in your client config:\n\n" +
|
|
31
45
|
' createClient({ project: "acme/web-app", apiKey: "bi18n_..." })');
|
|
32
46
|
}
|
|
33
|
-
|
|
47
|
+
const http = createHttpClient(apiBase, org, project, config.apiKey, config.debug);
|
|
48
|
+
return {
|
|
49
|
+
from(modelSlug) {
|
|
50
|
+
return ContentQueryBuilder.create(http, modelSlug);
|
|
51
|
+
},
|
|
52
|
+
getModels: () => http.getModels(),
|
|
53
|
+
getEntries: (model, opts) => http.getEntries(model, opts),
|
|
54
|
+
getEntry: (model, slug, opts) => http.getEntry(model, slug, opts),
|
|
55
|
+
};
|
|
34
56
|
}
|
|
35
57
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,gBAAgB,GAAG,iCAAiC,CAAC;AAE3D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,MAAM,OAAO,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,gBAAgB,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;IAExE,MAAM,KAAK,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACxC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACjD,MAAM,IAAI,KAAK,CACb,2BAA2B,MAAM,CAAC,OAAO,mDAAmD,CAC7F,CAAC;IACJ,CAAC;IACD,MAAM,CAAC,GAAG,EAAE,OAAO,CAAC,GAAG,KAAK,CAAC;IAE7B,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CACb,+CAA+C;YAC7C,uCAAuC;YACvC,kEAAkE,CACrE,CAAC;IACJ,CAAC;IAED,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;IAElF,OAAO;QACL,IAAI,CAAC,SAAiB;YACpB,OAAO,mBAAmB,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;QACrD,CAAC;QACD,SAAS,EAAE,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,EAAE;QACjC,UAAU,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,EAAE,IAAI,CAAC;QACzD,QAAQ,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,IAAI,CAAC;KAClE,CAAC;AACJ,CAAC"}
|
package/dist/content-api.d.ts
CHANGED
|
@@ -1,14 +1,5 @@
|
|
|
1
|
-
import type { ContentClient } from "./types.js";
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* This mode supports filtering, pagination, and real-time data (no caching lag).
|
|
6
|
-
* Requires an API key for authentication via the `x-api-key` header.
|
|
7
|
-
*
|
|
8
|
-
* URL patterns:
|
|
9
|
-
* - Models: `{apiBase}/v1/content/{org}/{project}/models`
|
|
10
|
-
* - Entries: `{apiBase}/v1/content/{org}/{project}/models/{model}/entries`
|
|
11
|
-
* - Entry: `{apiBase}/v1/content/{org}/{project}/models/{model}/entries/{slug}`
|
|
2
|
+
* @deprecated Import from `./http.js` instead. This file is kept for backward compatibility.
|
|
12
3
|
*/
|
|
13
|
-
export
|
|
4
|
+
export { createHttpClient as createContentAPIClient } from "./http.js";
|
|
14
5
|
//# sourceMappingURL=content-api.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-api.d.ts","sourceRoot":"","sources":["../src/content-api.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"content-api.d.ts","sourceRoot":"","sources":["../src/content-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,gBAAgB,IAAI,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/content-api.js
CHANGED
|
@@ -1,82 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
* This mode supports filtering, pagination, and real-time data (no caching lag).
|
|
5
|
-
* Requires an API key for authentication via the `x-api-key` header.
|
|
6
|
-
*
|
|
7
|
-
* URL patterns:
|
|
8
|
-
* - Models: `{apiBase}/v1/content/{org}/{project}/models`
|
|
9
|
-
* - Entries: `{apiBase}/v1/content/{org}/{project}/models/{model}/entries`
|
|
10
|
-
* - Entry: `{apiBase}/v1/content/{org}/{project}/models/{model}/entries/{slug}`
|
|
2
|
+
* @deprecated Import from `./http.js` instead. This file is kept for backward compatibility.
|
|
11
3
|
*/
|
|
12
|
-
export
|
|
13
|
-
const base = `${apiBase}/v1/content/${org}/${project}`;
|
|
14
|
-
const headers = {
|
|
15
|
-
"x-api-key": apiKey,
|
|
16
|
-
"content-type": "application/json",
|
|
17
|
-
};
|
|
18
|
-
const log = debug
|
|
19
|
-
? (...args) => console.log("[better-i18n]", ...args)
|
|
20
|
-
: () => { };
|
|
21
|
-
if (debug) {
|
|
22
|
-
log("Client initialized", { apiBase, org, project, base });
|
|
23
|
-
}
|
|
24
|
-
async function request(url, label) {
|
|
25
|
-
log(`→ ${label}`, url);
|
|
26
|
-
const res = await fetch(url, { headers });
|
|
27
|
-
log(`← ${res.status} ${res.statusText}`);
|
|
28
|
-
if (!res.ok) {
|
|
29
|
-
const body = await res.text().catch(() => "");
|
|
30
|
-
log(" Error body:", body);
|
|
31
|
-
throw new Error(`API error ${label}: ${res.status} ${body}`);
|
|
32
|
-
}
|
|
33
|
-
const data = await res.json();
|
|
34
|
-
log(" Response:", JSON.stringify(data).slice(0, 500));
|
|
35
|
-
return { res, data };
|
|
36
|
-
}
|
|
37
|
-
return {
|
|
38
|
-
async getModels() {
|
|
39
|
-
const { data } = await request(`${base}/models`, "getModels");
|
|
40
|
-
return data;
|
|
41
|
-
},
|
|
42
|
-
async getEntries(modelSlug, options) {
|
|
43
|
-
const params = new URLSearchParams();
|
|
44
|
-
if (options?.language)
|
|
45
|
-
params.set("language", options.language);
|
|
46
|
-
if (options?.status)
|
|
47
|
-
params.set("status", options.status);
|
|
48
|
-
if (options?.sort)
|
|
49
|
-
params.set("sort", options.sort);
|
|
50
|
-
if (options?.order)
|
|
51
|
-
params.set("order", options.order);
|
|
52
|
-
if (options?.page)
|
|
53
|
-
params.set("page", String(options.page));
|
|
54
|
-
if (options?.limit)
|
|
55
|
-
params.set("limit", String(options.limit));
|
|
56
|
-
if (options?.expand?.length)
|
|
57
|
-
params.set("expand", options.expand.join(","));
|
|
58
|
-
if (options?.fields?.length)
|
|
59
|
-
params.set("fields", options.fields.join(","));
|
|
60
|
-
const qs = params.toString() ? `?${params}` : "";
|
|
61
|
-
const { data } = await request(`${base}/models/${modelSlug}/entries${qs}`, `getEntries(${modelSlug})`);
|
|
62
|
-
return {
|
|
63
|
-
items: data.items,
|
|
64
|
-
total: data.total,
|
|
65
|
-
hasMore: data.hasMore,
|
|
66
|
-
};
|
|
67
|
-
},
|
|
68
|
-
async getEntry(modelSlug, entrySlug, options) {
|
|
69
|
-
const params = new URLSearchParams();
|
|
70
|
-
if (options?.language)
|
|
71
|
-
params.set("language", options.language);
|
|
72
|
-
if (options?.expand?.length)
|
|
73
|
-
params.set("expand", options.expand.join(","));
|
|
74
|
-
if (options?.fields?.length)
|
|
75
|
-
params.set("fields", options.fields.join(","));
|
|
76
|
-
const qs = params.toString() ? `?${params}` : "";
|
|
77
|
-
const { data } = await request(`${base}/models/${modelSlug}/entries/${entrySlug}${qs}`, `getEntry(${modelSlug}/${entrySlug})`);
|
|
78
|
-
return data;
|
|
79
|
-
},
|
|
80
|
-
};
|
|
81
|
-
}
|
|
4
|
+
export { createHttpClient as createContentAPIClient } from "./http.js";
|
|
82
5
|
//# sourceMappingURL=content-api.js.map
|
package/dist/content-api.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"content-api.js","sourceRoot":"","sources":["../src/content-api.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"content-api.js","sourceRoot":"","sources":["../src/content-api.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,OAAO,EAAE,gBAAgB,IAAI,sBAAsB,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/http.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ContentEntry, ContentEntryListItem, ContentModel, GetEntryOptions, ListEntriesOptions, PaginatedResponse } from "./types.js";
|
|
2
|
+
/** Low-level HTTP client used by both the legacy API and the query builder. */
|
|
3
|
+
export interface HttpClient {
|
|
4
|
+
/** Make a raw GET request and return `{ data, error }` (never throws). */
|
|
5
|
+
request<T>(path: string, params?: URLSearchParams): Promise<HttpResult<T>>;
|
|
6
|
+
/** List content models. */
|
|
7
|
+
getModels(): Promise<ContentModel[]>;
|
|
8
|
+
/** List entries with legacy options. */
|
|
9
|
+
getEntries(model: string, opts?: ListEntriesOptions): Promise<PaginatedResponse<ContentEntryListItem>>;
|
|
10
|
+
/** Fetch a single entry by slug. */
|
|
11
|
+
getEntry<CF extends Record<string, string | null> = Record<string, string | null>>(model: string, slug: string, opts?: GetEntryOptions): Promise<ContentEntry<CF>>;
|
|
12
|
+
}
|
|
13
|
+
export type HttpResult<T> = {
|
|
14
|
+
data: T;
|
|
15
|
+
error: null;
|
|
16
|
+
} | {
|
|
17
|
+
data: null;
|
|
18
|
+
error: Error;
|
|
19
|
+
};
|
|
20
|
+
export declare function createHttpClient(apiBase: string, org: string, project: string, apiKey: string, debug?: boolean): HttpClient;
|
|
21
|
+
//# sourceMappingURL=http.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAIpB,+EAA+E;AAC/E,MAAM,WAAW,UAAU;IACzB,0EAA0E;IAC1E,OAAO,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,eAAe,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;IAC3E,2BAA2B;IAC3B,SAAS,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACrC,wCAAwC;IACxC,UAAU,CACR,KAAK,EAAE,MAAM,EACb,IAAI,CAAC,EAAE,kBAAkB,GACxB,OAAO,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACpD,oCAAoC;IACpC,QAAQ,CAAC,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC/E,KAAK,EAAE,MAAM,EACb,IAAI,EAAE,MAAM,EACZ,IAAI,CAAC,EAAE,eAAe,GACrB,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;CAC9B;AAED,MAAM,MAAM,UAAU,CAAC,CAAC,IACpB;IAAE,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,IAAI,CAAA;CAAE,GACxB;IAAE,IAAI,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,KAAK,CAAA;CAAE,CAAC;AAIjC,wBAAgB,gBAAgB,CAC9B,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,UAAQ,GACZ,UAAU,CAuFZ"}
|
package/dist/http.js
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
// ─── Factory ────────────────────────────────────────────────────────
|
|
2
|
+
export function createHttpClient(apiBase, org, project, apiKey, debug = false) {
|
|
3
|
+
const base = `${apiBase}/v1/content/${org}/${project}`;
|
|
4
|
+
const headers = {
|
|
5
|
+
"x-api-key": apiKey,
|
|
6
|
+
"content-type": "application/json",
|
|
7
|
+
};
|
|
8
|
+
const log = debug
|
|
9
|
+
? (...args) => console.log("[better-i18n]", ...args)
|
|
10
|
+
: () => { };
|
|
11
|
+
if (debug) {
|
|
12
|
+
log("Client initialized", { apiBase, org, project, base });
|
|
13
|
+
}
|
|
14
|
+
/** Internal fetch helper — throws on HTTP errors. */
|
|
15
|
+
async function rawRequest(url, label) {
|
|
16
|
+
log(`→ ${label}`, url);
|
|
17
|
+
const res = await fetch(url, { headers });
|
|
18
|
+
log(`← ${res.status} ${res.statusText}`);
|
|
19
|
+
if (!res.ok) {
|
|
20
|
+
const body = await res.text().catch(() => "");
|
|
21
|
+
log(" Error body:", body);
|
|
22
|
+
throw new Error(`API error ${label}: ${res.status} ${body}`);
|
|
23
|
+
}
|
|
24
|
+
const data = (await res.json());
|
|
25
|
+
log(" Response:", JSON.stringify(data).slice(0, 500));
|
|
26
|
+
return data;
|
|
27
|
+
}
|
|
28
|
+
return {
|
|
29
|
+
async request(path, params) {
|
|
30
|
+
const qs = params?.toString() ? `?${params}` : "";
|
|
31
|
+
const url = `${base}${path}${qs}`;
|
|
32
|
+
try {
|
|
33
|
+
const data = await rawRequest(url, `request(${path})`);
|
|
34
|
+
return { data, error: null };
|
|
35
|
+
}
|
|
36
|
+
catch (err) {
|
|
37
|
+
return { data: null, error: err instanceof Error ? err : new Error(String(err)) };
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
async getModels() {
|
|
41
|
+
return rawRequest(`${base}/models`, "getModels");
|
|
42
|
+
},
|
|
43
|
+
async getEntries(modelSlug, options) {
|
|
44
|
+
const params = new URLSearchParams();
|
|
45
|
+
if (options?.language)
|
|
46
|
+
params.set("language", options.language);
|
|
47
|
+
if (options?.status)
|
|
48
|
+
params.set("status", options.status);
|
|
49
|
+
if (options?.sort)
|
|
50
|
+
params.set("sort", options.sort);
|
|
51
|
+
if (options?.order)
|
|
52
|
+
params.set("order", options.order);
|
|
53
|
+
if (options?.page)
|
|
54
|
+
params.set("page", String(options.page));
|
|
55
|
+
if (options?.limit)
|
|
56
|
+
params.set("limit", String(options.limit));
|
|
57
|
+
if (options?.expand?.length)
|
|
58
|
+
params.set("expand", options.expand.join(","));
|
|
59
|
+
if (options?.fields?.length)
|
|
60
|
+
params.set("fields", options.fields.join(","));
|
|
61
|
+
const qs = params.toString() ? `?${params}` : "";
|
|
62
|
+
const data = await rawRequest(`${base}/models/${modelSlug}/entries${qs}`, `getEntries(${modelSlug})`);
|
|
63
|
+
return { items: data.items, total: data.total, hasMore: data.hasMore };
|
|
64
|
+
},
|
|
65
|
+
async getEntry(modelSlug, entrySlug, options) {
|
|
66
|
+
const params = new URLSearchParams();
|
|
67
|
+
if (options?.language)
|
|
68
|
+
params.set("language", options.language);
|
|
69
|
+
if (options?.expand?.length)
|
|
70
|
+
params.set("expand", options.expand.join(","));
|
|
71
|
+
if (options?.fields?.length)
|
|
72
|
+
params.set("fields", options.fields.join(","));
|
|
73
|
+
const qs = params.toString() ? `?${params}` : "";
|
|
74
|
+
return rawRequest(`${base}/models/${modelSlug}/entries/${entrySlug}${qs}`, `getEntry(${modelSlug}/${entrySlug})`);
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
//# sourceMappingURL=http.js.map
|
package/dist/http.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
export { createClient } from "./client.js";
|
|
2
|
+
export { ContentQueryBuilder, SingleQueryBuilder } from "./query-builder.js";
|
|
3
|
+
export { createHttpClient } from "./http.js";
|
|
4
|
+
/** @deprecated Use `createHttpClient` from `./http.js` instead. */
|
|
2
5
|
export { createContentAPIClient } from "./content-api.js";
|
|
3
|
-
export type { ClientConfig, ContentClient, ContentEntry, ContentEntryListItem, ContentEntryStatus, ContentEntrySortField, ContentModel, ListEntriesOptions, GetEntryOptions, PaginatedResponse, RelationValue, } from "./types.js";
|
|
6
|
+
export type { ClientConfig, ContentClient, ContentEntry, ContentEntryListItem, ContentEntryStatus, ContentEntrySortField, ContentModel, ListEntriesOptions, GetEntryOptions, PaginatedResponse, QueryResult, SingleQueryResult, RelationValue, } from "./types.js";
|
|
7
|
+
export type { HttpClient, HttpResult } from "./http.js";
|
|
4
8
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,mEAAmE;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAC1D,YAAY,EACV,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,kBAAkB,EAClB,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,iBAAiB,EACjB,aAAa,GACd,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
1
|
export { createClient } from "./client.js";
|
|
2
|
+
export { ContentQueryBuilder, SingleQueryBuilder } from "./query-builder.js";
|
|
3
|
+
export { createHttpClient } from "./http.js";
|
|
4
|
+
/** @deprecated Use `createHttpClient` from `./http.js` instead. */
|
|
2
5
|
export { createContentAPIClient } from "./content-api.js";
|
|
3
6
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,gBAAgB,EAAE,MAAM,WAAW,CAAC;AAC7C,mEAAmE;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import type { HttpClient } from "./http.js";
|
|
2
|
+
import type { ContentEntry, ContentEntryListItem, ContentEntrySortField, QueryResult, SingleQueryResult } from "./types.js";
|
|
3
|
+
interface QueryParams {
|
|
4
|
+
fields: string[];
|
|
5
|
+
expand: string[];
|
|
6
|
+
filters: Record<string, string>;
|
|
7
|
+
search: string | undefined;
|
|
8
|
+
language: string | undefined;
|
|
9
|
+
status: string | undefined;
|
|
10
|
+
sort: ContentEntrySortField | undefined;
|
|
11
|
+
ascending: boolean | undefined;
|
|
12
|
+
limitVal: number | undefined;
|
|
13
|
+
pageVal: number | undefined;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Terminal builder for fetching a single entry by slug.
|
|
17
|
+
* Thenable — can be awaited directly.
|
|
18
|
+
*/
|
|
19
|
+
export declare class SingleQueryBuilder<CF extends Record<string, string | null> = Record<string, string | null>> {
|
|
20
|
+
private readonly _http;
|
|
21
|
+
private readonly _model;
|
|
22
|
+
private readonly _slug;
|
|
23
|
+
private readonly _params;
|
|
24
|
+
/** @internal */
|
|
25
|
+
constructor(_http: HttpClient, _model: string, _slug: string, _params: QueryParams);
|
|
26
|
+
/** Execute the query. Prefer `await builder` over calling this directly. */
|
|
27
|
+
execute(): Promise<SingleQueryResult<ContentEntry<CF>>>;
|
|
28
|
+
/** Makes this object thenable so `await builder.single("slug")` works. */
|
|
29
|
+
then<TResult1 = SingleQueryResult<ContentEntry<CF>>, TResult2 = never>(onfulfilled?: ((value: SingleQueryResult<ContentEntry<CF>>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Supabase-style chainable query builder for content entries.
|
|
33
|
+
*
|
|
34
|
+
* Each chainable method returns a **new** builder instance (immutable).
|
|
35
|
+
* The builder is thenable — `await` it to execute the query.
|
|
36
|
+
*
|
|
37
|
+
* @example
|
|
38
|
+
* ```typescript
|
|
39
|
+
* const { data, error, total, hasMore } = await client
|
|
40
|
+
* .from("blog-posts")
|
|
41
|
+
* .select("title", "body")
|
|
42
|
+
* .eq("status", "published")
|
|
43
|
+
* .order("publishedAt", { ascending: false })
|
|
44
|
+
* .limit(10)
|
|
45
|
+
* .language("en");
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare class ContentQueryBuilder<T = ContentEntryListItem> {
|
|
49
|
+
private readonly _http;
|
|
50
|
+
private readonly _model;
|
|
51
|
+
private readonly _params;
|
|
52
|
+
/** @internal — use `ContentQueryBuilder.create()` */
|
|
53
|
+
private constructor();
|
|
54
|
+
/** @internal */
|
|
55
|
+
static create(http: HttpClient, model: string): ContentQueryBuilder;
|
|
56
|
+
private clone;
|
|
57
|
+
/**
|
|
58
|
+
* Choose which fields to include in the response.
|
|
59
|
+
*
|
|
60
|
+
* @example `.select("title", "body", "category")`
|
|
61
|
+
*/
|
|
62
|
+
select(...fields: string[]): ContentQueryBuilder<T>;
|
|
63
|
+
/**
|
|
64
|
+
* Filter by a built-in field value (status, etc.).
|
|
65
|
+
*
|
|
66
|
+
* @example `.eq("status", "published")`
|
|
67
|
+
*/
|
|
68
|
+
eq(field: string, value: string): ContentQueryBuilder<T>;
|
|
69
|
+
/**
|
|
70
|
+
* Filter by a custom field value. Maps to `?filter[field]=value` on the REST API.
|
|
71
|
+
*
|
|
72
|
+
* @example `.filter("category", "engineering")`
|
|
73
|
+
*/
|
|
74
|
+
filter(field: string, value: string): ContentQueryBuilder<T>;
|
|
75
|
+
/**
|
|
76
|
+
* Full-text search on entry titles.
|
|
77
|
+
*
|
|
78
|
+
* @example `.search("kubernetes")`
|
|
79
|
+
*/
|
|
80
|
+
search(term: string): ContentQueryBuilder<T>;
|
|
81
|
+
/**
|
|
82
|
+
* Set the language for localized content.
|
|
83
|
+
*
|
|
84
|
+
* @example `.language("fr")`
|
|
85
|
+
*/
|
|
86
|
+
language(code: string): ContentQueryBuilder<T>;
|
|
87
|
+
/**
|
|
88
|
+
* Set the sort field and direction.
|
|
89
|
+
*
|
|
90
|
+
* @example `.order("publishedAt", { ascending: false })`
|
|
91
|
+
*/
|
|
92
|
+
order(field: ContentEntrySortField, opts?: {
|
|
93
|
+
ascending?: boolean;
|
|
94
|
+
}): ContentQueryBuilder<T>;
|
|
95
|
+
/**
|
|
96
|
+
* Limit the number of results per page (1-100).
|
|
97
|
+
*
|
|
98
|
+
* @example `.limit(10)`
|
|
99
|
+
*/
|
|
100
|
+
limit(n: number): ContentQueryBuilder<T>;
|
|
101
|
+
/**
|
|
102
|
+
* Set the page number (1-based).
|
|
103
|
+
*
|
|
104
|
+
* @example `.page(2)`
|
|
105
|
+
*/
|
|
106
|
+
page(n: number): ContentQueryBuilder<T>;
|
|
107
|
+
/**
|
|
108
|
+
* Expand relation fields by name.
|
|
109
|
+
*
|
|
110
|
+
* @example `.expand("author", "category")`
|
|
111
|
+
*/
|
|
112
|
+
expand(...fields: string[]): ContentQueryBuilder<T>;
|
|
113
|
+
/**
|
|
114
|
+
* Switch to single-entry mode. Returns a thenable that resolves a single entry.
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```typescript
|
|
118
|
+
* const { data: post, error } = await client
|
|
119
|
+
* .from("blog-posts")
|
|
120
|
+
* .language("fr")
|
|
121
|
+
* .single("hello-world");
|
|
122
|
+
* ```
|
|
123
|
+
*/
|
|
124
|
+
single<CF extends Record<string, string | null> = Record<string, string | null>>(slug: string): SingleQueryBuilder<CF>;
|
|
125
|
+
/**
|
|
126
|
+
* Execute the list query. Prefer `await builder` over calling this directly.
|
|
127
|
+
*/
|
|
128
|
+
execute(): Promise<QueryResult<T[]>>;
|
|
129
|
+
/** Makes this object thenable so `await client.from("posts").limit(5)` works. */
|
|
130
|
+
then<TResult1 = QueryResult<T[]>, TResult2 = never>(onfulfilled?: ((value: QueryResult<T[]>) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
|
131
|
+
private buildSearchParams;
|
|
132
|
+
}
|
|
133
|
+
export {};
|
|
134
|
+
//# sourceMappingURL=query-builder.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.d.ts","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
function emptyParams() {
|
|
2
|
+
return {
|
|
3
|
+
fields: [],
|
|
4
|
+
expand: [],
|
|
5
|
+
filters: {},
|
|
6
|
+
search: undefined,
|
|
7
|
+
language: undefined,
|
|
8
|
+
status: undefined,
|
|
9
|
+
sort: undefined,
|
|
10
|
+
ascending: undefined,
|
|
11
|
+
limitVal: undefined,
|
|
12
|
+
pageVal: undefined,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
// ─── SingleQueryBuilder ─────────────────────────────────────────────
|
|
16
|
+
/**
|
|
17
|
+
* Terminal builder for fetching a single entry by slug.
|
|
18
|
+
* Thenable — can be awaited directly.
|
|
19
|
+
*/
|
|
20
|
+
export class SingleQueryBuilder {
|
|
21
|
+
_http;
|
|
22
|
+
_model;
|
|
23
|
+
_slug;
|
|
24
|
+
_params;
|
|
25
|
+
/** @internal */
|
|
26
|
+
constructor(_http, _model, _slug, _params) {
|
|
27
|
+
this._http = _http;
|
|
28
|
+
this._model = _model;
|
|
29
|
+
this._slug = _slug;
|
|
30
|
+
this._params = _params;
|
|
31
|
+
}
|
|
32
|
+
/** Execute the query. Prefer `await builder` over calling this directly. */
|
|
33
|
+
async execute() {
|
|
34
|
+
const params = new URLSearchParams();
|
|
35
|
+
if (this._params.language)
|
|
36
|
+
params.set("language", this._params.language);
|
|
37
|
+
if (this._params.fields.length)
|
|
38
|
+
params.set("fields", this._params.fields.join(","));
|
|
39
|
+
if (this._params.expand.length)
|
|
40
|
+
params.set("expand", this._params.expand.join(","));
|
|
41
|
+
const result = await this._http.request(`/models/${this._model}/entries/${this._slug}`, params);
|
|
42
|
+
if (result.error) {
|
|
43
|
+
return { data: null, error: result.error };
|
|
44
|
+
}
|
|
45
|
+
return { data: result.data, error: null };
|
|
46
|
+
}
|
|
47
|
+
/** Makes this object thenable so `await builder.single("slug")` works. */
|
|
48
|
+
then(onfulfilled, onrejected) {
|
|
49
|
+
return this.execute().then(onfulfilled, onrejected);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
// ─── ContentQueryBuilder ────────────────────────────────────────────
|
|
53
|
+
/**
|
|
54
|
+
* Supabase-style chainable query builder for content entries.
|
|
55
|
+
*
|
|
56
|
+
* Each chainable method returns a **new** builder instance (immutable).
|
|
57
|
+
* The builder is thenable — `await` it to execute the query.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const { data, error, total, hasMore } = await client
|
|
62
|
+
* .from("blog-posts")
|
|
63
|
+
* .select("title", "body")
|
|
64
|
+
* .eq("status", "published")
|
|
65
|
+
* .order("publishedAt", { ascending: false })
|
|
66
|
+
* .limit(10)
|
|
67
|
+
* .language("en");
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export class ContentQueryBuilder {
|
|
71
|
+
_http;
|
|
72
|
+
_model;
|
|
73
|
+
_params;
|
|
74
|
+
/** @internal — use `ContentQueryBuilder.create()` */
|
|
75
|
+
constructor(_http, _model, _params) {
|
|
76
|
+
this._http = _http;
|
|
77
|
+
this._model = _model;
|
|
78
|
+
this._params = _params;
|
|
79
|
+
}
|
|
80
|
+
/** @internal */
|
|
81
|
+
static create(http, model) {
|
|
82
|
+
return new ContentQueryBuilder(http, model, emptyParams());
|
|
83
|
+
}
|
|
84
|
+
// ─── Private helpers ────────────────────────────────────────────
|
|
85
|
+
clone(patch) {
|
|
86
|
+
return new ContentQueryBuilder(this._http, this._model, {
|
|
87
|
+
...this._params,
|
|
88
|
+
...patch,
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
// ─── Chainable methods ──────────────────────────────────────────
|
|
92
|
+
/**
|
|
93
|
+
* Choose which fields to include in the response.
|
|
94
|
+
*
|
|
95
|
+
* @example `.select("title", "body", "category")`
|
|
96
|
+
*/
|
|
97
|
+
select(...fields) {
|
|
98
|
+
return this.clone({ fields: [...this._params.fields, ...fields] });
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Filter by a built-in field value (status, etc.).
|
|
102
|
+
*
|
|
103
|
+
* @example `.eq("status", "published")`
|
|
104
|
+
*/
|
|
105
|
+
eq(field, value) {
|
|
106
|
+
if (field === "status") {
|
|
107
|
+
return this.clone({ status: value });
|
|
108
|
+
}
|
|
109
|
+
return this.clone({
|
|
110
|
+
filters: { ...this._params.filters, [field]: value },
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Filter by a custom field value. Maps to `?filter[field]=value` on the REST API.
|
|
115
|
+
*
|
|
116
|
+
* @example `.filter("category", "engineering")`
|
|
117
|
+
*/
|
|
118
|
+
filter(field, value) {
|
|
119
|
+
return this.clone({
|
|
120
|
+
filters: { ...this._params.filters, [field]: value },
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Full-text search on entry titles.
|
|
125
|
+
*
|
|
126
|
+
* @example `.search("kubernetes")`
|
|
127
|
+
*/
|
|
128
|
+
search(term) {
|
|
129
|
+
return this.clone({ search: term });
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Set the language for localized content.
|
|
133
|
+
*
|
|
134
|
+
* @example `.language("fr")`
|
|
135
|
+
*/
|
|
136
|
+
language(code) {
|
|
137
|
+
return this.clone({ language: code });
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Set the sort field and direction.
|
|
141
|
+
*
|
|
142
|
+
* @example `.order("publishedAt", { ascending: false })`
|
|
143
|
+
*/
|
|
144
|
+
order(field, opts) {
|
|
145
|
+
return this.clone({
|
|
146
|
+
sort: field,
|
|
147
|
+
ascending: opts?.ascending,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* Limit the number of results per page (1-100).
|
|
152
|
+
*
|
|
153
|
+
* @example `.limit(10)`
|
|
154
|
+
*/
|
|
155
|
+
limit(n) {
|
|
156
|
+
return this.clone({ limitVal: n });
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Set the page number (1-based).
|
|
160
|
+
*
|
|
161
|
+
* @example `.page(2)`
|
|
162
|
+
*/
|
|
163
|
+
page(n) {
|
|
164
|
+
return this.clone({ pageVal: n });
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Expand relation fields by name.
|
|
168
|
+
*
|
|
169
|
+
* @example `.expand("author", "category")`
|
|
170
|
+
*/
|
|
171
|
+
expand(...fields) {
|
|
172
|
+
return this.clone({ expand: [...this._params.expand, ...fields] });
|
|
173
|
+
}
|
|
174
|
+
// ─── Terminal methods ───────────────────────────────────────────
|
|
175
|
+
/**
|
|
176
|
+
* Switch to single-entry mode. Returns a thenable that resolves a single entry.
|
|
177
|
+
*
|
|
178
|
+
* @example
|
|
179
|
+
* ```typescript
|
|
180
|
+
* const { data: post, error } = await client
|
|
181
|
+
* .from("blog-posts")
|
|
182
|
+
* .language("fr")
|
|
183
|
+
* .single("hello-world");
|
|
184
|
+
* ```
|
|
185
|
+
*/
|
|
186
|
+
single(slug) {
|
|
187
|
+
return new SingleQueryBuilder(this._http, this._model, slug, this._params);
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Execute the list query. Prefer `await builder` over calling this directly.
|
|
191
|
+
*/
|
|
192
|
+
async execute() {
|
|
193
|
+
const params = this.buildSearchParams();
|
|
194
|
+
const result = await this._http.request(`/models/${this._model}/entries`, params);
|
|
195
|
+
if (result.error) {
|
|
196
|
+
return { data: null, error: result.error, total: 0, hasMore: false };
|
|
197
|
+
}
|
|
198
|
+
return {
|
|
199
|
+
data: result.data.items,
|
|
200
|
+
error: null,
|
|
201
|
+
total: result.data.total,
|
|
202
|
+
hasMore: result.data.hasMore,
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
/** Makes this object thenable so `await client.from("posts").limit(5)` works. */
|
|
206
|
+
then(onfulfilled, onrejected) {
|
|
207
|
+
return this.execute().then(onfulfilled, onrejected);
|
|
208
|
+
}
|
|
209
|
+
// ─── Internal ───────────────────────────────────────────────────
|
|
210
|
+
buildSearchParams() {
|
|
211
|
+
const params = new URLSearchParams();
|
|
212
|
+
if (this._params.language)
|
|
213
|
+
params.set("language", this._params.language);
|
|
214
|
+
if (this._params.status)
|
|
215
|
+
params.set("status", this._params.status);
|
|
216
|
+
if (this._params.sort)
|
|
217
|
+
params.set("sort", this._params.sort);
|
|
218
|
+
if (this._params.ascending !== undefined) {
|
|
219
|
+
params.set("order", this._params.ascending ? "asc" : "desc");
|
|
220
|
+
}
|
|
221
|
+
if (this._params.pageVal)
|
|
222
|
+
params.set("page", String(this._params.pageVal));
|
|
223
|
+
if (this._params.limitVal)
|
|
224
|
+
params.set("limit", String(this._params.limitVal));
|
|
225
|
+
if (this._params.fields.length)
|
|
226
|
+
params.set("fields", this._params.fields.join(","));
|
|
227
|
+
if (this._params.expand.length)
|
|
228
|
+
params.set("expand", this._params.expand.join(","));
|
|
229
|
+
if (this._params.search)
|
|
230
|
+
params.set("search", this._params.search);
|
|
231
|
+
for (const [key, value] of Object.entries(this._params.filters)) {
|
|
232
|
+
params.set(`filter[${key}]`, value);
|
|
233
|
+
}
|
|
234
|
+
return params;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
//# sourceMappingURL=query-builder.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"query-builder.js","sourceRoot":"","sources":["../src/query-builder.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
|
@@ -9,8 +9,8 @@ export interface ClientConfig {
|
|
|
9
9
|
/** Enable debug logging to see request URLs, headers, and responses. */
|
|
10
10
|
debug?: boolean;
|
|
11
11
|
}
|
|
12
|
-
/** Expanded relation value returned when a relation field is expanded. */
|
|
13
|
-
export
|
|
12
|
+
/** Expanded relation value returned when a relation field is expanded. Custom fields are spread directly on the object. */
|
|
13
|
+
export type RelationValue = {
|
|
14
14
|
/** Referenced entry UUID */
|
|
15
15
|
id: string;
|
|
16
16
|
/** Referenced entry slug */
|
|
@@ -19,11 +19,10 @@ export interface RelationValue {
|
|
|
19
19
|
title: string;
|
|
20
20
|
/** Target model slug */
|
|
21
21
|
modelSlug: string;
|
|
22
|
-
|
|
23
|
-
customFields?: Record<string, string | null>;
|
|
24
|
-
}
|
|
22
|
+
} & Record<string, string | null>;
|
|
25
23
|
/**
|
|
26
24
|
* A full content entry with all localized fields.
|
|
25
|
+
* Custom fields are spread directly on the entry object (flat access).
|
|
27
26
|
*
|
|
28
27
|
* @typeParam CF - Custom fields shape. Defaults to `Record<string, string | null>`.
|
|
29
28
|
*
|
|
@@ -31,38 +30,36 @@ export interface RelationValue {
|
|
|
31
30
|
* ```typescript
|
|
32
31
|
* // Typed custom fields
|
|
33
32
|
* interface BlogFields { readingTime: string | null; category: string | null }
|
|
34
|
-
* const post = await client.
|
|
35
|
-
* post.
|
|
33
|
+
* const { data: post } = await client.from("blog").single<BlogFields>("hello-world");
|
|
34
|
+
* post.readingTime; // string | null (typed!)
|
|
35
|
+
* post.category; // string | null (typed!)
|
|
36
36
|
* ```
|
|
37
37
|
*/
|
|
38
|
-
export
|
|
38
|
+
export type ContentEntry<CF extends Record<string, string | null> = Record<string, string | null>> = {
|
|
39
39
|
id: string;
|
|
40
40
|
slug: string;
|
|
41
41
|
status: "draft" | "published" | "archived";
|
|
42
42
|
publishedAt: string | null;
|
|
43
43
|
sourceLanguage: string;
|
|
44
44
|
availableLanguages: string[];
|
|
45
|
-
customFields: CF;
|
|
46
45
|
/** Expanded relation fields (only present when expand is used) */
|
|
47
46
|
relations?: Record<string, RelationValue | null>;
|
|
48
47
|
title: string;
|
|
49
48
|
/** Rich text body as Markdown string. */
|
|
50
49
|
body: string | null;
|
|
51
|
-
}
|
|
50
|
+
} & CF;
|
|
52
51
|
/** Entry status filter values. */
|
|
53
52
|
export type ContentEntryStatus = "draft" | "published" | "archived";
|
|
54
|
-
/** A summary item for content entry lists. */
|
|
55
|
-
export
|
|
53
|
+
/** A summary item for content entry lists. Custom fields are spread directly on the object. */
|
|
54
|
+
export type ContentEntryListItem<CF extends Record<string, string | null> = Record<string, string | null>> = {
|
|
56
55
|
slug: string;
|
|
57
56
|
title: string;
|
|
58
57
|
publishedAt: string | null;
|
|
59
58
|
/** Markdown body — only present when `fields` includes `"body"`. */
|
|
60
59
|
body?: string | null;
|
|
61
|
-
/** Custom fields — only present when `fields` includes specific field names. */
|
|
62
|
-
customFields?: Record<string, string | null>;
|
|
63
60
|
/** Expanded relation fields (only present when expand is used) */
|
|
64
61
|
relations?: Record<string, RelationValue | null>;
|
|
65
|
-
}
|
|
62
|
+
} & CF;
|
|
66
63
|
/** Paginated response wrapper. */
|
|
67
64
|
export interface PaginatedResponse<T> {
|
|
68
65
|
items: T[];
|
|
@@ -77,6 +74,18 @@ export interface ContentModel {
|
|
|
77
74
|
kind: string;
|
|
78
75
|
entryCount: number;
|
|
79
76
|
}
|
|
77
|
+
/** Result of a list query — Supabase-style `{ data, error }` pattern. */
|
|
78
|
+
export interface QueryResult<T> {
|
|
79
|
+
data: T | null;
|
|
80
|
+
error: Error | null;
|
|
81
|
+
total: number;
|
|
82
|
+
hasMore: boolean;
|
|
83
|
+
}
|
|
84
|
+
/** Result of a single-entry query — Supabase-style `{ data, error }` pattern. */
|
|
85
|
+
export interface SingleQueryResult<T> {
|
|
86
|
+
data: T | null;
|
|
87
|
+
error: Error | null;
|
|
88
|
+
}
|
|
80
89
|
/** Sortable fields for content entries. */
|
|
81
90
|
export type ContentEntrySortField = "publishedAt" | "createdAt" | "updatedAt" | "title";
|
|
82
91
|
/** Options for listing content entries. */
|
|
@@ -107,13 +116,33 @@ export interface GetEntryOptions {
|
|
|
107
116
|
/** Relation field names to expand (e.g., ["category", "author"]) */
|
|
108
117
|
expand?: string[];
|
|
109
118
|
}
|
|
119
|
+
import type { ContentQueryBuilder } from "./query-builder.js";
|
|
110
120
|
/** Client for fetching content entries and models. */
|
|
111
121
|
export interface ContentClient {
|
|
122
|
+
/**
|
|
123
|
+
* Start a chainable query for a content model — Supabase-style API.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* ```typescript
|
|
127
|
+
* const { data, error } = await client
|
|
128
|
+
* .from("blog-posts")
|
|
129
|
+
* .eq("status", "published")
|
|
130
|
+
* .order("publishedAt", { ascending: false })
|
|
131
|
+
* .limit(10);
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
from(modelSlug: string): ContentQueryBuilder;
|
|
112
135
|
/** List all content models in the project. */
|
|
113
136
|
getModels(): Promise<ContentModel[]>;
|
|
114
|
-
/**
|
|
137
|
+
/**
|
|
138
|
+
* List entries for a content model with pagination.
|
|
139
|
+
* @deprecated Use `client.from(modelSlug)` for a chainable, composable API.
|
|
140
|
+
*/
|
|
115
141
|
getEntries(modelSlug: string, options?: ListEntriesOptions): Promise<PaginatedResponse<ContentEntryListItem>>;
|
|
116
|
-
/**
|
|
142
|
+
/**
|
|
143
|
+
* Fetch a single content entry by slug.
|
|
144
|
+
* @deprecated Use `client.from(modelSlug).single(slug)` for error-safe API.
|
|
145
|
+
*/
|
|
117
146
|
getEntry<CF extends Record<string, string | null> = Record<string, string | null>>(modelSlug: string, entrySlug: string, options?: GetEntryOptions): Promise<ContentEntry<CF>>;
|
|
118
147
|
}
|
|
119
148
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,+DAA+D;AAC/D,MAAM,WAAW,YAAY;IAC3B,8GAA8G;IAC9G,OAAO,EAAE,MAAM,CAAC;IAChB,6DAA6D;IAC7D,MAAM,EAAE,MAAM,CAAC;IACf,wEAAwE;IACxE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@better-i18n/sdk",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "3.0.0",
|
|
4
4
|
"description": "Content SDK for Better i18n - headless CMS client for fetching content models and entries",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"README.md"
|
|
18
18
|
],
|
|
19
19
|
"scripts": {
|
|
20
|
-
"build": "tsc",
|
|
20
|
+
"build": "tsc -b --force",
|
|
21
21
|
"typecheck": "tsc --noEmit",
|
|
22
22
|
"clean": "rm -rf dist",
|
|
23
23
|
"prepublishOnly": "bun run build"
|