@amaster.ai/entity-client 1.0.0-beta.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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Amaster Team
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,305 @@
1
+ # @amaster.ai/entity-client
2
+
3
+ Type-safe CRUD client for entity data management with automatic date handling and advanced filtering.
4
+
5
+ ## Features
6
+
7
+ - 🔐 Type-safe CRUD operations
8
+ - 📅 Automatic date format conversion
9
+ - 🔍 Advanced filtering with operators
10
+ - 📄 Pagination and sorting
11
+ - 🔗 Relation loading support
12
+ - 📦 Bulk operations (update/delete)
13
+ - 🌳 Tree-shakeable ESM/CJS builds
14
+
15
+ ## Installation
16
+
17
+ ```bash
18
+ pnpm add @amaster.ai/entity-client @amaster.ai/http-client axios
19
+ ```
20
+
21
+ ## Quick Start
22
+
23
+ ```typescript
24
+ import { createEntityClient } from "@amaster.ai/entity-client";
25
+
26
+ const client = createEntityClient();
27
+
28
+ // List with pagination
29
+ const result = await client.list("default", "users", {
30
+ page: 1,
31
+ perPage: 20,
32
+ orderBy: "createdAt",
33
+ orderDir: "desc",
34
+ });
35
+
36
+ if (result.data) {
37
+ console.log(result.data.items); // Array of users
38
+ console.log(result.data.total); // Total count
39
+ }
40
+ ```
41
+
42
+ ## API Reference
43
+
44
+ ### `list<T>(source, entity, params?)`
45
+
46
+ List entities with pagination, sorting, and filtering.
47
+
48
+ ```typescript
49
+ const result = await client.list("default", "tasks", {
50
+ page: 1,
51
+ perPage: 20,
52
+ orderBy: "createdAt",
53
+ orderDir: "desc",
54
+ status: "active", // Simple filter
55
+ "title[like]": "search", // Like operator
56
+ });
57
+
58
+ // result.data structure:
59
+ // {
60
+ // items: T[],
61
+ // total: number,
62
+ // page?: number,
63
+ // perPage?: number
64
+ // }
65
+ ```
66
+
67
+ ### `get<T>(source, entity, id)`
68
+
69
+ Get a single entity by ID.
70
+
71
+ ```typescript
72
+ const result = await client.get("default", "users", 1);
73
+ if (result.data) {
74
+ console.log(result.data); // User object
75
+ }
76
+ ```
77
+
78
+ ### `create<T>(source, entity, data)`
79
+
80
+ Create a new entity.
81
+
82
+ ```typescript
83
+ const result = await client.create("default", "tasks", {
84
+ title: "New Task",
85
+ dueDate: new Date(), // Automatically converted to backend format
86
+ status: "pending",
87
+ });
88
+ ```
89
+
90
+ ### `update<T>(source, entity, id, data)`
91
+
92
+ Update an existing entity.
93
+
94
+ ```typescript
95
+ const result = await client.update("default", "tasks", 1, {
96
+ status: "completed",
97
+ completedAt: new Date(),
98
+ });
99
+ ```
100
+
101
+ ### `delete(source, entity, id)`
102
+
103
+ Delete an entity.
104
+
105
+ ```typescript
106
+ const result = await client.delete("default", "tasks", 1);
107
+ ```
108
+
109
+ ### `options<T>(source, entity, fields?)`
110
+
111
+ Get options for select fields.
112
+
113
+ ```typescript
114
+ const result = await client.options("default", "users", ["id", "name"]);
115
+ // Returns array of { id, name } objects
116
+ ```
117
+
118
+ ### `bulkUpdate<T>(source, entity, items)`
119
+
120
+ Update multiple entities in one request.
121
+
122
+ ```typescript
123
+ const result = await client.bulkUpdate("default", "tasks", [
124
+ { id: 1, status: "completed" },
125
+ { id: 2, status: "completed" },
126
+ ]);
127
+ ```
128
+
129
+ ### `bulkDelete(source, entity, ids)`
130
+
131
+ Delete multiple entities in one request.
132
+
133
+ ```typescript
134
+ const result = await client.bulkDelete("default", "tasks", [1, 2, 3]);
135
+ ```
136
+
137
+ ## Query Parameters
138
+
139
+ ### Pagination
140
+
141
+ ```typescript
142
+ {
143
+ page: 1, // Page number (starts from 1)
144
+ perPage: 20 // Items per page
145
+ }
146
+ ```
147
+
148
+ ### Sorting
149
+
150
+ ```typescript
151
+ {
152
+ orderBy: "createdAt",
153
+ orderDir: "desc" // 'asc' or 'desc'
154
+ }
155
+ ```
156
+
157
+ ### Simple Filters
158
+
159
+ ```typescript
160
+ {
161
+ status: "active", // Equals (default)
162
+ "age[gt]": 18, // Greater than
163
+ "name[like]": "John", // Like search
164
+ "email[sw]": "@example" // Starts with
165
+ }
166
+ ```
167
+
168
+ ### Filter Operators
169
+
170
+ - `eq` - Equal (default)
171
+ - `ne` - Not equal
172
+ - `gt` - Greater than
173
+ - `ge` - Greater or equal
174
+ - `lt` - Less than
175
+ - `le` - Less or equal
176
+ - `like` - Fuzzy match
177
+ - `sw` - Starts with
178
+ - `ew` - Ends with
179
+ - `bt` - Between
180
+ - `in` - In array
181
+
182
+ ### Keyword Search
183
+
184
+ Search across multiple fields:
185
+
186
+ ```typescript
187
+ {
188
+ "__keywords[title,description]": "search term"
189
+ }
190
+ ```
191
+
192
+ ### Relation Loading
193
+
194
+ Load related entities:
195
+
196
+ ```typescript
197
+ {
198
+ "__relations[]": ["author", "comments"]
199
+ }
200
+ ```
201
+
202
+ ### Advanced Filters
203
+
204
+ Complex AND/OR filter groups:
205
+
206
+ ```typescript
207
+ {
208
+ __filter: {
209
+ conjunction: "and",
210
+ children: [
211
+ {
212
+ op: "equal",
213
+ left: { type: "field", field: "status" },
214
+ right: "active"
215
+ },
216
+ {
217
+ conjunction: "or",
218
+ children: [
219
+ {
220
+ op: "greater",
221
+ left: { type: "field", field: "priority" },
222
+ right: 5
223
+ },
224
+ {
225
+ op: "like",
226
+ left: { type: "field", field: "title" },
227
+ right: "urgent"
228
+ }
229
+ ]
230
+ }
231
+ ]
232
+ }
233
+ }
234
+ ```
235
+
236
+ ## Date Handling
237
+
238
+ Dates are automatically converted to backend format:
239
+
240
+ ```typescript
241
+ // Input
242
+ {
243
+ dueDate: new Date("2026-01-05T10:30:45.000Z"),
244
+ createdAt: "2026-01-05T10:30:45.000Z"
245
+ }
246
+
247
+ // Sent to backend as
248
+ {
249
+ dueDate: "2026-01-05 10:30:45",
250
+ createdAt: "2026-01-05 10:30:45"
251
+ }
252
+ ```
253
+
254
+ ## TypeScript Support
255
+
256
+ Full generic type support:
257
+
258
+ ```typescript
259
+ interface Task {
260
+ id: number;
261
+ title: string;
262
+ status: "pending" | "active" | "completed";
263
+ dueDate: string;
264
+ }
265
+
266
+ const result = await client.list<Task>("default", "tasks");
267
+ if (result.data) {
268
+ result.data.items.forEach((task) => {
269
+ console.log(task.title); // Fully typed
270
+ });
271
+ }
272
+ ```
273
+
274
+ ## Error Handling
275
+
276
+ ```typescript
277
+ const result = await client.get("default", "users", 1);
278
+
279
+ if (result.error) {
280
+ console.error("Error:", result.error.message);
281
+ console.error("Status:", result.error.status);
282
+ }
283
+ ```
284
+
285
+ ## Custom HTTP Client
286
+
287
+ Use a custom HTTP client with your own configuration:
288
+
289
+ ```typescript
290
+ import { createHttpClient } from "@amaster.ai/http-client";
291
+ import { createEntityClient } from "@amaster.ai/entity-client";
292
+ import axios from "axios";
293
+
294
+ const axiosInstance = axios.create({
295
+ baseURL: "https://api.example.com",
296
+ timeout: 5000,
297
+ });
298
+
299
+ const httpClient = createHttpClient(axiosInstance);
300
+ const entityClient = createEntityClient(httpClient);
301
+ ```
302
+
303
+ ## License
304
+
305
+ MIT
package/dist/index.cjs ADDED
@@ -0,0 +1,237 @@
1
+ 'use strict';
2
+
3
+ var httpClient = require('@amaster.ai/http-client');
4
+
5
+ // src/entity-client.ts
6
+ function formatDateForBackend(date) {
7
+ let dateObj;
8
+ if (date instanceof Date) {
9
+ dateObj = date;
10
+ } else if (typeof date === "string") {
11
+ dateObj = new Date(date);
12
+ } else {
13
+ dateObj = new Date(date);
14
+ }
15
+ if (Number.isNaN(dateObj.getTime())) {
16
+ return String(date);
17
+ }
18
+ const year = dateObj.getUTCFullYear();
19
+ const month = String(dateObj.getUTCMonth() + 1).padStart(2, "0");
20
+ const day = String(dateObj.getUTCDate()).padStart(2, "0");
21
+ const hours = String(dateObj.getUTCHours()).padStart(2, "0");
22
+ const minutes = String(dateObj.getUTCMinutes()).padStart(2, "0");
23
+ const seconds = String(dateObj.getUTCSeconds()).padStart(2, "0");
24
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
25
+ }
26
+ function processDataForBackend(data) {
27
+ if (data === null || data === void 0) {
28
+ return data;
29
+ }
30
+ if (data instanceof Date) {
31
+ return formatDateForBackend(data);
32
+ }
33
+ if (Array.isArray(data)) {
34
+ return data.map((item) => processDataForBackend(item));
35
+ }
36
+ if (typeof data === "object") {
37
+ const processed = {};
38
+ for (const [key, value] of Object.entries(data)) {
39
+ processed[key] = processDataForBackend(value);
40
+ }
41
+ return processed;
42
+ }
43
+ if (typeof data === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(data)) {
44
+ return formatDateForBackend(data);
45
+ }
46
+ return data;
47
+ }
48
+ function buildEntityUrl(source, entity, path = "") {
49
+ const basePath = `/api/entity/data/${source}/${entity}`;
50
+ return path ? `${basePath}${path.startsWith("/") ? path : `/${path}`}` : basePath;
51
+ }
52
+ function encodeQueryParams(params) {
53
+ if (!params || Object.keys(params).length === 0) {
54
+ return "";
55
+ }
56
+ const searchParams = new URLSearchParams();
57
+ for (const [key, value] of Object.entries(params)) {
58
+ if (value === void 0 || value === null) {
59
+ continue;
60
+ }
61
+ if (key === "__filter" && typeof value === "object") {
62
+ searchParams.append(key, JSON.stringify(value));
63
+ } else if (key === "__relations" && Array.isArray(value)) {
64
+ for (const v of value) {
65
+ searchParams.append("__relations[]", String(v));
66
+ }
67
+ } else if (Array.isArray(value)) {
68
+ for (const v of value) {
69
+ searchParams.append(key, String(v));
70
+ }
71
+ } else if (typeof value === "object" && !Array.isArray(value)) {
72
+ for (const [subKey, subValue] of Object.entries(value)) {
73
+ if (subValue !== void 0 && subValue !== null) {
74
+ searchParams.append(`${key}[${subKey}]`, String(subValue));
75
+ }
76
+ }
77
+ } else {
78
+ searchParams.append(key, String(value));
79
+ }
80
+ }
81
+ const query = searchParams.toString();
82
+ return query ? `?${query}` : "";
83
+ }
84
+ function createEntityClient(http = httpClient.createHttpClient()) {
85
+ return {
86
+ async list(source, entity, params) {
87
+ const url = buildEntityUrl(source, entity) + encodeQueryParams(params);
88
+ const result = await http.request({
89
+ url,
90
+ method: "get"
91
+ });
92
+ if (result.error || !result.data) {
93
+ return {
94
+ data: { items: [], total: 0 },
95
+ error: result.error,
96
+ status: result.status
97
+ };
98
+ }
99
+ const items = Array.isArray(result.data.items) ? result.data.items : [];
100
+ const total = result.data.total ?? result.data.count ?? items.length;
101
+ return {
102
+ ...result,
103
+ data: {
104
+ items,
105
+ total,
106
+ page: result.data.page,
107
+ perPage: result.data.perPage || result.data.pageSize
108
+ }
109
+ };
110
+ },
111
+ get(source, entity, id) {
112
+ if (!id) {
113
+ return Promise.resolve({
114
+ data: null,
115
+ error: { message: "Entity ID is required", status: 400 },
116
+ status: 400
117
+ });
118
+ }
119
+ const url = buildEntityUrl(source, entity, `/${id}`);
120
+ return http.request({
121
+ url,
122
+ method: "get"
123
+ });
124
+ },
125
+ create(source, entity, data) {
126
+ if (!data || typeof data !== "object") {
127
+ return Promise.resolve({
128
+ data: null,
129
+ error: { message: "Entity data is required", status: 400 },
130
+ status: 400
131
+ });
132
+ }
133
+ const processedData = processDataForBackend(data);
134
+ const url = buildEntityUrl(source, entity);
135
+ return http.request({
136
+ url,
137
+ method: "post",
138
+ headers: { "Content-Type": "application/json" },
139
+ data: processedData
140
+ });
141
+ },
142
+ update(source, entity, id, data) {
143
+ if (!id) {
144
+ return Promise.resolve({
145
+ data: null,
146
+ error: { message: "Entity ID is required", status: 400 },
147
+ status: 400
148
+ });
149
+ }
150
+ if (!data || typeof data !== "object") {
151
+ return Promise.resolve({
152
+ data: null,
153
+ error: { message: "Entity data is required", status: 400 },
154
+ status: 400
155
+ });
156
+ }
157
+ const processedData = processDataForBackend(data);
158
+ const url = buildEntityUrl(source, entity, `/${id}`);
159
+ return http.request({
160
+ url,
161
+ method: "put",
162
+ headers: { "Content-Type": "application/json" },
163
+ data: processedData
164
+ });
165
+ },
166
+ async delete(source, entity, id) {
167
+ if (!id) {
168
+ return {
169
+ data: null,
170
+ error: { message: "Entity ID is required", status: 400 },
171
+ status: 400
172
+ };
173
+ }
174
+ const url = buildEntityUrl(source, entity, `/${id}`);
175
+ const result = await http.request({
176
+ url,
177
+ method: "delete"
178
+ });
179
+ return result.status === 204 ? { ...result, data: null } : result;
180
+ },
181
+ async options(source, entity, fields) {
182
+ const params = fields && fields.length > 0 ? { "__fields[]": fields } : void 0;
183
+ const url = buildEntityUrl(source, entity, "/options") + encodeQueryParams(params);
184
+ const result = await http.request({
185
+ url,
186
+ method: "get"
187
+ });
188
+ if (result.error || !result.data) {
189
+ return {
190
+ data: null,
191
+ error: result.error,
192
+ status: result.status
193
+ };
194
+ }
195
+ return {
196
+ ...result,
197
+ data: result.data.items || []
198
+ };
199
+ },
200
+ bulkUpdate(source, entity, items) {
201
+ if (!items || items.length === 0) {
202
+ return Promise.resolve({
203
+ data: null,
204
+ error: { message: "Items array is required", status: 400 },
205
+ status: 400
206
+ });
207
+ }
208
+ const processedItems = items.map((item) => processDataForBackend(item));
209
+ const url = buildEntityUrl(source, entity, "/bulkUpdate");
210
+ return http.request({
211
+ url,
212
+ method: "post",
213
+ headers: { "Content-Type": "application/json" },
214
+ data: { items: processedItems }
215
+ });
216
+ },
217
+ async bulkDelete(source, entity, ids) {
218
+ if (!ids || ids.length === 0) {
219
+ return {
220
+ data: null,
221
+ error: { message: "IDs array is required", status: 400 },
222
+ status: 400
223
+ };
224
+ }
225
+ const url = buildEntityUrl(source, entity, `/${ids.join(",")}`);
226
+ const result = await http.request({
227
+ url,
228
+ method: "delete"
229
+ });
230
+ return result.status === 204 ? { ...result, data: null } : result;
231
+ }
232
+ };
233
+ }
234
+
235
+ exports.createEntityClient = createEntityClient;
236
+ //# sourceMappingURL=index.cjs.map
237
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/entity-client.ts"],"names":["createHttpClient"],"mappings":"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","file":"index.cjs","sourcesContent":["import { type ClientResult, createHttpClient, type HttpClient } from \"@amaster.ai/http-client\";\nimport type { EntityListResponse, EntityQueryParams } from \"./types\";\n\n// Export types for convenience\nexport type { EntityListResponse, EntityQueryParams, FilterGroup, FilterItem, FilterOperator } from \"./types\";\n\n/**\n * Entity Client - Type-safe client for entity CRUD operations\n *\n * ## Quick Start\n * ```typescript\n * const entityClient = createEntityClient();\n *\n * // List with pagination and sorting\n * const result = await entityClient.list('default', 'tasks', {\n * page: 1,\n * perPage: 20,\n * orderBy: 'createdAt',\n * orderDir: 'desc'\n * });\n *\n * // ⚠️ IMPORTANT: Access items via result.data.items, NOT result.data\n * setTasks(result.data?.items || []); // ✅ Correct\n * setTotal(result.data?.total || 0);\n *\n * // ❌ WRONG: setTasks(result.data || []) - result.data is an object, not an array!\n *\n * // Get single record\n * const task = await entityClient.get('default', 'tasks', 1);\n * setTask(result.data); // ✅ result.data is the entity object directly\n *\n * // CRUD operations\n * await entityClient.create('default', 'tasks', { title: 'New', dueDate: new Date() });\n * await entityClient.update('default', 'tasks', 1, { status: 'done' });\n * await entityClient.delete('default', 'tasks', 1);\n * ```\n *\n * ## Date Handling\n * Date values are automatically converted to backend-compatible format:\n * - Date objects: `new Date()` → `\"2026-01-05 10:30:45\"`\n * - ISO 8601 strings: `\"2026-01-05T00:00:00.000Z\"` → `\"2026-01-05 00:00:00\"`\n * - Works in nested objects and arrays\n *\n * ## Filter Operators\n * eq, ne, gt, ge, lt, le, like, sw, ew, bt, in\n *\n * Usage: `{ 'field[op]': value }` or `{ field: value }` (eq is default)\n */\nexport type EntityClient = {\n list<T = Record<string, unknown>>(\n source: string,\n entity: string,\n params?: EntityQueryParams\n ): Promise<ClientResult<EntityListResponse<T>>>;\n get<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number\n ): Promise<ClientResult<T>>;\n create<T = Record<string, unknown>>(\n source: string,\n entity: string,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>>;\n update<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>>;\n delete(source: string, entity: string, id: string | number): Promise<ClientResult<null>>;\n options<T = Record<string, unknown>>(\n source: string,\n entity: string,\n fields?: string[]\n ): Promise<ClientResult<T[]>>;\n bulkUpdate<T = Record<string, unknown>>(\n source: string,\n entity: string,\n items: Array<Record<string, unknown> & { id: string | number }>\n ): Promise<ClientResult<T>>;\n bulkDelete(\n source: string,\n entity: string,\n ids: Array<string | number>\n ): Promise<ClientResult<null>>;\n};\n\n// ==================== Helper Functions ====================\n\n/**\n * Convert Date object or ISO 8601 string to backend-compatible DATETIME format\n * Backend expects: \"YYYY-MM-DD HH:MM:SS\" (space-separated, no T or Z)\n */\nfunction formatDateForBackend(date: Date | string): string {\n let dateObj: Date;\n\n if (date instanceof Date) {\n dateObj = date;\n } else if (typeof date === \"string\") {\n dateObj = new Date(date);\n } else {\n dateObj = new Date(date);\n }\n\n // Check if date is valid\n if (Number.isNaN(dateObj.getTime())) {\n return String(date); // Return original value if invalid\n }\n\n // Format as \"YYYY-MM-DD HH:MM:SS\" in UTC\n const year = dateObj.getUTCFullYear();\n const month = String(dateObj.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(dateObj.getUTCDate()).padStart(2, \"0\");\n const hours = String(dateObj.getUTCHours()).padStart(2, \"0\");\n const minutes = String(dateObj.getUTCMinutes()).padStart(2, \"0\");\n const seconds = String(dateObj.getUTCSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * Recursively process data object to convert Date values to backend format\n * Handles nested objects and arrays\n */\nfunction processDataForBackend(data: unknown): unknown {\n if (data === null || data === undefined) {\n return data;\n }\n\n // Handle Date objects\n if (data instanceof Date) {\n return formatDateForBackend(data);\n }\n\n // Handle arrays\n if (Array.isArray(data)) {\n return data.map((item) => processDataForBackend(item));\n }\n\n // Handle objects\n if (typeof data === \"object\") {\n const processed: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n processed[key] = processDataForBackend(value);\n }\n return processed;\n }\n\n // Handle ISO 8601 date strings (detect pattern)\n if (typeof data === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(data)) {\n return formatDateForBackend(data);\n }\n\n return data;\n}\n\nfunction buildEntityUrl(source: string, entity: string, path = \"\"): string {\n const basePath = `/api/entity/data/${source}/${entity}`;\n return path ? `${basePath}${path.startsWith(\"/\") ? path : `/${path}`}` : basePath;\n}\n\nfunction encodeQueryParams(params?: Record<string, unknown>): string {\n if (!params || Object.keys(params).length === 0) {\n return \"\";\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (key === \"__filter\" && typeof value === \"object\") {\n searchParams.append(key, JSON.stringify(value));\n } else if (key === \"__relations\" && Array.isArray(value)) {\n for (const v of value) {\n searchParams.append(\"__relations[]\", String(v));\n }\n } else if (Array.isArray(value)) {\n for (const v of value) {\n searchParams.append(key, String(v));\n }\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n for (const [subKey, subValue] of Object.entries(value)) {\n if (subValue !== undefined && subValue !== null) {\n searchParams.append(`${key}[${subKey}]`, String(subValue));\n }\n }\n } else {\n searchParams.append(key, String(value));\n }\n }\n\n const query = searchParams.toString();\n return query ? `?${query}` : \"\";\n}\n\n// ==================== Client Factory ====================\n\nexport function createEntityClient(http: HttpClient = createHttpClient()): EntityClient {\n return {\n async list<T = Record<string, unknown>>(\n source: string,\n entity: string,\n params?: EntityQueryParams\n ): Promise<ClientResult<EntityListResponse<T>>> {\n const url = buildEntityUrl(source, entity) + encodeQueryParams(params);\n const result = await http.request<{\n items: T[];\n count?: number;\n total?: number;\n page?: number;\n perPage?: number;\n pageSize?: number;\n }>({\n url,\n method: \"get\",\n });\n\n if (result.error || !result.data) {\n return {\n data: { items: [], total: 0 },\n error: result.error,\n status: result.status,\n };\n }\n\n const items = Array.isArray(result.data.items) ? result.data.items : [];\n const total = result.data.total ?? result.data.count ?? items.length;\n\n return {\n ...result,\n data: {\n items,\n total,\n page: result.data.page,\n perPage: result.data.perPage || result.data.pageSize,\n },\n };\n },\n\n get<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number\n ): Promise<ClientResult<T>> {\n if (!id) {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity ID is required\", status: 400 },\n status: 400,\n });\n }\n const url = buildEntityUrl(source, entity, `/${id}`);\n return http.request<T>({\n url,\n method: \"get\",\n });\n },\n\n create<T = Record<string, unknown>>(\n source: string,\n entity: string,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>> {\n if (!data || typeof data !== \"object\") {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity data is required\", status: 400 },\n status: 400,\n });\n }\n\n const processedData = processDataForBackend(data);\n\n const url = buildEntityUrl(source, entity);\n return http.request<T>({\n url,\n method: \"post\",\n headers: { \"Content-Type\": \"application/json\" },\n data: processedData,\n });\n },\n\n update<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>> {\n if (!id) {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity ID is required\", status: 400 },\n status: 400,\n });\n }\n if (!data || typeof data !== \"object\") {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity data is required\", status: 400 },\n status: 400,\n });\n }\n\n const processedData = processDataForBackend(data);\n\n const url = buildEntityUrl(source, entity, `/${id}`);\n return http.request<T>({\n url,\n method: \"put\",\n headers: { \"Content-Type\": \"application/json\" },\n data: processedData,\n });\n },\n\n async delete(source: string, entity: string, id: string | number): Promise<ClientResult<null>> {\n if (!id) {\n return {\n data: null,\n error: { message: \"Entity ID is required\", status: 400 },\n status: 400,\n };\n }\n const url = buildEntityUrl(source, entity, `/${id}`);\n const result = await http.request<null>({\n url,\n method: \"delete\",\n });\n return result.status === 204 ? { ...result, data: null } : result;\n },\n\n async options<T = Record<string, unknown>>(\n source: string,\n entity: string,\n fields?: string[]\n ): Promise<ClientResult<T[]>> {\n const params = fields && fields.length > 0 ? { \"__fields[]\": fields } : undefined;\n\n const url = buildEntityUrl(source, entity, \"/options\") + encodeQueryParams(params);\n const result = await http.request<{ items: T[] }>({\n url,\n method: \"get\",\n });\n\n if (result.error || !result.data) {\n return {\n data: null,\n error: result.error,\n status: result.status,\n };\n }\n\n return {\n ...result,\n data: result.data.items || [],\n };\n },\n\n bulkUpdate<T = Record<string, unknown>>(\n source: string,\n entity: string,\n items: Array<Record<string, unknown> & { id: string | number }>\n ): Promise<ClientResult<T>> {\n if (!items || items.length === 0) {\n return Promise.resolve({\n data: null,\n error: { message: \"Items array is required\", status: 400 },\n status: 400,\n });\n }\n\n const processedItems = items.map((item) => processDataForBackend(item));\n\n const url = buildEntityUrl(source, entity, \"/bulkUpdate\");\n return http.request<T>({\n url,\n method: \"post\",\n headers: { \"Content-Type\": \"application/json\" },\n data: { items: processedItems },\n });\n },\n\n async bulkDelete(\n source: string,\n entity: string,\n ids: Array<string | number>\n ): Promise<ClientResult<null>> {\n if (!ids || ids.length === 0) {\n return {\n data: null,\n error: { message: \"IDs array is required\", status: 400 },\n status: 400,\n };\n }\n\n const url = buildEntityUrl(source, entity, `/${ids.join(\",\")}`);\n const result = await http.request<null>({\n url,\n method: \"delete\",\n });\n\n return result.status === 204 ? { ...result, data: null } : result;\n },\n };\n}\n"]}
@@ -0,0 +1,107 @@
1
+ import { ClientResult, HttpClient } from '@amaster.ai/http-client';
2
+
3
+ /**
4
+ * Entity Client Type Definitions
5
+ */
6
+ /**
7
+ * Filter operators supported by the entity API
8
+ */
9
+ type FilterOperator = "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "like" | "sw" | "ew" | "bt" | "in";
10
+ /**
11
+ * Advanced filter item
12
+ */
13
+ type FilterItem = {
14
+ op: "equal" | "not_equal" | "less" | "less_or_equal" | "greater" | "greater_or_equal" | "like" | "starts_with" | "ends_with" | "between" | "is_empty" | "is_not_empty";
15
+ left: {
16
+ type: "field";
17
+ field: string;
18
+ };
19
+ right: string | number | boolean | Date | null | string[];
20
+ };
21
+ /**
22
+ * Advanced filter group (supports AND/OR combinations)
23
+ */
24
+ type FilterGroup = {
25
+ conjunction: "and" | "or";
26
+ children: Array<FilterGroup | FilterItem>;
27
+ };
28
+ /**
29
+ * Entity query parameters
30
+ */
31
+ type EntityQueryParams = {
32
+ page?: number;
33
+ perPage?: number;
34
+ orderBy?: string;
35
+ orderDir?: "asc" | "desc";
36
+ __keywords?: string;
37
+ __relations?: string[];
38
+ __filter?: FilterGroup;
39
+ [key: string]: unknown;
40
+ };
41
+ /**
42
+ * Entity list response
43
+ */
44
+ type EntityListResponse<T = Record<string, unknown>> = {
45
+ items: T[];
46
+ total: number;
47
+ page?: number;
48
+ perPage?: number;
49
+ };
50
+
51
+ /**
52
+ * Entity Client - Type-safe client for entity CRUD operations
53
+ *
54
+ * ## Quick Start
55
+ * ```typescript
56
+ * const entityClient = createEntityClient();
57
+ *
58
+ * // List with pagination and sorting
59
+ * const result = await entityClient.list('default', 'tasks', {
60
+ * page: 1,
61
+ * perPage: 20,
62
+ * orderBy: 'createdAt',
63
+ * orderDir: 'desc'
64
+ * });
65
+ *
66
+ * // ⚠️ IMPORTANT: Access items via result.data.items, NOT result.data
67
+ * setTasks(result.data?.items || []); // ✅ Correct
68
+ * setTotal(result.data?.total || 0);
69
+ *
70
+ * // ❌ WRONG: setTasks(result.data || []) - result.data is an object, not an array!
71
+ *
72
+ * // Get single record
73
+ * const task = await entityClient.get('default', 'tasks', 1);
74
+ * setTask(result.data); // ✅ result.data is the entity object directly
75
+ *
76
+ * // CRUD operations
77
+ * await entityClient.create('default', 'tasks', { title: 'New', dueDate: new Date() });
78
+ * await entityClient.update('default', 'tasks', 1, { status: 'done' });
79
+ * await entityClient.delete('default', 'tasks', 1);
80
+ * ```
81
+ *
82
+ * ## Date Handling
83
+ * Date values are automatically converted to backend-compatible format:
84
+ * - Date objects: `new Date()` → `"2026-01-05 10:30:45"`
85
+ * - ISO 8601 strings: `"2026-01-05T00:00:00.000Z"` → `"2026-01-05 00:00:00"`
86
+ * - Works in nested objects and arrays
87
+ *
88
+ * ## Filter Operators
89
+ * eq, ne, gt, ge, lt, le, like, sw, ew, bt, in
90
+ *
91
+ * Usage: `{ 'field[op]': value }` or `{ field: value }` (eq is default)
92
+ */
93
+ type EntityClient = {
94
+ list<T = Record<string, unknown>>(source: string, entity: string, params?: EntityQueryParams): Promise<ClientResult<EntityListResponse<T>>>;
95
+ get<T = Record<string, unknown>>(source: string, entity: string, id: string | number): Promise<ClientResult<T>>;
96
+ create<T = Record<string, unknown>>(source: string, entity: string, data: Record<string, unknown>): Promise<ClientResult<T>>;
97
+ update<T = Record<string, unknown>>(source: string, entity: string, id: string | number, data: Record<string, unknown>): Promise<ClientResult<T>>;
98
+ delete(source: string, entity: string, id: string | number): Promise<ClientResult<null>>;
99
+ options<T = Record<string, unknown>>(source: string, entity: string, fields?: string[]): Promise<ClientResult<T[]>>;
100
+ bulkUpdate<T = Record<string, unknown>>(source: string, entity: string, items: Array<Record<string, unknown> & {
101
+ id: string | number;
102
+ }>): Promise<ClientResult<T>>;
103
+ bulkDelete(source: string, entity: string, ids: Array<string | number>): Promise<ClientResult<null>>;
104
+ };
105
+ declare function createEntityClient(http?: HttpClient): EntityClient;
106
+
107
+ export { type EntityClient, type EntityListResponse, type EntityQueryParams, type FilterGroup, type FilterItem, type FilterOperator, createEntityClient };
@@ -0,0 +1,107 @@
1
+ import { ClientResult, HttpClient } from '@amaster.ai/http-client';
2
+
3
+ /**
4
+ * Entity Client Type Definitions
5
+ */
6
+ /**
7
+ * Filter operators supported by the entity API
8
+ */
9
+ type FilterOperator = "eq" | "ne" | "gt" | "ge" | "lt" | "le" | "like" | "sw" | "ew" | "bt" | "in";
10
+ /**
11
+ * Advanced filter item
12
+ */
13
+ type FilterItem = {
14
+ op: "equal" | "not_equal" | "less" | "less_or_equal" | "greater" | "greater_or_equal" | "like" | "starts_with" | "ends_with" | "between" | "is_empty" | "is_not_empty";
15
+ left: {
16
+ type: "field";
17
+ field: string;
18
+ };
19
+ right: string | number | boolean | Date | null | string[];
20
+ };
21
+ /**
22
+ * Advanced filter group (supports AND/OR combinations)
23
+ */
24
+ type FilterGroup = {
25
+ conjunction: "and" | "or";
26
+ children: Array<FilterGroup | FilterItem>;
27
+ };
28
+ /**
29
+ * Entity query parameters
30
+ */
31
+ type EntityQueryParams = {
32
+ page?: number;
33
+ perPage?: number;
34
+ orderBy?: string;
35
+ orderDir?: "asc" | "desc";
36
+ __keywords?: string;
37
+ __relations?: string[];
38
+ __filter?: FilterGroup;
39
+ [key: string]: unknown;
40
+ };
41
+ /**
42
+ * Entity list response
43
+ */
44
+ type EntityListResponse<T = Record<string, unknown>> = {
45
+ items: T[];
46
+ total: number;
47
+ page?: number;
48
+ perPage?: number;
49
+ };
50
+
51
+ /**
52
+ * Entity Client - Type-safe client for entity CRUD operations
53
+ *
54
+ * ## Quick Start
55
+ * ```typescript
56
+ * const entityClient = createEntityClient();
57
+ *
58
+ * // List with pagination and sorting
59
+ * const result = await entityClient.list('default', 'tasks', {
60
+ * page: 1,
61
+ * perPage: 20,
62
+ * orderBy: 'createdAt',
63
+ * orderDir: 'desc'
64
+ * });
65
+ *
66
+ * // ⚠️ IMPORTANT: Access items via result.data.items, NOT result.data
67
+ * setTasks(result.data?.items || []); // ✅ Correct
68
+ * setTotal(result.data?.total || 0);
69
+ *
70
+ * // ❌ WRONG: setTasks(result.data || []) - result.data is an object, not an array!
71
+ *
72
+ * // Get single record
73
+ * const task = await entityClient.get('default', 'tasks', 1);
74
+ * setTask(result.data); // ✅ result.data is the entity object directly
75
+ *
76
+ * // CRUD operations
77
+ * await entityClient.create('default', 'tasks', { title: 'New', dueDate: new Date() });
78
+ * await entityClient.update('default', 'tasks', 1, { status: 'done' });
79
+ * await entityClient.delete('default', 'tasks', 1);
80
+ * ```
81
+ *
82
+ * ## Date Handling
83
+ * Date values are automatically converted to backend-compatible format:
84
+ * - Date objects: `new Date()` → `"2026-01-05 10:30:45"`
85
+ * - ISO 8601 strings: `"2026-01-05T00:00:00.000Z"` → `"2026-01-05 00:00:00"`
86
+ * - Works in nested objects and arrays
87
+ *
88
+ * ## Filter Operators
89
+ * eq, ne, gt, ge, lt, le, like, sw, ew, bt, in
90
+ *
91
+ * Usage: `{ 'field[op]': value }` or `{ field: value }` (eq is default)
92
+ */
93
+ type EntityClient = {
94
+ list<T = Record<string, unknown>>(source: string, entity: string, params?: EntityQueryParams): Promise<ClientResult<EntityListResponse<T>>>;
95
+ get<T = Record<string, unknown>>(source: string, entity: string, id: string | number): Promise<ClientResult<T>>;
96
+ create<T = Record<string, unknown>>(source: string, entity: string, data: Record<string, unknown>): Promise<ClientResult<T>>;
97
+ update<T = Record<string, unknown>>(source: string, entity: string, id: string | number, data: Record<string, unknown>): Promise<ClientResult<T>>;
98
+ delete(source: string, entity: string, id: string | number): Promise<ClientResult<null>>;
99
+ options<T = Record<string, unknown>>(source: string, entity: string, fields?: string[]): Promise<ClientResult<T[]>>;
100
+ bulkUpdate<T = Record<string, unknown>>(source: string, entity: string, items: Array<Record<string, unknown> & {
101
+ id: string | number;
102
+ }>): Promise<ClientResult<T>>;
103
+ bulkDelete(source: string, entity: string, ids: Array<string | number>): Promise<ClientResult<null>>;
104
+ };
105
+ declare function createEntityClient(http?: HttpClient): EntityClient;
106
+
107
+ export { type EntityClient, type EntityListResponse, type EntityQueryParams, type FilterGroup, type FilterItem, type FilterOperator, createEntityClient };
package/dist/index.js ADDED
@@ -0,0 +1,235 @@
1
+ import { createHttpClient } from '@amaster.ai/http-client';
2
+
3
+ // src/entity-client.ts
4
+ function formatDateForBackend(date) {
5
+ let dateObj;
6
+ if (date instanceof Date) {
7
+ dateObj = date;
8
+ } else if (typeof date === "string") {
9
+ dateObj = new Date(date);
10
+ } else {
11
+ dateObj = new Date(date);
12
+ }
13
+ if (Number.isNaN(dateObj.getTime())) {
14
+ return String(date);
15
+ }
16
+ const year = dateObj.getUTCFullYear();
17
+ const month = String(dateObj.getUTCMonth() + 1).padStart(2, "0");
18
+ const day = String(dateObj.getUTCDate()).padStart(2, "0");
19
+ const hours = String(dateObj.getUTCHours()).padStart(2, "0");
20
+ const minutes = String(dateObj.getUTCMinutes()).padStart(2, "0");
21
+ const seconds = String(dateObj.getUTCSeconds()).padStart(2, "0");
22
+ return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
23
+ }
24
+ function processDataForBackend(data) {
25
+ if (data === null || data === void 0) {
26
+ return data;
27
+ }
28
+ if (data instanceof Date) {
29
+ return formatDateForBackend(data);
30
+ }
31
+ if (Array.isArray(data)) {
32
+ return data.map((item) => processDataForBackend(item));
33
+ }
34
+ if (typeof data === "object") {
35
+ const processed = {};
36
+ for (const [key, value] of Object.entries(data)) {
37
+ processed[key] = processDataForBackend(value);
38
+ }
39
+ return processed;
40
+ }
41
+ if (typeof data === "string" && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/.test(data)) {
42
+ return formatDateForBackend(data);
43
+ }
44
+ return data;
45
+ }
46
+ function buildEntityUrl(source, entity, path = "") {
47
+ const basePath = `/api/entity/data/${source}/${entity}`;
48
+ return path ? `${basePath}${path.startsWith("/") ? path : `/${path}`}` : basePath;
49
+ }
50
+ function encodeQueryParams(params) {
51
+ if (!params || Object.keys(params).length === 0) {
52
+ return "";
53
+ }
54
+ const searchParams = new URLSearchParams();
55
+ for (const [key, value] of Object.entries(params)) {
56
+ if (value === void 0 || value === null) {
57
+ continue;
58
+ }
59
+ if (key === "__filter" && typeof value === "object") {
60
+ searchParams.append(key, JSON.stringify(value));
61
+ } else if (key === "__relations" && Array.isArray(value)) {
62
+ for (const v of value) {
63
+ searchParams.append("__relations[]", String(v));
64
+ }
65
+ } else if (Array.isArray(value)) {
66
+ for (const v of value) {
67
+ searchParams.append(key, String(v));
68
+ }
69
+ } else if (typeof value === "object" && !Array.isArray(value)) {
70
+ for (const [subKey, subValue] of Object.entries(value)) {
71
+ if (subValue !== void 0 && subValue !== null) {
72
+ searchParams.append(`${key}[${subKey}]`, String(subValue));
73
+ }
74
+ }
75
+ } else {
76
+ searchParams.append(key, String(value));
77
+ }
78
+ }
79
+ const query = searchParams.toString();
80
+ return query ? `?${query}` : "";
81
+ }
82
+ function createEntityClient(http = createHttpClient()) {
83
+ return {
84
+ async list(source, entity, params) {
85
+ const url = buildEntityUrl(source, entity) + encodeQueryParams(params);
86
+ const result = await http.request({
87
+ url,
88
+ method: "get"
89
+ });
90
+ if (result.error || !result.data) {
91
+ return {
92
+ data: { items: [], total: 0 },
93
+ error: result.error,
94
+ status: result.status
95
+ };
96
+ }
97
+ const items = Array.isArray(result.data.items) ? result.data.items : [];
98
+ const total = result.data.total ?? result.data.count ?? items.length;
99
+ return {
100
+ ...result,
101
+ data: {
102
+ items,
103
+ total,
104
+ page: result.data.page,
105
+ perPage: result.data.perPage || result.data.pageSize
106
+ }
107
+ };
108
+ },
109
+ get(source, entity, id) {
110
+ if (!id) {
111
+ return Promise.resolve({
112
+ data: null,
113
+ error: { message: "Entity ID is required", status: 400 },
114
+ status: 400
115
+ });
116
+ }
117
+ const url = buildEntityUrl(source, entity, `/${id}`);
118
+ return http.request({
119
+ url,
120
+ method: "get"
121
+ });
122
+ },
123
+ create(source, entity, data) {
124
+ if (!data || typeof data !== "object") {
125
+ return Promise.resolve({
126
+ data: null,
127
+ error: { message: "Entity data is required", status: 400 },
128
+ status: 400
129
+ });
130
+ }
131
+ const processedData = processDataForBackend(data);
132
+ const url = buildEntityUrl(source, entity);
133
+ return http.request({
134
+ url,
135
+ method: "post",
136
+ headers: { "Content-Type": "application/json" },
137
+ data: processedData
138
+ });
139
+ },
140
+ update(source, entity, id, data) {
141
+ if (!id) {
142
+ return Promise.resolve({
143
+ data: null,
144
+ error: { message: "Entity ID is required", status: 400 },
145
+ status: 400
146
+ });
147
+ }
148
+ if (!data || typeof data !== "object") {
149
+ return Promise.resolve({
150
+ data: null,
151
+ error: { message: "Entity data is required", status: 400 },
152
+ status: 400
153
+ });
154
+ }
155
+ const processedData = processDataForBackend(data);
156
+ const url = buildEntityUrl(source, entity, `/${id}`);
157
+ return http.request({
158
+ url,
159
+ method: "put",
160
+ headers: { "Content-Type": "application/json" },
161
+ data: processedData
162
+ });
163
+ },
164
+ async delete(source, entity, id) {
165
+ if (!id) {
166
+ return {
167
+ data: null,
168
+ error: { message: "Entity ID is required", status: 400 },
169
+ status: 400
170
+ };
171
+ }
172
+ const url = buildEntityUrl(source, entity, `/${id}`);
173
+ const result = await http.request({
174
+ url,
175
+ method: "delete"
176
+ });
177
+ return result.status === 204 ? { ...result, data: null } : result;
178
+ },
179
+ async options(source, entity, fields) {
180
+ const params = fields && fields.length > 0 ? { "__fields[]": fields } : void 0;
181
+ const url = buildEntityUrl(source, entity, "/options") + encodeQueryParams(params);
182
+ const result = await http.request({
183
+ url,
184
+ method: "get"
185
+ });
186
+ if (result.error || !result.data) {
187
+ return {
188
+ data: null,
189
+ error: result.error,
190
+ status: result.status
191
+ };
192
+ }
193
+ return {
194
+ ...result,
195
+ data: result.data.items || []
196
+ };
197
+ },
198
+ bulkUpdate(source, entity, items) {
199
+ if (!items || items.length === 0) {
200
+ return Promise.resolve({
201
+ data: null,
202
+ error: { message: "Items array is required", status: 400 },
203
+ status: 400
204
+ });
205
+ }
206
+ const processedItems = items.map((item) => processDataForBackend(item));
207
+ const url = buildEntityUrl(source, entity, "/bulkUpdate");
208
+ return http.request({
209
+ url,
210
+ method: "post",
211
+ headers: { "Content-Type": "application/json" },
212
+ data: { items: processedItems }
213
+ });
214
+ },
215
+ async bulkDelete(source, entity, ids) {
216
+ if (!ids || ids.length === 0) {
217
+ return {
218
+ data: null,
219
+ error: { message: "IDs array is required", status: 400 },
220
+ status: 400
221
+ };
222
+ }
223
+ const url = buildEntityUrl(source, entity, `/${ids.join(",")}`);
224
+ const result = await http.request({
225
+ url,
226
+ method: "delete"
227
+ });
228
+ return result.status === 204 ? { ...result, data: null } : result;
229
+ }
230
+ };
231
+ }
232
+
233
+ export { createEntityClient };
234
+ //# sourceMappingURL=index.js.map
235
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/entity-client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["import { type ClientResult, createHttpClient, type HttpClient } from \"@amaster.ai/http-client\";\nimport type { EntityListResponse, EntityQueryParams } from \"./types\";\n\n// Export types for convenience\nexport type { EntityListResponse, EntityQueryParams, FilterGroup, FilterItem, FilterOperator } from \"./types\";\n\n/**\n * Entity Client - Type-safe client for entity CRUD operations\n *\n * ## Quick Start\n * ```typescript\n * const entityClient = createEntityClient();\n *\n * // List with pagination and sorting\n * const result = await entityClient.list('default', 'tasks', {\n * page: 1,\n * perPage: 20,\n * orderBy: 'createdAt',\n * orderDir: 'desc'\n * });\n *\n * // ⚠️ IMPORTANT: Access items via result.data.items, NOT result.data\n * setTasks(result.data?.items || []); // ✅ Correct\n * setTotal(result.data?.total || 0);\n *\n * // ❌ WRONG: setTasks(result.data || []) - result.data is an object, not an array!\n *\n * // Get single record\n * const task = await entityClient.get('default', 'tasks', 1);\n * setTask(result.data); // ✅ result.data is the entity object directly\n *\n * // CRUD operations\n * await entityClient.create('default', 'tasks', { title: 'New', dueDate: new Date() });\n * await entityClient.update('default', 'tasks', 1, { status: 'done' });\n * await entityClient.delete('default', 'tasks', 1);\n * ```\n *\n * ## Date Handling\n * Date values are automatically converted to backend-compatible format:\n * - Date objects: `new Date()` → `\"2026-01-05 10:30:45\"`\n * - ISO 8601 strings: `\"2026-01-05T00:00:00.000Z\"` → `\"2026-01-05 00:00:00\"`\n * - Works in nested objects and arrays\n *\n * ## Filter Operators\n * eq, ne, gt, ge, lt, le, like, sw, ew, bt, in\n *\n * Usage: `{ 'field[op]': value }` or `{ field: value }` (eq is default)\n */\nexport type EntityClient = {\n list<T = Record<string, unknown>>(\n source: string,\n entity: string,\n params?: EntityQueryParams\n ): Promise<ClientResult<EntityListResponse<T>>>;\n get<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number\n ): Promise<ClientResult<T>>;\n create<T = Record<string, unknown>>(\n source: string,\n entity: string,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>>;\n update<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>>;\n delete(source: string, entity: string, id: string | number): Promise<ClientResult<null>>;\n options<T = Record<string, unknown>>(\n source: string,\n entity: string,\n fields?: string[]\n ): Promise<ClientResult<T[]>>;\n bulkUpdate<T = Record<string, unknown>>(\n source: string,\n entity: string,\n items: Array<Record<string, unknown> & { id: string | number }>\n ): Promise<ClientResult<T>>;\n bulkDelete(\n source: string,\n entity: string,\n ids: Array<string | number>\n ): Promise<ClientResult<null>>;\n};\n\n// ==================== Helper Functions ====================\n\n/**\n * Convert Date object or ISO 8601 string to backend-compatible DATETIME format\n * Backend expects: \"YYYY-MM-DD HH:MM:SS\" (space-separated, no T or Z)\n */\nfunction formatDateForBackend(date: Date | string): string {\n let dateObj: Date;\n\n if (date instanceof Date) {\n dateObj = date;\n } else if (typeof date === \"string\") {\n dateObj = new Date(date);\n } else {\n dateObj = new Date(date);\n }\n\n // Check if date is valid\n if (Number.isNaN(dateObj.getTime())) {\n return String(date); // Return original value if invalid\n }\n\n // Format as \"YYYY-MM-DD HH:MM:SS\" in UTC\n const year = dateObj.getUTCFullYear();\n const month = String(dateObj.getUTCMonth() + 1).padStart(2, \"0\");\n const day = String(dateObj.getUTCDate()).padStart(2, \"0\");\n const hours = String(dateObj.getUTCHours()).padStart(2, \"0\");\n const minutes = String(dateObj.getUTCMinutes()).padStart(2, \"0\");\n const seconds = String(dateObj.getUTCSeconds()).padStart(2, \"0\");\n\n return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;\n}\n\n/**\n * Recursively process data object to convert Date values to backend format\n * Handles nested objects and arrays\n */\nfunction processDataForBackend(data: unknown): unknown {\n if (data === null || data === undefined) {\n return data;\n }\n\n // Handle Date objects\n if (data instanceof Date) {\n return formatDateForBackend(data);\n }\n\n // Handle arrays\n if (Array.isArray(data)) {\n return data.map((item) => processDataForBackend(item));\n }\n\n // Handle objects\n if (typeof data === \"object\") {\n const processed: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(data)) {\n processed[key] = processDataForBackend(value);\n }\n return processed;\n }\n\n // Handle ISO 8601 date strings (detect pattern)\n if (typeof data === \"string\" && /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}/.test(data)) {\n return formatDateForBackend(data);\n }\n\n return data;\n}\n\nfunction buildEntityUrl(source: string, entity: string, path = \"\"): string {\n const basePath = `/api/entity/data/${source}/${entity}`;\n return path ? `${basePath}${path.startsWith(\"/\") ? path : `/${path}`}` : basePath;\n}\n\nfunction encodeQueryParams(params?: Record<string, unknown>): string {\n if (!params || Object.keys(params).length === 0) {\n return \"\";\n }\n\n const searchParams = new URLSearchParams();\n\n for (const [key, value] of Object.entries(params)) {\n if (value === undefined || value === null) {\n continue;\n }\n\n if (key === \"__filter\" && typeof value === \"object\") {\n searchParams.append(key, JSON.stringify(value));\n } else if (key === \"__relations\" && Array.isArray(value)) {\n for (const v of value) {\n searchParams.append(\"__relations[]\", String(v));\n }\n } else if (Array.isArray(value)) {\n for (const v of value) {\n searchParams.append(key, String(v));\n }\n } else if (typeof value === \"object\" && !Array.isArray(value)) {\n for (const [subKey, subValue] of Object.entries(value)) {\n if (subValue !== undefined && subValue !== null) {\n searchParams.append(`${key}[${subKey}]`, String(subValue));\n }\n }\n } else {\n searchParams.append(key, String(value));\n }\n }\n\n const query = searchParams.toString();\n return query ? `?${query}` : \"\";\n}\n\n// ==================== Client Factory ====================\n\nexport function createEntityClient(http: HttpClient = createHttpClient()): EntityClient {\n return {\n async list<T = Record<string, unknown>>(\n source: string,\n entity: string,\n params?: EntityQueryParams\n ): Promise<ClientResult<EntityListResponse<T>>> {\n const url = buildEntityUrl(source, entity) + encodeQueryParams(params);\n const result = await http.request<{\n items: T[];\n count?: number;\n total?: number;\n page?: number;\n perPage?: number;\n pageSize?: number;\n }>({\n url,\n method: \"get\",\n });\n\n if (result.error || !result.data) {\n return {\n data: { items: [], total: 0 },\n error: result.error,\n status: result.status,\n };\n }\n\n const items = Array.isArray(result.data.items) ? result.data.items : [];\n const total = result.data.total ?? result.data.count ?? items.length;\n\n return {\n ...result,\n data: {\n items,\n total,\n page: result.data.page,\n perPage: result.data.perPage || result.data.pageSize,\n },\n };\n },\n\n get<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number\n ): Promise<ClientResult<T>> {\n if (!id) {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity ID is required\", status: 400 },\n status: 400,\n });\n }\n const url = buildEntityUrl(source, entity, `/${id}`);\n return http.request<T>({\n url,\n method: \"get\",\n });\n },\n\n create<T = Record<string, unknown>>(\n source: string,\n entity: string,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>> {\n if (!data || typeof data !== \"object\") {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity data is required\", status: 400 },\n status: 400,\n });\n }\n\n const processedData = processDataForBackend(data);\n\n const url = buildEntityUrl(source, entity);\n return http.request<T>({\n url,\n method: \"post\",\n headers: { \"Content-Type\": \"application/json\" },\n data: processedData,\n });\n },\n\n update<T = Record<string, unknown>>(\n source: string,\n entity: string,\n id: string | number,\n data: Record<string, unknown>\n ): Promise<ClientResult<T>> {\n if (!id) {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity ID is required\", status: 400 },\n status: 400,\n });\n }\n if (!data || typeof data !== \"object\") {\n return Promise.resolve({\n data: null,\n error: { message: \"Entity data is required\", status: 400 },\n status: 400,\n });\n }\n\n const processedData = processDataForBackend(data);\n\n const url = buildEntityUrl(source, entity, `/${id}`);\n return http.request<T>({\n url,\n method: \"put\",\n headers: { \"Content-Type\": \"application/json\" },\n data: processedData,\n });\n },\n\n async delete(source: string, entity: string, id: string | number): Promise<ClientResult<null>> {\n if (!id) {\n return {\n data: null,\n error: { message: \"Entity ID is required\", status: 400 },\n status: 400,\n };\n }\n const url = buildEntityUrl(source, entity, `/${id}`);\n const result = await http.request<null>({\n url,\n method: \"delete\",\n });\n return result.status === 204 ? { ...result, data: null } : result;\n },\n\n async options<T = Record<string, unknown>>(\n source: string,\n entity: string,\n fields?: string[]\n ): Promise<ClientResult<T[]>> {\n const params = fields && fields.length > 0 ? { \"__fields[]\": fields } : undefined;\n\n const url = buildEntityUrl(source, entity, \"/options\") + encodeQueryParams(params);\n const result = await http.request<{ items: T[] }>({\n url,\n method: \"get\",\n });\n\n if (result.error || !result.data) {\n return {\n data: null,\n error: result.error,\n status: result.status,\n };\n }\n\n return {\n ...result,\n data: result.data.items || [],\n };\n },\n\n bulkUpdate<T = Record<string, unknown>>(\n source: string,\n entity: string,\n items: Array<Record<string, unknown> & { id: string | number }>\n ): Promise<ClientResult<T>> {\n if (!items || items.length === 0) {\n return Promise.resolve({\n data: null,\n error: { message: \"Items array is required\", status: 400 },\n status: 400,\n });\n }\n\n const processedItems = items.map((item) => processDataForBackend(item));\n\n const url = buildEntityUrl(source, entity, \"/bulkUpdate\");\n return http.request<T>({\n url,\n method: \"post\",\n headers: { \"Content-Type\": \"application/json\" },\n data: { items: processedItems },\n });\n },\n\n async bulkDelete(\n source: string,\n entity: string,\n ids: Array<string | number>\n ): Promise<ClientResult<null>> {\n if (!ids || ids.length === 0) {\n return {\n data: null,\n error: { message: \"IDs array is required\", status: 400 },\n status: 400,\n };\n }\n\n const url = buildEntityUrl(source, entity, `/${ids.join(\",\")}`);\n const result = await http.request<null>({\n url,\n method: \"delete\",\n });\n\n return result.status === 204 ? { ...result, data: null } : result;\n },\n };\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,50 @@
1
+ {
2
+ "name": "@amaster.ai/entity-client",
3
+ "version": "1.0.0-beta.0",
4
+ "description": "Type-safe CRUD client for entity data management",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "types": "./dist/index.d.ts",
9
+ "exports": {
10
+ ".": {
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs",
13
+ "types": "./dist/index.d.ts"
14
+ }
15
+ },
16
+ "files": [
17
+ "dist",
18
+ "README.md"
19
+ ],
20
+ "keywords": [
21
+ "entity",
22
+ "crud",
23
+ "api",
24
+ "client",
25
+ "typescript"
26
+ ],
27
+ "author": "Amaster Team",
28
+ "license": "MIT",
29
+ "publishConfig": {
30
+ "access": "public",
31
+ "registry": "https://registry.npmjs.org/"
32
+ },
33
+ "dependencies": {
34
+ "@amaster.ai/http-client": "1.0.0-beta.0"
35
+ },
36
+ "peerDependencies": {
37
+ "axios": "^1.11.0"
38
+ },
39
+ "devDependencies": {
40
+ "axios": "^1.11.0",
41
+ "tsup": "^8.3.5",
42
+ "typescript": "~5.7.2"
43
+ },
44
+ "scripts": {
45
+ "build": "tsup",
46
+ "dev": "tsup --watch",
47
+ "clean": "rm -rf dist *.tsbuildinfo",
48
+ "type-check": "tsc --noEmit"
49
+ }
50
+ }