@flexacms/client 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.md +61 -2
- package/dist/index.cjs +352 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +300 -0
- package/dist/index.d.ts +300 -0
- package/dist/index.js +319 -0
- package/dist/index.js.map +1 -0
- package/package.json +53 -5
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shapes returned by the Flexa content API (`/api/v1`). Keys are kept exactly
|
|
3
|
+
* as the API sends them (snake_case), so responses can be passed around as-is.
|
|
4
|
+
*/
|
|
5
|
+
type EntryStatus = 'draft' | 'published' | 'archived';
|
|
6
|
+
/** Values of a translatable field: one entry per configured locale. */
|
|
7
|
+
type Localized<T = string> = {
|
|
8
|
+
[locale: string]: T | null | undefined;
|
|
9
|
+
};
|
|
10
|
+
/** Field values of an entry, keyed by field key. Narrowed by generated types. */
|
|
11
|
+
type EntryValues = Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Maps entity slugs to the values of their entries. Generate it for your
|
|
14
|
+
* workspace with `npx @flexacms/cli generate` to get typed `client.entity()`.
|
|
15
|
+
*/
|
|
16
|
+
type ContentSchema = Record<string, EntryValues>;
|
|
17
|
+
/** A file URL, a list of them, translations of them, or repeater items holding them. */
|
|
18
|
+
type EntryMedia = string | null | (string | null)[] | {
|
|
19
|
+
[locale: string]: string | string[] | null;
|
|
20
|
+
} | Record<string, string | string[] | null>[];
|
|
21
|
+
interface Category {
|
|
22
|
+
id: number;
|
|
23
|
+
name: string;
|
|
24
|
+
slug: string;
|
|
25
|
+
}
|
|
26
|
+
interface RelatedEntry {
|
|
27
|
+
id: number;
|
|
28
|
+
title: string | null;
|
|
29
|
+
slug: string | null;
|
|
30
|
+
status: EntryStatus;
|
|
31
|
+
}
|
|
32
|
+
interface Entry<TValues extends object = EntryValues> {
|
|
33
|
+
id: number;
|
|
34
|
+
entity_id: number;
|
|
35
|
+
entity_slug: string;
|
|
36
|
+
title: string | null;
|
|
37
|
+
slug: string | null;
|
|
38
|
+
status: EntryStatus;
|
|
39
|
+
order: number | null;
|
|
40
|
+
categories: Category[];
|
|
41
|
+
values: TValues;
|
|
42
|
+
/**
|
|
43
|
+
* Absolute URLs of the files in image and file fields, keyed by field key
|
|
44
|
+
* and shaped like their values (`values` keeps the stored paths).
|
|
45
|
+
* Repeaters list their media sub-fields per item. Sent by Flexa 0.2+.
|
|
46
|
+
*/
|
|
47
|
+
media?: Record<string, EntryMedia>;
|
|
48
|
+
/** Present when the request includes `relations`. */
|
|
49
|
+
relations?: Record<string, RelatedEntry[]>;
|
|
50
|
+
created_at: string | null;
|
|
51
|
+
updated_at: string | null;
|
|
52
|
+
deleted_at: string | null;
|
|
53
|
+
}
|
|
54
|
+
interface EntitySummary {
|
|
55
|
+
id: number;
|
|
56
|
+
name: string;
|
|
57
|
+
slug: string;
|
|
58
|
+
description: string | null;
|
|
59
|
+
icon: string | null;
|
|
60
|
+
color: string | null;
|
|
61
|
+
links: {
|
|
62
|
+
records: string;
|
|
63
|
+
schema: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
type FieldType = 'text' | 'textarea' | 'number' | 'email' | 'url' | 'phone' | 'date' | 'datetime' | 'boolean' | 'select' | 'multiselect' | 'color' | 'file' | 'image' | 'richtext' | 'json' | 'tags' | 'repeater' | 'address' | 'relationship' | (string & {});
|
|
67
|
+
interface RepeaterSubfield {
|
|
68
|
+
key: string;
|
|
69
|
+
label: string;
|
|
70
|
+
type: FieldType;
|
|
71
|
+
[setting: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
interface FieldSchema {
|
|
74
|
+
id: number;
|
|
75
|
+
key: string;
|
|
76
|
+
label: string;
|
|
77
|
+
type: FieldType;
|
|
78
|
+
description: string | null;
|
|
79
|
+
placeholder: string | null;
|
|
80
|
+
default_value: string | null;
|
|
81
|
+
is_required: boolean;
|
|
82
|
+
is_active: boolean;
|
|
83
|
+
is_searchable: boolean;
|
|
84
|
+
is_shown_in_list: boolean;
|
|
85
|
+
width: string;
|
|
86
|
+
order: number;
|
|
87
|
+
group: string | null;
|
|
88
|
+
options: Record<string, string> | null;
|
|
89
|
+
validation_rules: string[];
|
|
90
|
+
settings: Record<string, unknown>;
|
|
91
|
+
repeater_subfields: RepeaterSubfield[] | null;
|
|
92
|
+
category_ids: number[];
|
|
93
|
+
show_when: unknown;
|
|
94
|
+
translatable: boolean;
|
|
95
|
+
multiple: boolean;
|
|
96
|
+
value_format: string;
|
|
97
|
+
relationship?: {
|
|
98
|
+
entity: string | null;
|
|
99
|
+
multiple: boolean;
|
|
100
|
+
};
|
|
101
|
+
address_parts?: string[];
|
|
102
|
+
}
|
|
103
|
+
interface FieldGroupSchema {
|
|
104
|
+
id: number;
|
|
105
|
+
key: string;
|
|
106
|
+
label: string;
|
|
107
|
+
description: string | null;
|
|
108
|
+
order: number;
|
|
109
|
+
is_collapsible: boolean;
|
|
110
|
+
is_collapsed: boolean;
|
|
111
|
+
}
|
|
112
|
+
interface EntitySchema {
|
|
113
|
+
id: number;
|
|
114
|
+
name: string;
|
|
115
|
+
slug: string;
|
|
116
|
+
description: string | null;
|
|
117
|
+
icon: string | null;
|
|
118
|
+
color: string | null;
|
|
119
|
+
is_active: boolean;
|
|
120
|
+
show_in_menu: boolean;
|
|
121
|
+
menu_order: number;
|
|
122
|
+
settings: Record<string, unknown>;
|
|
123
|
+
fields_count: number;
|
|
124
|
+
records_count: number;
|
|
125
|
+
fields: FieldSchema[];
|
|
126
|
+
groups: FieldGroupSchema[];
|
|
127
|
+
categories: (Category & {
|
|
128
|
+
parent_id: number | null;
|
|
129
|
+
description: string | null;
|
|
130
|
+
})[];
|
|
131
|
+
record_statuses: EntryStatus[];
|
|
132
|
+
locales: string[];
|
|
133
|
+
}
|
|
134
|
+
interface PaginationMeta {
|
|
135
|
+
current_page: number;
|
|
136
|
+
last_page: number;
|
|
137
|
+
per_page: number;
|
|
138
|
+
total: number;
|
|
139
|
+
from: number | null;
|
|
140
|
+
to: number | null;
|
|
141
|
+
path: string;
|
|
142
|
+
}
|
|
143
|
+
interface Paginated<T> {
|
|
144
|
+
data: T[];
|
|
145
|
+
meta: PaginationMeta;
|
|
146
|
+
links: {
|
|
147
|
+
first: string | null;
|
|
148
|
+
last: string | null;
|
|
149
|
+
prev: string | null;
|
|
150
|
+
next: string | null;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
interface ListParams {
|
|
154
|
+
status?: EntryStatus;
|
|
155
|
+
search?: string;
|
|
156
|
+
/** Category id. */
|
|
157
|
+
category?: number;
|
|
158
|
+
page?: number;
|
|
159
|
+
/** Capped by the server (100 by default). */
|
|
160
|
+
perPage?: number;
|
|
161
|
+
/** Include soft-deleted entries (`with`) or only them (`only`). Needs the Write ability. */
|
|
162
|
+
trashed?: 'with' | 'only';
|
|
163
|
+
/** Expand relationship fields into `entry.relations`. */
|
|
164
|
+
includeRelations?: boolean;
|
|
165
|
+
}
|
|
166
|
+
interface GetParams {
|
|
167
|
+
includeRelations?: boolean;
|
|
168
|
+
}
|
|
169
|
+
interface EntryInput<TValues extends object = EntryValues> {
|
|
170
|
+
title?: string | null;
|
|
171
|
+
slug?: string | null;
|
|
172
|
+
status?: EntryStatus;
|
|
173
|
+
order?: number;
|
|
174
|
+
/** Category ids or slugs. */
|
|
175
|
+
categories?: (number | string)[];
|
|
176
|
+
values?: Partial<TValues>;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Per-request options. `init` is merged into the `fetch` call, which is how
|
|
180
|
+
* framework adapters pass cache settings (e.g. Next.js `next: { tags }`).
|
|
181
|
+
*/
|
|
182
|
+
interface RequestOptions {
|
|
183
|
+
signal?: AbortSignal;
|
|
184
|
+
init?: RequestInit & Record<string, unknown>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface FlexaClientOptions {
|
|
188
|
+
/** Base URL of your Flexa installation, e.g. `https://cms.example.com`. */
|
|
189
|
+
url: string;
|
|
190
|
+
/**
|
|
191
|
+
* Workspace API key. Keep it on the server: anyone with the key can do what
|
|
192
|
+
* its abilities allow. Use a Read-only key for public websites.
|
|
193
|
+
*/
|
|
194
|
+
apiKey: string;
|
|
195
|
+
/** Path of the content API. Defaults to `/api/v1`. */
|
|
196
|
+
apiPath?: string;
|
|
197
|
+
/** Custom fetch implementation (defaults to the global `fetch`). */
|
|
198
|
+
fetch?: typeof fetch;
|
|
199
|
+
/** Extra headers sent with every request. */
|
|
200
|
+
headers?: Record<string, string>;
|
|
201
|
+
/** Abort requests that take longer than this, in milliseconds. Defaults to 30s. */
|
|
202
|
+
timeout?: number;
|
|
203
|
+
/**
|
|
204
|
+
* How many times to retry reads after a rate limit (429), a gateway error
|
|
205
|
+
* (502/503/504) or a network failure. Writes are never retried. Defaults to 2.
|
|
206
|
+
*/
|
|
207
|
+
retries?: number;
|
|
208
|
+
}
|
|
209
|
+
type ValuesOf<TSchema extends object, TEntity extends string> = TEntity extends keyof TSchema ? TSchema[TEntity] extends object ? TSchema[TEntity] : EntryValues : EntryValues;
|
|
210
|
+
/** The part of the client entity helpers need: sending requests. */
|
|
211
|
+
type RequestSender = Pick<FlexaClient, 'request'>;
|
|
212
|
+
/**
|
|
213
|
+
* Content API client for one Flexa workspace (the workspace is set by the API key).
|
|
214
|
+
*/
|
|
215
|
+
declare class FlexaClient<TSchema extends object = ContentSchema> {
|
|
216
|
+
readonly baseUrl: string;
|
|
217
|
+
private readonly options;
|
|
218
|
+
constructor(options: FlexaClientOptions);
|
|
219
|
+
/** Entities (content models) the API key can read. */
|
|
220
|
+
entities(options?: RequestOptions): Promise<EntitySummary[]>;
|
|
221
|
+
/** Typed access to the entries of one entity. */
|
|
222
|
+
entity<TEntity extends Extract<keyof TSchema, string> | (string & {})>(slug: TEntity): EntityClient<ValuesOf<TSchema, TEntity>>;
|
|
223
|
+
/**
|
|
224
|
+
* Send a request to the content API. Exposed for endpoints the typed helpers
|
|
225
|
+
* do not cover yet; `path` is relative to the API base (e.g. `/posts`).
|
|
226
|
+
*/
|
|
227
|
+
request<T>(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
228
|
+
private backoff;
|
|
229
|
+
private toError;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Entries of one entity: list, read, create, update, delete and restore.
|
|
233
|
+
*/
|
|
234
|
+
declare class EntityClient<TValues extends object = EntryValues> {
|
|
235
|
+
private readonly client;
|
|
236
|
+
readonly slug: string;
|
|
237
|
+
constructor(client: RequestSender, slug: string);
|
|
238
|
+
private get path();
|
|
239
|
+
/** Fields, groups, categories and locales of the entity. */
|
|
240
|
+
schema(options?: RequestOptions): Promise<EntitySchema>;
|
|
241
|
+
/** One page of entries. */
|
|
242
|
+
list(params?: ListParams, options?: RequestOptions): Promise<Paginated<Entry<TValues>>>;
|
|
243
|
+
/** Iterate over every matching entry, fetching pages as needed. */
|
|
244
|
+
iterate(params?: Omit<ListParams, 'page'>, options?: RequestOptions): AsyncGenerator<Entry<TValues>>;
|
|
245
|
+
/** Every matching entry, across all pages. */
|
|
246
|
+
all(params?: Omit<ListParams, 'page'>, options?: RequestOptions): Promise<Entry<TValues>[]>;
|
|
247
|
+
/** An entry by id or slug. Throws a 404 `FlexaError` when it does not exist. */
|
|
248
|
+
get(idOrSlug: number | string, params?: GetParams, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
249
|
+
/** Like `get()`, but resolves to `null` when the entry does not exist. */
|
|
250
|
+
find(idOrSlug: number | string, params?: GetParams, options?: RequestOptions): Promise<Entry<TValues> | null>;
|
|
251
|
+
/** Create an entry. Needs the Write ability. */
|
|
252
|
+
create(input: EntryInput<TValues>, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
253
|
+
/** Partially update an entry. Needs the Write ability. */
|
|
254
|
+
update(idOrSlug: number | string, input: EntryInput<TValues>, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
255
|
+
/** Move an entry to the trash, or delete it for good with `force`. Needs the Delete ability. */
|
|
256
|
+
delete(idOrSlug: number | string, params?: {
|
|
257
|
+
force?: boolean;
|
|
258
|
+
}, options?: RequestOptions): Promise<void>;
|
|
259
|
+
/** Restore a trashed entry. Needs the Write ability. */
|
|
260
|
+
restore(idOrSlug: number | string, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
261
|
+
}
|
|
262
|
+
declare function createClient<TSchema extends object = ContentSchema>(options: FlexaClientOptions): FlexaClient<TSchema>;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Error thrown for every non-2xx response from the content API.
|
|
266
|
+
*/
|
|
267
|
+
declare class FlexaError extends Error {
|
|
268
|
+
/** HTTP status, or 0 when the request never reached the server. */
|
|
269
|
+
readonly status: number;
|
|
270
|
+
/** Validation errors keyed by field (422 responses). */
|
|
271
|
+
readonly errors: Record<string, string[]>;
|
|
272
|
+
/** Parsed response body, when there was one. */
|
|
273
|
+
readonly body: unknown;
|
|
274
|
+
readonly name = "FlexaError";
|
|
275
|
+
constructor(message: string,
|
|
276
|
+
/** HTTP status, or 0 when the request never reached the server. */
|
|
277
|
+
status: number,
|
|
278
|
+
/** Validation errors keyed by field (422 responses). */
|
|
279
|
+
errors?: Record<string, string[]>,
|
|
280
|
+
/** Parsed response body, when there was one. */
|
|
281
|
+
body?: unknown);
|
|
282
|
+
get isNotFound(): boolean;
|
|
283
|
+
get isUnauthorized(): boolean;
|
|
284
|
+
get isForbidden(): boolean;
|
|
285
|
+
get isValidationError(): boolean;
|
|
286
|
+
get isRateLimited(): boolean;
|
|
287
|
+
}
|
|
288
|
+
declare function isFlexaError(error: unknown): error is FlexaError;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Whether a field value is a translatable value ({ "en": "...", "es": "..." }).
|
|
292
|
+
*/
|
|
293
|
+
declare function isLocalized(value: unknown, locales?: readonly string[]): value is Localized<unknown>;
|
|
294
|
+
/**
|
|
295
|
+
* Pick one locale of a translatable value, falling back to the given locales
|
|
296
|
+
* (and then to the first non-empty translation). Plain values pass through.
|
|
297
|
+
*/
|
|
298
|
+
declare function localize<T>(value: Localized<T> | T | null | undefined, locale: string, fallbacks?: readonly string[]): T | null;
|
|
299
|
+
|
|
300
|
+
export { type Category, type ContentSchema, EntityClient, type EntitySchema, type EntitySummary, type Entry, type EntryInput, type EntryMedia, type EntryStatus, type EntryValues, type FieldGroupSchema, type FieldSchema, type FieldType, FlexaClient, type FlexaClientOptions, FlexaError, type GetParams, type ListParams, type Localized, type Paginated, type PaginationMeta, type RelatedEntry, type RepeaterSubfield, type RequestOptions, createClient, isFlexaError, isLocalized, localize };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shapes returned by the Flexa content API (`/api/v1`). Keys are kept exactly
|
|
3
|
+
* as the API sends them (snake_case), so responses can be passed around as-is.
|
|
4
|
+
*/
|
|
5
|
+
type EntryStatus = 'draft' | 'published' | 'archived';
|
|
6
|
+
/** Values of a translatable field: one entry per configured locale. */
|
|
7
|
+
type Localized<T = string> = {
|
|
8
|
+
[locale: string]: T | null | undefined;
|
|
9
|
+
};
|
|
10
|
+
/** Field values of an entry, keyed by field key. Narrowed by generated types. */
|
|
11
|
+
type EntryValues = Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Maps entity slugs to the values of their entries. Generate it for your
|
|
14
|
+
* workspace with `npx @flexacms/cli generate` to get typed `client.entity()`.
|
|
15
|
+
*/
|
|
16
|
+
type ContentSchema = Record<string, EntryValues>;
|
|
17
|
+
/** A file URL, a list of them, translations of them, or repeater items holding them. */
|
|
18
|
+
type EntryMedia = string | null | (string | null)[] | {
|
|
19
|
+
[locale: string]: string | string[] | null;
|
|
20
|
+
} | Record<string, string | string[] | null>[];
|
|
21
|
+
interface Category {
|
|
22
|
+
id: number;
|
|
23
|
+
name: string;
|
|
24
|
+
slug: string;
|
|
25
|
+
}
|
|
26
|
+
interface RelatedEntry {
|
|
27
|
+
id: number;
|
|
28
|
+
title: string | null;
|
|
29
|
+
slug: string | null;
|
|
30
|
+
status: EntryStatus;
|
|
31
|
+
}
|
|
32
|
+
interface Entry<TValues extends object = EntryValues> {
|
|
33
|
+
id: number;
|
|
34
|
+
entity_id: number;
|
|
35
|
+
entity_slug: string;
|
|
36
|
+
title: string | null;
|
|
37
|
+
slug: string | null;
|
|
38
|
+
status: EntryStatus;
|
|
39
|
+
order: number | null;
|
|
40
|
+
categories: Category[];
|
|
41
|
+
values: TValues;
|
|
42
|
+
/**
|
|
43
|
+
* Absolute URLs of the files in image and file fields, keyed by field key
|
|
44
|
+
* and shaped like their values (`values` keeps the stored paths).
|
|
45
|
+
* Repeaters list their media sub-fields per item. Sent by Flexa 0.2+.
|
|
46
|
+
*/
|
|
47
|
+
media?: Record<string, EntryMedia>;
|
|
48
|
+
/** Present when the request includes `relations`. */
|
|
49
|
+
relations?: Record<string, RelatedEntry[]>;
|
|
50
|
+
created_at: string | null;
|
|
51
|
+
updated_at: string | null;
|
|
52
|
+
deleted_at: string | null;
|
|
53
|
+
}
|
|
54
|
+
interface EntitySummary {
|
|
55
|
+
id: number;
|
|
56
|
+
name: string;
|
|
57
|
+
slug: string;
|
|
58
|
+
description: string | null;
|
|
59
|
+
icon: string | null;
|
|
60
|
+
color: string | null;
|
|
61
|
+
links: {
|
|
62
|
+
records: string;
|
|
63
|
+
schema: string;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
type FieldType = 'text' | 'textarea' | 'number' | 'email' | 'url' | 'phone' | 'date' | 'datetime' | 'boolean' | 'select' | 'multiselect' | 'color' | 'file' | 'image' | 'richtext' | 'json' | 'tags' | 'repeater' | 'address' | 'relationship' | (string & {});
|
|
67
|
+
interface RepeaterSubfield {
|
|
68
|
+
key: string;
|
|
69
|
+
label: string;
|
|
70
|
+
type: FieldType;
|
|
71
|
+
[setting: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
interface FieldSchema {
|
|
74
|
+
id: number;
|
|
75
|
+
key: string;
|
|
76
|
+
label: string;
|
|
77
|
+
type: FieldType;
|
|
78
|
+
description: string | null;
|
|
79
|
+
placeholder: string | null;
|
|
80
|
+
default_value: string | null;
|
|
81
|
+
is_required: boolean;
|
|
82
|
+
is_active: boolean;
|
|
83
|
+
is_searchable: boolean;
|
|
84
|
+
is_shown_in_list: boolean;
|
|
85
|
+
width: string;
|
|
86
|
+
order: number;
|
|
87
|
+
group: string | null;
|
|
88
|
+
options: Record<string, string> | null;
|
|
89
|
+
validation_rules: string[];
|
|
90
|
+
settings: Record<string, unknown>;
|
|
91
|
+
repeater_subfields: RepeaterSubfield[] | null;
|
|
92
|
+
category_ids: number[];
|
|
93
|
+
show_when: unknown;
|
|
94
|
+
translatable: boolean;
|
|
95
|
+
multiple: boolean;
|
|
96
|
+
value_format: string;
|
|
97
|
+
relationship?: {
|
|
98
|
+
entity: string | null;
|
|
99
|
+
multiple: boolean;
|
|
100
|
+
};
|
|
101
|
+
address_parts?: string[];
|
|
102
|
+
}
|
|
103
|
+
interface FieldGroupSchema {
|
|
104
|
+
id: number;
|
|
105
|
+
key: string;
|
|
106
|
+
label: string;
|
|
107
|
+
description: string | null;
|
|
108
|
+
order: number;
|
|
109
|
+
is_collapsible: boolean;
|
|
110
|
+
is_collapsed: boolean;
|
|
111
|
+
}
|
|
112
|
+
interface EntitySchema {
|
|
113
|
+
id: number;
|
|
114
|
+
name: string;
|
|
115
|
+
slug: string;
|
|
116
|
+
description: string | null;
|
|
117
|
+
icon: string | null;
|
|
118
|
+
color: string | null;
|
|
119
|
+
is_active: boolean;
|
|
120
|
+
show_in_menu: boolean;
|
|
121
|
+
menu_order: number;
|
|
122
|
+
settings: Record<string, unknown>;
|
|
123
|
+
fields_count: number;
|
|
124
|
+
records_count: number;
|
|
125
|
+
fields: FieldSchema[];
|
|
126
|
+
groups: FieldGroupSchema[];
|
|
127
|
+
categories: (Category & {
|
|
128
|
+
parent_id: number | null;
|
|
129
|
+
description: string | null;
|
|
130
|
+
})[];
|
|
131
|
+
record_statuses: EntryStatus[];
|
|
132
|
+
locales: string[];
|
|
133
|
+
}
|
|
134
|
+
interface PaginationMeta {
|
|
135
|
+
current_page: number;
|
|
136
|
+
last_page: number;
|
|
137
|
+
per_page: number;
|
|
138
|
+
total: number;
|
|
139
|
+
from: number | null;
|
|
140
|
+
to: number | null;
|
|
141
|
+
path: string;
|
|
142
|
+
}
|
|
143
|
+
interface Paginated<T> {
|
|
144
|
+
data: T[];
|
|
145
|
+
meta: PaginationMeta;
|
|
146
|
+
links: {
|
|
147
|
+
first: string | null;
|
|
148
|
+
last: string | null;
|
|
149
|
+
prev: string | null;
|
|
150
|
+
next: string | null;
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
interface ListParams {
|
|
154
|
+
status?: EntryStatus;
|
|
155
|
+
search?: string;
|
|
156
|
+
/** Category id. */
|
|
157
|
+
category?: number;
|
|
158
|
+
page?: number;
|
|
159
|
+
/** Capped by the server (100 by default). */
|
|
160
|
+
perPage?: number;
|
|
161
|
+
/** Include soft-deleted entries (`with`) or only them (`only`). Needs the Write ability. */
|
|
162
|
+
trashed?: 'with' | 'only';
|
|
163
|
+
/** Expand relationship fields into `entry.relations`. */
|
|
164
|
+
includeRelations?: boolean;
|
|
165
|
+
}
|
|
166
|
+
interface GetParams {
|
|
167
|
+
includeRelations?: boolean;
|
|
168
|
+
}
|
|
169
|
+
interface EntryInput<TValues extends object = EntryValues> {
|
|
170
|
+
title?: string | null;
|
|
171
|
+
slug?: string | null;
|
|
172
|
+
status?: EntryStatus;
|
|
173
|
+
order?: number;
|
|
174
|
+
/** Category ids or slugs. */
|
|
175
|
+
categories?: (number | string)[];
|
|
176
|
+
values?: Partial<TValues>;
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Per-request options. `init` is merged into the `fetch` call, which is how
|
|
180
|
+
* framework adapters pass cache settings (e.g. Next.js `next: { tags }`).
|
|
181
|
+
*/
|
|
182
|
+
interface RequestOptions {
|
|
183
|
+
signal?: AbortSignal;
|
|
184
|
+
init?: RequestInit & Record<string, unknown>;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
interface FlexaClientOptions {
|
|
188
|
+
/** Base URL of your Flexa installation, e.g. `https://cms.example.com`. */
|
|
189
|
+
url: string;
|
|
190
|
+
/**
|
|
191
|
+
* Workspace API key. Keep it on the server: anyone with the key can do what
|
|
192
|
+
* its abilities allow. Use a Read-only key for public websites.
|
|
193
|
+
*/
|
|
194
|
+
apiKey: string;
|
|
195
|
+
/** Path of the content API. Defaults to `/api/v1`. */
|
|
196
|
+
apiPath?: string;
|
|
197
|
+
/** Custom fetch implementation (defaults to the global `fetch`). */
|
|
198
|
+
fetch?: typeof fetch;
|
|
199
|
+
/** Extra headers sent with every request. */
|
|
200
|
+
headers?: Record<string, string>;
|
|
201
|
+
/** Abort requests that take longer than this, in milliseconds. Defaults to 30s. */
|
|
202
|
+
timeout?: number;
|
|
203
|
+
/**
|
|
204
|
+
* How many times to retry reads after a rate limit (429), a gateway error
|
|
205
|
+
* (502/503/504) or a network failure. Writes are never retried. Defaults to 2.
|
|
206
|
+
*/
|
|
207
|
+
retries?: number;
|
|
208
|
+
}
|
|
209
|
+
type ValuesOf<TSchema extends object, TEntity extends string> = TEntity extends keyof TSchema ? TSchema[TEntity] extends object ? TSchema[TEntity] : EntryValues : EntryValues;
|
|
210
|
+
/** The part of the client entity helpers need: sending requests. */
|
|
211
|
+
type RequestSender = Pick<FlexaClient, 'request'>;
|
|
212
|
+
/**
|
|
213
|
+
* Content API client for one Flexa workspace (the workspace is set by the API key).
|
|
214
|
+
*/
|
|
215
|
+
declare class FlexaClient<TSchema extends object = ContentSchema> {
|
|
216
|
+
readonly baseUrl: string;
|
|
217
|
+
private readonly options;
|
|
218
|
+
constructor(options: FlexaClientOptions);
|
|
219
|
+
/** Entities (content models) the API key can read. */
|
|
220
|
+
entities(options?: RequestOptions): Promise<EntitySummary[]>;
|
|
221
|
+
/** Typed access to the entries of one entity. */
|
|
222
|
+
entity<TEntity extends Extract<keyof TSchema, string> | (string & {})>(slug: TEntity): EntityClient<ValuesOf<TSchema, TEntity>>;
|
|
223
|
+
/**
|
|
224
|
+
* Send a request to the content API. Exposed for endpoints the typed helpers
|
|
225
|
+
* do not cover yet; `path` is relative to the API base (e.g. `/posts`).
|
|
226
|
+
*/
|
|
227
|
+
request<T>(method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE', path: string, body?: unknown, options?: RequestOptions): Promise<T>;
|
|
228
|
+
private backoff;
|
|
229
|
+
private toError;
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* Entries of one entity: list, read, create, update, delete and restore.
|
|
233
|
+
*/
|
|
234
|
+
declare class EntityClient<TValues extends object = EntryValues> {
|
|
235
|
+
private readonly client;
|
|
236
|
+
readonly slug: string;
|
|
237
|
+
constructor(client: RequestSender, slug: string);
|
|
238
|
+
private get path();
|
|
239
|
+
/** Fields, groups, categories and locales of the entity. */
|
|
240
|
+
schema(options?: RequestOptions): Promise<EntitySchema>;
|
|
241
|
+
/** One page of entries. */
|
|
242
|
+
list(params?: ListParams, options?: RequestOptions): Promise<Paginated<Entry<TValues>>>;
|
|
243
|
+
/** Iterate over every matching entry, fetching pages as needed. */
|
|
244
|
+
iterate(params?: Omit<ListParams, 'page'>, options?: RequestOptions): AsyncGenerator<Entry<TValues>>;
|
|
245
|
+
/** Every matching entry, across all pages. */
|
|
246
|
+
all(params?: Omit<ListParams, 'page'>, options?: RequestOptions): Promise<Entry<TValues>[]>;
|
|
247
|
+
/** An entry by id or slug. Throws a 404 `FlexaError` when it does not exist. */
|
|
248
|
+
get(idOrSlug: number | string, params?: GetParams, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
249
|
+
/** Like `get()`, but resolves to `null` when the entry does not exist. */
|
|
250
|
+
find(idOrSlug: number | string, params?: GetParams, options?: RequestOptions): Promise<Entry<TValues> | null>;
|
|
251
|
+
/** Create an entry. Needs the Write ability. */
|
|
252
|
+
create(input: EntryInput<TValues>, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
253
|
+
/** Partially update an entry. Needs the Write ability. */
|
|
254
|
+
update(idOrSlug: number | string, input: EntryInput<TValues>, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
255
|
+
/** Move an entry to the trash, or delete it for good with `force`. Needs the Delete ability. */
|
|
256
|
+
delete(idOrSlug: number | string, params?: {
|
|
257
|
+
force?: boolean;
|
|
258
|
+
}, options?: RequestOptions): Promise<void>;
|
|
259
|
+
/** Restore a trashed entry. Needs the Write ability. */
|
|
260
|
+
restore(idOrSlug: number | string, options?: RequestOptions): Promise<Entry<TValues>>;
|
|
261
|
+
}
|
|
262
|
+
declare function createClient<TSchema extends object = ContentSchema>(options: FlexaClientOptions): FlexaClient<TSchema>;
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* Error thrown for every non-2xx response from the content API.
|
|
266
|
+
*/
|
|
267
|
+
declare class FlexaError extends Error {
|
|
268
|
+
/** HTTP status, or 0 when the request never reached the server. */
|
|
269
|
+
readonly status: number;
|
|
270
|
+
/** Validation errors keyed by field (422 responses). */
|
|
271
|
+
readonly errors: Record<string, string[]>;
|
|
272
|
+
/** Parsed response body, when there was one. */
|
|
273
|
+
readonly body: unknown;
|
|
274
|
+
readonly name = "FlexaError";
|
|
275
|
+
constructor(message: string,
|
|
276
|
+
/** HTTP status, or 0 when the request never reached the server. */
|
|
277
|
+
status: number,
|
|
278
|
+
/** Validation errors keyed by field (422 responses). */
|
|
279
|
+
errors?: Record<string, string[]>,
|
|
280
|
+
/** Parsed response body, when there was one. */
|
|
281
|
+
body?: unknown);
|
|
282
|
+
get isNotFound(): boolean;
|
|
283
|
+
get isUnauthorized(): boolean;
|
|
284
|
+
get isForbidden(): boolean;
|
|
285
|
+
get isValidationError(): boolean;
|
|
286
|
+
get isRateLimited(): boolean;
|
|
287
|
+
}
|
|
288
|
+
declare function isFlexaError(error: unknown): error is FlexaError;
|
|
289
|
+
|
|
290
|
+
/**
|
|
291
|
+
* Whether a field value is a translatable value ({ "en": "...", "es": "..." }).
|
|
292
|
+
*/
|
|
293
|
+
declare function isLocalized(value: unknown, locales?: readonly string[]): value is Localized<unknown>;
|
|
294
|
+
/**
|
|
295
|
+
* Pick one locale of a translatable value, falling back to the given locales
|
|
296
|
+
* (and then to the first non-empty translation). Plain values pass through.
|
|
297
|
+
*/
|
|
298
|
+
declare function localize<T>(value: Localized<T> | T | null | undefined, locale: string, fallbacks?: readonly string[]): T | null;
|
|
299
|
+
|
|
300
|
+
export { type Category, type ContentSchema, EntityClient, type EntitySchema, type EntitySummary, type Entry, type EntryInput, type EntryMedia, type EntryStatus, type EntryValues, type FieldGroupSchema, type FieldSchema, type FieldType, FlexaClient, type FlexaClientOptions, FlexaError, type GetParams, type ListParams, type Localized, type Paginated, type PaginationMeta, type RelatedEntry, type RepeaterSubfield, type RequestOptions, createClient, isFlexaError, isLocalized, localize };
|