@better-i18n/sdk 2.0.0 → 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 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, sort by date or title
12
- - ⚡ **Lightweight** — Thin wrapper over REST API
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,76 +28,144 @@ const client = createClient({
27
28
  apiKey: process.env.BETTER_I18N_API_KEY!,
28
29
  });
29
30
 
30
- // List content models
31
- const models = await client.getModels();
32
-
33
- // List published blog posts
34
- const { items, total, hasMore } = await client.getEntries("blog-posts", {
35
- status: "published",
36
- sort: "publishedAt",
37
- order: "desc",
38
- language: "en",
39
- limit: 10,
40
- });
41
-
42
- // Get a single entry with localized content
43
- const post = await client.getEntry("blog-posts", "hello-world", {
44
- language: "fr",
45
- });
46
- console.log(post.title, post.bodyMarkdown);
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
- ## API
51
+ ## Chainable Query Builder
50
52
 
51
- | Method | Description |
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
- ### `getEntries` Options
55
+ Every chain method returns a **new** builder instance, so you can safely reuse base queries:
58
56
 
59
- | Option | Type | Default | Description |
60
- | --- | --- | --- | --- |
61
- | `language` | `string` | source language | Language code for localized content |
62
- | `status` | `"draft" \| "published" \| "archived"` | all | Filter by entry status |
63
- | `sort` | `"publishedAt" \| "createdAt" \| "updatedAt" \| "title"` | `"updatedAt"` | Sort field |
64
- | `order` | `"asc" \| "desc"` | `"desc"` | Sort direction |
65
- | `page` | `number` | `1` | Page number (1-based) |
66
- | `limit` | `number` | `50` | Entries per page (1-100) |
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
+ ```
67
71
 
68
- ### `getEntry` Options
72
+ ### Chain Methods
69
73
 
70
- | Option | Type | Default | Description |
71
- | --- | --- | --- | --- |
72
- | `language` | `string` | source language | Language code for localized content |
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 }` |
73
92
 
74
93
  ### Response Types
75
94
 
76
- **`getEntries` returns `PaginatedResponse<ContentEntryListItem>`:**
95
+ **List query returns `QueryResult<T[]>`:**
77
96
 
78
97
  ```typescript
79
98
  {
80
- items: ContentEntryListItem[]; // slug, title, excerpt, publishedAt, tags, author
81
- total: number; // total matching entries
82
- hasMore: boolean; // more pages available
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
83
103
  }
84
104
  ```
85
105
 
86
- **`getEntry` returns `ContentEntry<CF>`:**
106
+ **Single query returns `SingleQueryResult<ContentEntry>`:**
87
107
 
88
108
  ```typescript
89
109
  {
90
- id, slug, status, publishedAt, sourceLanguage, availableLanguages,
91
- featuredImage, tags, author, customFields,
92
- title, excerpt, body, bodyHtml, bodyMarkdown,
93
- metaTitle, metaDescription
110
+ data: ContentEntry | null; // null on error
111
+ error: Error | null; // null on success
94
112
  }
95
113
  ```
96
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
+
97
165
  ## Typed Custom Fields
98
166
 
99
- Use the generic type parameter for type-safe custom fields:
167
+ Custom fields are returned flat directly on the entry object (no `customFields` wrapper).
168
+ Use the generic type parameter for type-safe access:
100
169
 
101
170
  ```typescript
102
171
  interface BlogFields {
@@ -104,9 +173,65 @@ interface BlogFields {
104
173
  category: string | null;
105
174
  }
106
175
 
107
- const post = await client.getEntry<BlogFields>("blog-posts", "hello-world");
108
- post.customFields.readingTime; // string | null (typed!)
109
- post.customFields.category; // string | null (typed!)
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
+ }
184
+ ```
185
+
186
+ ## Expanding Relations
187
+
188
+ Use `expand` to resolve related entries in a single request:
189
+
190
+ ```typescript
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
+ }
201
+ ```
202
+
203
+ Each expanded relation is a `RelationValue` object with custom fields spread directly:
204
+
205
+ ```typescript
206
+ type RelationValue = {
207
+ id: string;
208
+ slug: string;
209
+ title: string;
210
+ modelSlug: string;
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
+ });
110
235
  ```
111
236
 
112
237
  ## Configuration
@@ -115,7 +240,8 @@ post.customFields.category; // string | null (typed!)
115
240
  | --- | --- | --- |
116
241
  | `project` | Yes | Project identifier in `org/project` format (e.g., `"acme/web-app"`) |
117
242
  | `apiKey` | Yes | API key from [dashboard](https://dash.better-i18n.com) |
118
- | `apiBase` | No | API base URL (default: `https://dash.better-i18n.com`) |
243
+ | `apiBase` | No | API base URL (default: `https://content.better-i18n.com`) |
244
+ | `debug` | No | Enable debug logging for request/response inspection |
119
245
 
120
246
  ## Documentation
121
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
- * Fetches content models and entries from the REST API.
6
- * Requires an API key for authentication.
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;
@@ -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;AAK9D;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAoBhE"}
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 { createContentAPIClient } from "./content-api.js";
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
- * Fetches content models and entries from the REST API.
7
- * Requires an API key for authentication.
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
- return createContentAPIClient(apiBase, org, project, config.apiKey, config.debug);
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
@@ -1 +1 @@
1
- {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,sBAAsB,EAAE,MAAM,kBAAkB,CAAC;AAE1D,MAAM,gBAAgB,GAAG,iCAAiC,CAAC;AAE3D;;;;;;;;;;;;;;;;;GAiBG;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,OAAO,sBAAsB,CAAC,OAAO,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;AACpF,CAAC"}
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"}
@@ -1,14 +1,5 @@
1
- import type { ContentClient } from "./types.js";
2
1
  /**
3
- * Creates a content client that fetches from the REST API.
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 declare function createContentAPIClient(apiBase: string, org: string, project: string, apiKey: string, debug?: boolean): ContentClient;
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,OAAO,KAAK,EACV,aAAa,EAOd,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;GAUG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,KAAK,UAAQ,GACZ,aAAa,CA+Ef"}
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"}
@@ -1,82 +1,5 @@
1
1
  /**
2
- * Creates a content client that fetches from the REST API.
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 function createContentAPIClient(apiBase, org, project, apiKey, debug = false) {
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
@@ -1 +1 @@
1
- {"version":3,"file":"content-api.js","sourceRoot":"","sources":["../src/content-api.ts"],"names":[],"mappings":"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"}
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
@@ -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
@@ -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
@@ -4,13 +4,13 @@ export interface ClientConfig {
4
4
  project: string;
5
5
  /** API key for authenticating content requests. Required. */
6
6
  apiKey: string;
7
- /** REST API base URL. Defaults to `https://dash.better-i18n.com`. */
7
+ /** REST API base URL. Defaults to `https://content.better-i18n.com`. */
8
8
  apiBase?: string;
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 interface RelationValue {
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,9 +19,10 @@ export interface RelationValue {
19
19
  title: string;
20
20
  /** Target model slug */
21
21
  modelSlug: string;
22
- }
22
+ } & Record<string, string | null>;
23
23
  /**
24
24
  * A full content entry with all localized fields.
25
+ * Custom fields are spread directly on the entry object (flat access).
25
26
  *
26
27
  * @typeParam CF - Custom fields shape. Defaults to `Record<string, string | null>`.
27
28
  *
@@ -29,38 +30,36 @@ export interface RelationValue {
29
30
  * ```typescript
30
31
  * // Typed custom fields
31
32
  * interface BlogFields { readingTime: string | null; category: string | null }
32
- * const post = await client.getEntry<BlogFields>("blog", "hello-world");
33
- * post.customFields.readingTime; // string | null (typed!)
33
+ * const { data: post } = await client.from("blog").single<BlogFields>("hello-world");
34
+ * post.readingTime; // string | null (typed!)
35
+ * post.category; // string | null (typed!)
34
36
  * ```
35
37
  */
36
- export interface ContentEntry<CF extends Record<string, string | null> = Record<string, string | null>> {
38
+ export type ContentEntry<CF extends Record<string, string | null> = Record<string, string | null>> = {
37
39
  id: string;
38
40
  slug: string;
39
41
  status: "draft" | "published" | "archived";
40
42
  publishedAt: string | null;
41
43
  sourceLanguage: string;
42
44
  availableLanguages: string[];
43
- customFields: CF;
44
45
  /** Expanded relation fields (only present when expand is used) */
45
46
  relations?: Record<string, RelationValue | null>;
46
47
  title: string;
47
48
  /** Rich text body as Markdown string. */
48
49
  body: string | null;
49
- }
50
+ } & CF;
50
51
  /** Entry status filter values. */
51
52
  export type ContentEntryStatus = "draft" | "published" | "archived";
52
- /** A summary item for content entry lists. */
53
- export interface ContentEntryListItem {
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>> = {
54
55
  slug: string;
55
56
  title: string;
56
57
  publishedAt: string | null;
57
58
  /** Markdown body — only present when `fields` includes `"body"`. */
58
59
  body?: string | null;
59
- /** Custom fields — only present when `fields` includes specific field names. */
60
- customFields?: Record<string, string | null>;
61
60
  /** Expanded relation fields (only present when expand is used) */
62
61
  relations?: Record<string, RelationValue | null>;
63
- }
62
+ } & CF;
64
63
  /** Paginated response wrapper. */
65
64
  export interface PaginatedResponse<T> {
66
65
  items: T[];
@@ -75,6 +74,18 @@ export interface ContentModel {
75
74
  kind: string;
76
75
  entryCount: number;
77
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
+ }
78
89
  /** Sortable fields for content entries. */
79
90
  export type ContentEntrySortField = "publishedAt" | "createdAt" | "updatedAt" | "title";
80
91
  /** Options for listing content entries. */
@@ -105,13 +116,33 @@ export interface GetEntryOptions {
105
116
  /** Relation field names to expand (e.g., ["category", "author"]) */
106
117
  expand?: string[];
107
118
  }
119
+ import type { ContentQueryBuilder } from "./query-builder.js";
108
120
  /** Client for fetching content entries and models. */
109
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;
110
135
  /** List all content models in the project. */
111
136
  getModels(): Promise<ContentModel[]>;
112
- /** List entries for a content model with pagination. */
137
+ /**
138
+ * List entries for a content model with pagination.
139
+ * @deprecated Use `client.from(modelSlug)` for a chainable, composable API.
140
+ */
113
141
  getEntries(modelSlug: string, options?: ListEntriesOptions): Promise<PaginatedResponse<ContentEntryListItem>>;
114
- /** Fetch a single content entry by slug. */
142
+ /**
143
+ * Fetch a single content entry by slug.
144
+ * @deprecated Use `client.from(modelSlug).single(slug)` for error-safe API.
145
+ */
115
146
  getEntry<CF extends Record<string, string | null> = Record<string, string | null>>(modelSlug: string, entrySlug: string, options?: GetEntryOptions): Promise<ContentEntry<CF>>;
116
147
  }
117
148
  //# sourceMappingURL=types.d.ts.map
@@ -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,qEAAqE;IACrE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,KAAK,CAAC,EAAE,OAAO,CAAC;CACjB;AAID,0EAA0E;AAC1E,MAAM,WAAW,aAAa;IAC5B,4BAA4B;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,4BAA4B;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,qEAAqE;IACrE,KAAK,EAAE,MAAM,CAAC;IACd,wBAAwB;IACxB,SAAS,EAAE,MAAM,CAAC;CACnB;AAID;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,YAAY,CAAC,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC;IACpG,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;IAC3C,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,EAAE,MAAM,EAAE,CAAC;IAC7B,YAAY,EAAE,EAAE,CAAC;IACjB,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;IAEjD,KAAK,EAAE,MAAM,CAAC;IACd,yCAAyC;IACzC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;CACrB;AAED,kCAAkC;AAClC,MAAM,MAAM,kBAAkB,GAAG,OAAO,GAAG,WAAW,GAAG,UAAU,CAAC;AAEpE,8CAA8C;AAC9C,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,gFAAgF;IAChF,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,kEAAkE;IAClE,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC,CAAC;CAClD;AAED,kCAAkC;AAClC,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,KAAK,EAAE,CAAC,EAAE,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,kCAAkC;AAClC,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;CACpB;AAID,2CAA2C;AAC3C,MAAM,MAAM,qBAAqB,GAAG,aAAa,GAAG,WAAW,GAAG,WAAW,GAAG,OAAO,CAAC;AAExF,2CAA2C;AAC3C,MAAM,WAAW,kBAAkB;IACjC,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,MAAM,CAAC,EAAE,kBAAkB,CAAC;IAC5B,mDAAmD;IACnD,IAAI,CAAC,EAAE,qBAAqB,CAAC;IAC7B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,6BAA6B;IAC7B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,gHAAgH;IAChH,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,mDAAmD;AACnD,MAAM,WAAW,eAAe;IAC9B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,oGAAoG;IACpG,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;IAClB,oEAAoE;IACpE,MAAM,CAAC,EAAE,MAAM,EAAE,CAAC;CACnB;AAED,sDAAsD;AACtD,MAAM,WAAW,aAAa;IAC5B,8CAA8C;IAC9C,SAAS,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC,CAAC;IACrC,wDAAwD;IACxD,UAAU,CACR,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC,iBAAiB,CAAC,oBAAoB,CAAC,CAAC,CAAC;IACpD,4CAA4C;IAC5C,QAAQ,CAAC,EAAE,SAAS,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,EAC/E,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,EACjB,OAAO,CAAC,EAAE,eAAe,GACxB,OAAO,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;CAC9B"}
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": "2.0.0",
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"