@ram_28/kf-ai-sdk 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +840 -0
- package/dist/api/client.d.ts +78 -0
- package/dist/api/client.d.ts.map +1 -0
- package/dist/api/datetime.d.ts +21 -0
- package/dist/api/datetime.d.ts.map +1 -0
- package/dist/api/index.d.ts +7 -0
- package/dist/api/index.d.ts.map +1 -0
- package/dist/api/metadata.d.ts +75 -0
- package/dist/api/metadata.d.ts.map +1 -0
- package/dist/components/hooks/index.d.ts +8 -0
- package/dist/components/hooks/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/index.d.ts +5 -0
- package/dist/components/hooks/useFilter/index.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts +33 -0
- package/dist/components/hooks/useFilter/payloadBuilder.utils.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/types.d.ts +137 -0
- package/dist/components/hooks/useFilter/types.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts +3 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts +38 -0
- package/dist/components/hooks/useFilter/validation.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/apiClient.d.ts +71 -0
- package/dist/components/hooks/useForm/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/expressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/index.d.ts +6 -0
- package/dist/components/hooks/useForm/index.d.ts.map +1 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts +88 -0
- package/dist/components/hooks/useForm/optimizedExpressionValidator.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts +28 -0
- package/dist/components/hooks/useForm/ruleClassifier.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts +29 -0
- package/dist/components/hooks/useForm/schemaParser.utils.d.ts.map +1 -0
- package/dist/components/hooks/useForm/types.d.ts +412 -0
- package/dist/components/hooks/useForm/types.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +3 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts +99 -0
- package/dist/components/hooks/useKanban/apiClient.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/context.d.ts +4 -0
- package/dist/components/hooks/useKanban/context.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts +27 -0
- package/dist/components/hooks/useKanban/dragDropManager.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/index.d.ts +6 -0
- package/dist/components/hooks/useKanban/index.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/types.d.ts +438 -0
- package/dist/components/hooks/useKanban/types.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts +3 -0
- package/dist/components/hooks/useKanban/useKanban.d.ts.map +1 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts +62 -0
- package/dist/components/hooks/useKanban/useKanbanSimple.d.ts.map +1 -0
- package/dist/components/hooks/useTable/index.d.ts +3 -0
- package/dist/components/hooks/useTable/index.d.ts.map +1 -0
- package/dist/components/hooks/useTable/types.d.ts +107 -0
- package/dist/components/hooks/useTable/types.d.ts.map +1 -0
- package/dist/components/hooks/useTable/useTable.d.ts +8 -0
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -0
- package/dist/components/index.d.ts +3 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/ui/index.d.ts +2 -0
- package/dist/components/ui/index.d.ts.map +1 -0
- package/dist/components/ui/kanban/Kanban.d.ts +12 -0
- package/dist/components/ui/kanban/Kanban.d.ts.map +1 -0
- package/dist/components/ui/kanban/index.d.ts +2 -0
- package/dist/components/ui/kanban/index.d.ts.map +1 -0
- package/dist/index.cjs +45 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.mjs +6522 -0
- package/dist/types/base-fields.d.ts +182 -0
- package/dist/types/base-fields.d.ts.map +1 -0
- package/dist/types/common.d.ts +238 -0
- package/dist/types/common.d.ts.map +1 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +7 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/formatting.d.ts +52 -0
- package/dist/utils/formatting.d.ts.map +1 -0
- package/dist/utils/index.d.ts +3 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +98 -0
- package/sdk/api/client.ts +447 -0
- package/sdk/api/datetime.ts +33 -0
- package/sdk/api/index.ts +61 -0
- package/sdk/api/metadata.ts +148 -0
- package/sdk/components/hooks/index.ts +34 -0
- package/sdk/components/hooks/useFilter/index.ts +37 -0
- package/sdk/components/hooks/useFilter/payloadBuilder.utils.ts +298 -0
- package/sdk/components/hooks/useFilter/types.ts +158 -0
- package/sdk/components/hooks/useFilter/useFilter.llm.txt +497 -0
- package/sdk/components/hooks/useFilter/useFilter.ts +494 -0
- package/sdk/components/hooks/useFilter/validation.utils.ts +401 -0
- package/sdk/components/hooks/useForm/apiClient.ts +441 -0
- package/sdk/components/hooks/useForm/expressionValidator.utils.ts +444 -0
- package/sdk/components/hooks/useForm/index.ts +64 -0
- package/sdk/components/hooks/useForm/optimizedExpressionValidator.utils.ts +482 -0
- package/sdk/components/hooks/useForm/ruleClassifier.utils.ts +424 -0
- package/sdk/components/hooks/useForm/schemaParser.utils.ts +519 -0
- package/sdk/components/hooks/useForm/types.ts +630 -0
- package/sdk/components/hooks/useForm/useForm.llm.txt +340 -0
- package/sdk/components/hooks/useForm/useForm.ts +821 -0
- package/sdk/components/hooks/useKanban/apiClient.ts +494 -0
- package/sdk/components/hooks/useKanban/context.ts +14 -0
- package/sdk/components/hooks/useKanban/dragDropManager.ts +529 -0
- package/sdk/components/hooks/useKanban/index.ts +63 -0
- package/sdk/components/hooks/useKanban/types.ts +606 -0
- package/sdk/components/hooks/useKanban/useKanban.llm.txt +482 -0
- package/sdk/components/hooks/useKanban/useKanban.ts +725 -0
- package/sdk/components/hooks/useKanban/useKanbanSimple.ts +389 -0
- package/sdk/components/hooks/useTable/index.ts +5 -0
- package/sdk/components/hooks/useTable/types.ts +154 -0
- package/sdk/components/hooks/useTable/useTable.llm.txt +344 -0
- package/sdk/components/hooks/useTable/useTable.ts +413 -0
- package/sdk/components/index.ts +15 -0
- package/sdk/components/ui/index.ts +2 -0
- package/sdk/components/ui/kanban/Kanban.tsx +134 -0
- package/sdk/components/ui/kanban/index.ts +11 -0
- package/sdk/index.ts +13 -0
- package/sdk/types/base-fields.ts +221 -0
- package/sdk/types/common.ts +306 -0
- package/sdk/types/index.ts +5 -0
- package/sdk/utils/cn.ts +10 -0
- package/sdk/utils/formatting.ts +212 -0
- package/sdk/utils/index.ts +5 -0
|
@@ -0,0 +1,447 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// API Client - Simple CRUD Operations
|
|
3
|
+
// ============================================================
|
|
4
|
+
|
|
5
|
+
import type {
|
|
6
|
+
ListOptions,
|
|
7
|
+
ListResponse,
|
|
8
|
+
ReadResponse,
|
|
9
|
+
CreateUpdateResponse,
|
|
10
|
+
DeleteResponse,
|
|
11
|
+
CountResponse,
|
|
12
|
+
DateTimeEncoded,
|
|
13
|
+
DateEncoded,
|
|
14
|
+
MetricOptions,
|
|
15
|
+
MetricResponse,
|
|
16
|
+
PivotOptions,
|
|
17
|
+
PivotResponse,
|
|
18
|
+
DraftResponse,
|
|
19
|
+
FieldsResponse,
|
|
20
|
+
FetchFieldOption,
|
|
21
|
+
FetchFieldResponse,
|
|
22
|
+
} from "../types/common";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* API client interface for a specific Business Object
|
|
26
|
+
*/
|
|
27
|
+
export interface ResourceClient<T = any> {
|
|
28
|
+
// ============================================================
|
|
29
|
+
// BASIC CRUD OPERATIONS
|
|
30
|
+
// ============================================================
|
|
31
|
+
|
|
32
|
+
/** Get single record by ID */
|
|
33
|
+
get(id: string): Promise<T>;
|
|
34
|
+
|
|
35
|
+
/** Create new record */
|
|
36
|
+
create(data: Partial<T> & { _id?: string }): Promise<CreateUpdateResponse>;
|
|
37
|
+
|
|
38
|
+
/** Update existing record */
|
|
39
|
+
update(id: string, data: Partial<T>): Promise<CreateUpdateResponse>;
|
|
40
|
+
|
|
41
|
+
/** Delete record by ID */
|
|
42
|
+
delete(id: string): Promise<DeleteResponse>;
|
|
43
|
+
|
|
44
|
+
/** List records with optional filtering, sorting, and pagination */
|
|
45
|
+
list(options?: ListOptions): Promise<ListResponse<T>>;
|
|
46
|
+
|
|
47
|
+
/** Get count of records matching the same criteria as list */
|
|
48
|
+
count(options?: ListOptions): Promise<CountResponse>;
|
|
49
|
+
|
|
50
|
+
// ============================================================
|
|
51
|
+
// DRAFT/INTERACTIVE OPERATIONS
|
|
52
|
+
// ============================================================
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Create draft - compute fields without persisting
|
|
56
|
+
* POST /{bo_id}/draft
|
|
57
|
+
*/
|
|
58
|
+
draft(data: Partial<T>): Promise<DraftResponse>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Update draft (commit) - compute and prepare for update
|
|
62
|
+
* POST /{bo_id}/{instance_id}/draft
|
|
63
|
+
*/
|
|
64
|
+
draftUpdate(id: string, data: Partial<T>): Promise<CreateUpdateResponse>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Update draft (patch) - compute fields during editing
|
|
68
|
+
* PATCH /{bo_id}/{instance_id}/draft
|
|
69
|
+
*/
|
|
70
|
+
draftPatch(id: string, data: Partial<T>): Promise<DraftResponse>;
|
|
71
|
+
|
|
72
|
+
// ============================================================
|
|
73
|
+
// QUERY OPERATIONS
|
|
74
|
+
// ============================================================
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get aggregated metrics grouped by dimensions
|
|
78
|
+
* POST /{bo_id}/metric
|
|
79
|
+
*/
|
|
80
|
+
metric(options: Omit<MetricOptions, "Type">): Promise<MetricResponse>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Get pivot table data
|
|
84
|
+
* POST /{bo_id}/pivot
|
|
85
|
+
*/
|
|
86
|
+
pivot(options: Omit<PivotOptions, "Type">): Promise<PivotResponse>;
|
|
87
|
+
|
|
88
|
+
// ============================================================
|
|
89
|
+
// METADATA OPERATIONS
|
|
90
|
+
// ============================================================
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Get field definitions for this Business Object
|
|
94
|
+
* GET /{bo_id}/fields
|
|
95
|
+
*/
|
|
96
|
+
fields(): Promise<FieldsResponse>;
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Fetch reference data for a specific field (for lookup and dropdown fields)
|
|
100
|
+
* GET /{bo_id}/{instance_id}/field/{field_id}/fetch
|
|
101
|
+
*/
|
|
102
|
+
fetchField(instanceId: string, fieldId: string): Promise<FetchFieldOption[]>;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Configuration options for the API client
|
|
107
|
+
*/
|
|
108
|
+
interface ApiConfig {
|
|
109
|
+
baseUrl?: string;
|
|
110
|
+
headers?: Record<string, string>;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Global API configuration
|
|
115
|
+
*/
|
|
116
|
+
let apiConfig: ApiConfig = {
|
|
117
|
+
baseUrl: "",
|
|
118
|
+
headers: {
|
|
119
|
+
"Content-Type": "application/json",
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Set the base URL for all API requests
|
|
125
|
+
*/
|
|
126
|
+
export function setApiBaseUrl(baseUrl: string): void {
|
|
127
|
+
apiConfig.baseUrl = baseUrl;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Set default headers for all requests
|
|
132
|
+
*/
|
|
133
|
+
export function setDefaultHeaders(headers: Record<string, string>): void {
|
|
134
|
+
apiConfig.headers = { ...apiConfig.headers, ...headers };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Get current default headers
|
|
139
|
+
*/
|
|
140
|
+
export function getDefaultHeaders(): Record<string, string> {
|
|
141
|
+
return { ...apiConfig.headers };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Get current base URL
|
|
146
|
+
*/
|
|
147
|
+
export function getApiBaseUrl(): string {
|
|
148
|
+
return apiConfig.baseUrl || "";
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Recursively process an object to decode datetime fields
|
|
153
|
+
*/
|
|
154
|
+
function decodeResponseData<T>(data: any): T {
|
|
155
|
+
if (data === null || data === undefined) {
|
|
156
|
+
return data;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (Array.isArray(data)) {
|
|
160
|
+
return data.map((item) => decodeResponseData(item)) as T;
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
if (typeof data === "object") {
|
|
164
|
+
// Check for datetime encoding
|
|
165
|
+
if ("$__dt__" in data) {
|
|
166
|
+
return new Date((data as DateTimeEncoded).$__dt__ * 1000) as T;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// Check for date encoding
|
|
170
|
+
if ("$__d__" in data) {
|
|
171
|
+
return new Date((data as DateEncoded).$__d__) as T;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// Recursively process object properties
|
|
175
|
+
const result: any = {};
|
|
176
|
+
for (const [key, value] of Object.entries(data)) {
|
|
177
|
+
result[key] = decodeResponseData(value);
|
|
178
|
+
}
|
|
179
|
+
return result as T;
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return data as T;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Create a resource client for the specified Business Object
|
|
187
|
+
* @param bo_id - Business Object identifier (e.g., "user", "leave", "vendor")
|
|
188
|
+
* @returns Resource client with CRUD operations matching API spec
|
|
189
|
+
*/
|
|
190
|
+
export function api<T = any>(bo_id: string): ResourceClient<T> {
|
|
191
|
+
const baseUrl = apiConfig.baseUrl;
|
|
192
|
+
const defaultHeaders = apiConfig.headers;
|
|
193
|
+
|
|
194
|
+
return {
|
|
195
|
+
async get(id: string): Promise<T> {
|
|
196
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/${id}/read`, {
|
|
197
|
+
method: "GET",
|
|
198
|
+
headers: defaultHeaders,
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
if (!response.ok) {
|
|
202
|
+
throw new Error(`Failed to get ${bo_id} ${id}: ${response.statusText}`);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
const responseData: ReadResponse<T> = await response.json();
|
|
206
|
+
return decodeResponseData<T>(responseData.Data);
|
|
207
|
+
},
|
|
208
|
+
|
|
209
|
+
async create(
|
|
210
|
+
data: Partial<T> & { _id?: string }
|
|
211
|
+
): Promise<CreateUpdateResponse> {
|
|
212
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/create`, {
|
|
213
|
+
method: "POST",
|
|
214
|
+
headers: defaultHeaders,
|
|
215
|
+
body: JSON.stringify(data),
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
if (!response.ok) {
|
|
219
|
+
throw new Error(`Failed to create ${bo_id}: ${response.statusText}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return response.json();
|
|
223
|
+
},
|
|
224
|
+
|
|
225
|
+
async update(id: string, data: Partial<T>): Promise<CreateUpdateResponse> {
|
|
226
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/${id}/update`, {
|
|
227
|
+
method: "POST",
|
|
228
|
+
headers: defaultHeaders,
|
|
229
|
+
body: JSON.stringify(data),
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
if (!response.ok) {
|
|
233
|
+
throw new Error(
|
|
234
|
+
`Failed to update ${bo_id} ${id}: ${response.statusText}`
|
|
235
|
+
);
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
return response.json();
|
|
239
|
+
},
|
|
240
|
+
|
|
241
|
+
async delete(id: string): Promise<DeleteResponse> {
|
|
242
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/${id}/delete`, {
|
|
243
|
+
method: "DELETE",
|
|
244
|
+
headers: defaultHeaders,
|
|
245
|
+
});
|
|
246
|
+
|
|
247
|
+
if (!response.ok) {
|
|
248
|
+
throw new Error(
|
|
249
|
+
`Failed to delete ${bo_id} ${id}: ${response.statusText}`
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
return response.json();
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
async list(options?: ListOptions): Promise<ListResponse<T>> {
|
|
257
|
+
const requestBody: ListOptions = {
|
|
258
|
+
Type: "List",
|
|
259
|
+
...options,
|
|
260
|
+
};
|
|
261
|
+
|
|
262
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/list`, {
|
|
263
|
+
method: "POST",
|
|
264
|
+
headers: defaultHeaders,
|
|
265
|
+
body: JSON.stringify(requestBody),
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
if (!response.ok) {
|
|
269
|
+
throw new Error(`Failed to list ${bo_id}: ${response.statusText}`);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
const responseData: ListResponse<any> = await response.json();
|
|
273
|
+
return {
|
|
274
|
+
Data: responseData.Data.map((item) => decodeResponseData<T>(item)),
|
|
275
|
+
};
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
async count(options?: ListOptions): Promise<CountResponse> {
|
|
279
|
+
// Note: Count uses metric endpoint with Count aggregation
|
|
280
|
+
const requestBody = {
|
|
281
|
+
Type: "Metric",
|
|
282
|
+
GroupBy: [],
|
|
283
|
+
Metric: [{ Field: "_id", Type: "Count" }],
|
|
284
|
+
...(options?.Filter && { Filter: options.Filter }),
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/metric`, {
|
|
288
|
+
method: "POST",
|
|
289
|
+
headers: defaultHeaders,
|
|
290
|
+
body: JSON.stringify(requestBody),
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
if (!response.ok) {
|
|
294
|
+
throw new Error(`Failed to count ${bo_id}: ${response.statusText}`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
const result = await response.json();
|
|
298
|
+
// Extract count from metric response
|
|
299
|
+
const count = result.Data?.[0]?.count__id ?? 0;
|
|
300
|
+
return { Count: count };
|
|
301
|
+
},
|
|
302
|
+
|
|
303
|
+
// ============================================================
|
|
304
|
+
// DRAFT/INTERACTIVE OPERATIONS
|
|
305
|
+
// ============================================================
|
|
306
|
+
|
|
307
|
+
async draft(data: Partial<T>): Promise<DraftResponse> {
|
|
308
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/draft`, {
|
|
309
|
+
method: "POST",
|
|
310
|
+
headers: defaultHeaders,
|
|
311
|
+
body: JSON.stringify(data),
|
|
312
|
+
});
|
|
313
|
+
|
|
314
|
+
if (!response.ok) {
|
|
315
|
+
throw new Error(
|
|
316
|
+
`Failed to create draft for ${bo_id}: ${response.statusText}`
|
|
317
|
+
);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return response.json();
|
|
321
|
+
},
|
|
322
|
+
|
|
323
|
+
async draftUpdate(
|
|
324
|
+
id: string,
|
|
325
|
+
data: Partial<T>
|
|
326
|
+
): Promise<CreateUpdateResponse> {
|
|
327
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/${id}/draft`, {
|
|
328
|
+
method: "POST",
|
|
329
|
+
headers: defaultHeaders,
|
|
330
|
+
body: JSON.stringify(data),
|
|
331
|
+
});
|
|
332
|
+
|
|
333
|
+
if (!response.ok) {
|
|
334
|
+
throw new Error(
|
|
335
|
+
`Failed to update draft for ${bo_id} ${id}: ${response.statusText}`
|
|
336
|
+
);
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
return response.json();
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
async draftPatch(id: string, data: Partial<T>): Promise<DraftResponse> {
|
|
343
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/${id}/draft`, {
|
|
344
|
+
method: "PATCH",
|
|
345
|
+
headers: defaultHeaders,
|
|
346
|
+
body: JSON.stringify(data),
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
if (!response.ok) {
|
|
350
|
+
throw new Error(
|
|
351
|
+
`Failed to patch draft for ${bo_id} ${id}: ${response.statusText}`
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return response.json();
|
|
356
|
+
},
|
|
357
|
+
|
|
358
|
+
// ============================================================
|
|
359
|
+
// QUERY OPERATIONS
|
|
360
|
+
// ============================================================
|
|
361
|
+
|
|
362
|
+
async metric(
|
|
363
|
+
options: Omit<MetricOptions, "Type">
|
|
364
|
+
): Promise<MetricResponse> {
|
|
365
|
+
const requestBody: MetricOptions = {
|
|
366
|
+
Type: "Metric",
|
|
367
|
+
...options,
|
|
368
|
+
};
|
|
369
|
+
|
|
370
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/metric`, {
|
|
371
|
+
method: "POST",
|
|
372
|
+
headers: defaultHeaders,
|
|
373
|
+
body: JSON.stringify(requestBody),
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
if (!response.ok) {
|
|
377
|
+
throw new Error(
|
|
378
|
+
`Failed to get metrics for ${bo_id}: ${response.statusText}`
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return response.json();
|
|
383
|
+
},
|
|
384
|
+
|
|
385
|
+
async pivot(options: Omit<PivotOptions, "Type">): Promise<PivotResponse> {
|
|
386
|
+
const requestBody: PivotOptions = {
|
|
387
|
+
Type: "Pivot",
|
|
388
|
+
...options,
|
|
389
|
+
};
|
|
390
|
+
|
|
391
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/pivot`, {
|
|
392
|
+
method: "POST",
|
|
393
|
+
headers: defaultHeaders,
|
|
394
|
+
body: JSON.stringify(requestBody),
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
if (!response.ok) {
|
|
398
|
+
throw new Error(
|
|
399
|
+
`Failed to get pivot data for ${bo_id}: ${response.statusText}`
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
return response.json();
|
|
404
|
+
},
|
|
405
|
+
|
|
406
|
+
// ============================================================
|
|
407
|
+
// METADATA OPERATIONS
|
|
408
|
+
// ============================================================
|
|
409
|
+
|
|
410
|
+
async fields(): Promise<FieldsResponse> {
|
|
411
|
+
const response = await fetch(`${baseUrl}/api/app/${bo_id}/fields`, {
|
|
412
|
+
method: "GET",
|
|
413
|
+
headers: defaultHeaders,
|
|
414
|
+
});
|
|
415
|
+
|
|
416
|
+
if (!response.ok) {
|
|
417
|
+
throw new Error(
|
|
418
|
+
`Failed to get fields for ${bo_id}: ${response.statusText}`
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
return response.json();
|
|
423
|
+
},
|
|
424
|
+
|
|
425
|
+
async fetchField(
|
|
426
|
+
instanceId: string,
|
|
427
|
+
fieldId: string
|
|
428
|
+
): Promise<FetchFieldOption[]> {
|
|
429
|
+
const response = await fetch(
|
|
430
|
+
`${baseUrl}/api/app/${bo_id}/${instanceId}/field/${fieldId}/fetch`,
|
|
431
|
+
{
|
|
432
|
+
method: "GET",
|
|
433
|
+
headers: defaultHeaders,
|
|
434
|
+
}
|
|
435
|
+
);
|
|
436
|
+
|
|
437
|
+
if (!response.ok) {
|
|
438
|
+
throw new Error(
|
|
439
|
+
`Failed to fetch field ${fieldId} for ${bo_id}: ${response.statusText}`
|
|
440
|
+
);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
const responseData: FetchFieldResponse = await response.json();
|
|
444
|
+
return responseData.Data;
|
|
445
|
+
},
|
|
446
|
+
};
|
|
447
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { DateTimeEncoded, DateEncoded } from '../types/common';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Utility functions for datetime encoding/decoding
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Encode a Date object to API datetime format
|
|
9
|
+
*/
|
|
10
|
+
export function encodeDatetime(date: Date): DateTimeEncoded {
|
|
11
|
+
return { $__dt__: date.getTime() / 1000 };
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Decode API datetime format to Date object
|
|
16
|
+
*/
|
|
17
|
+
export function decodeDatetime(encoded: DateTimeEncoded): Date {
|
|
18
|
+
return new Date(encoded.$__dt__ * 1000);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Encode a Date object to API date format (YYYY-MM-DD)
|
|
23
|
+
*/
|
|
24
|
+
export function encodeDate(date: Date): DateEncoded {
|
|
25
|
+
return { $__d__: date.toISOString().split('T')[0] };
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Decode API date format to Date object
|
|
30
|
+
*/
|
|
31
|
+
export function decodeDate(encoded: DateEncoded): Date {
|
|
32
|
+
return new Date(encoded.$__d__);
|
|
33
|
+
}
|
package/sdk/api/index.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// Main API client
|
|
2
|
+
export {
|
|
3
|
+
api,
|
|
4
|
+
setApiBaseUrl,
|
|
5
|
+
setDefaultHeaders,
|
|
6
|
+
getDefaultHeaders,
|
|
7
|
+
getApiBaseUrl,
|
|
8
|
+
} from "./client";
|
|
9
|
+
export type { ResourceClient } from "./client";
|
|
10
|
+
|
|
11
|
+
// DateTime utilities
|
|
12
|
+
export {
|
|
13
|
+
encodeDatetime,
|
|
14
|
+
decodeDatetime,
|
|
15
|
+
encodeDate,
|
|
16
|
+
decodeDate,
|
|
17
|
+
} from "./datetime";
|
|
18
|
+
|
|
19
|
+
// Metadata API client
|
|
20
|
+
export { getBdoSchema, listMetadata } from "./metadata";
|
|
21
|
+
export type { BackendSchema, MetadataItem, FieldMetadata } from "./metadata";
|
|
22
|
+
|
|
23
|
+
// Re-export common types for convenience
|
|
24
|
+
export type {
|
|
25
|
+
// Sort types
|
|
26
|
+
SortDirection,
|
|
27
|
+
SortOption,
|
|
28
|
+
Sort,
|
|
29
|
+
// Filter types
|
|
30
|
+
Filter,
|
|
31
|
+
FilterCondition,
|
|
32
|
+
FilterOperator,
|
|
33
|
+
FilterRHSType,
|
|
34
|
+
LogicalOperator,
|
|
35
|
+
FilterLogical,
|
|
36
|
+
FilterNode,
|
|
37
|
+
// List types
|
|
38
|
+
ListOptions,
|
|
39
|
+
ListResponse,
|
|
40
|
+
ReadResponse,
|
|
41
|
+
CreateUpdateResponse,
|
|
42
|
+
DeleteResponse,
|
|
43
|
+
CountResponse,
|
|
44
|
+
// DateTime types
|
|
45
|
+
DateTimeEncoded,
|
|
46
|
+
DateEncoded,
|
|
47
|
+
// Metric types
|
|
48
|
+
MetricType,
|
|
49
|
+
MetricField,
|
|
50
|
+
MetricOptions,
|
|
51
|
+
MetricResponse,
|
|
52
|
+
// Pivot types
|
|
53
|
+
PivotHeaderItem,
|
|
54
|
+
PivotResponseData,
|
|
55
|
+
PivotOptions,
|
|
56
|
+
PivotResponse,
|
|
57
|
+
// Draft types
|
|
58
|
+
DraftResponse,
|
|
59
|
+
// Fields types
|
|
60
|
+
FieldsResponse,
|
|
61
|
+
} from "../types/common";
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// METADATA API CLIENT
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Handles metadata/schema fetching operations for Business Objects
|
|
5
|
+
|
|
6
|
+
import type { ListOptions, ListResponse } from "../types/common";
|
|
7
|
+
import { getApiBaseUrl, getDefaultHeaders } from "./client";
|
|
8
|
+
|
|
9
|
+
// ============================================================
|
|
10
|
+
// METADATA API OPERATIONS
|
|
11
|
+
// ============================================================
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* BDO Schema Structure (Business Object Metadata)
|
|
15
|
+
*/
|
|
16
|
+
export interface BackendSchema {
|
|
17
|
+
[fieldName: string]: any;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get BDO schema/metadata by ID
|
|
22
|
+
*
|
|
23
|
+
* Endpoint: GET //api/app/meta/bdo/${metaId}
|
|
24
|
+
*
|
|
25
|
+
* @param metaId - The Business Object metadata ID (e.g., "Product", "Order")
|
|
26
|
+
* @returns Promise resolving to the BDO schema
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```typescript
|
|
30
|
+
* const schema = await getBdoSchema("Product");
|
|
31
|
+
* console.log(schema.Fields); // Access field definitions
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export async function getBdoSchema(metaId: string): Promise<BackendSchema> {
|
|
35
|
+
try {
|
|
36
|
+
const baseUrl = getApiBaseUrl();
|
|
37
|
+
const headers = getDefaultHeaders();
|
|
38
|
+
|
|
39
|
+
const response = await fetch(`${baseUrl}/api/app/meta/bdo/${metaId}`, {
|
|
40
|
+
method: "GET",
|
|
41
|
+
headers,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
if (!response.ok) {
|
|
45
|
+
throw new Error(
|
|
46
|
+
`Failed to fetch schema for ${metaId}: ${response.statusText}`
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const bdoSchema = await response.json();
|
|
51
|
+
|
|
52
|
+
// Validate that response is a valid BDO schema object
|
|
53
|
+
if (!bdoSchema || typeof bdoSchema !== "object") {
|
|
54
|
+
throw new Error(`Invalid BDO schema response for ${metaId}`);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return bdoSchema as BackendSchema;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
console.error(`Schema fetch error for ${metaId}:`, error);
|
|
60
|
+
throw new Error(
|
|
61
|
+
`Failed to load BDO schema: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Metadata item structure
|
|
68
|
+
*/
|
|
69
|
+
export interface MetadataItem {
|
|
70
|
+
_id: string;
|
|
71
|
+
Name: string;
|
|
72
|
+
Kind: string;
|
|
73
|
+
Description?: string;
|
|
74
|
+
[key: string]: any;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* List all metadata items with optional filtering and pagination
|
|
79
|
+
*
|
|
80
|
+
* Endpoint: GET or POST /api/app/metadata/list
|
|
81
|
+
*
|
|
82
|
+
* @param options - Optional list options (filters, sorting, pagination)
|
|
83
|
+
* @returns Promise resolving to list of metadata items
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```typescript
|
|
87
|
+
* // List all metadata
|
|
88
|
+
* const all = await listMetadata();
|
|
89
|
+
*
|
|
90
|
+
* // List with filters
|
|
91
|
+
* const businessObjects = await listMetadata({
|
|
92
|
+
* Filter: {
|
|
93
|
+
* Operator: "AND",
|
|
94
|
+
* Condition: [{ LhsField: "Kind", Operator: "eq", RhsValue: "BusinessObject" }]
|
|
95
|
+
* }
|
|
96
|
+
* });
|
|
97
|
+
* ```
|
|
98
|
+
*/
|
|
99
|
+
export async function listMetadata(
|
|
100
|
+
options?: ListOptions
|
|
101
|
+
): Promise<ListResponse<MetadataItem>> {
|
|
102
|
+
try {
|
|
103
|
+
const baseUrl = getApiBaseUrl();
|
|
104
|
+
const headers = getDefaultHeaders();
|
|
105
|
+
|
|
106
|
+
// Use GET for simple requests, POST for complex filters
|
|
107
|
+
const method = options?.Filter || options?.Sort ? "POST" : "GET";
|
|
108
|
+
|
|
109
|
+
const response = await fetch(`${baseUrl}/api/app/metadata/list`, {
|
|
110
|
+
method,
|
|
111
|
+
headers,
|
|
112
|
+
...(method === "POST" &&
|
|
113
|
+
options && {
|
|
114
|
+
body: JSON.stringify(options),
|
|
115
|
+
}),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
if (!response.ok) {
|
|
119
|
+
throw new Error(`Failed to list metadata: ${response.statusText}`);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const result = await response.json();
|
|
123
|
+
|
|
124
|
+
return result as ListResponse<MetadataItem>;
|
|
125
|
+
} catch (error) {
|
|
126
|
+
console.error("Metadata list error:", error);
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Failed to list metadata: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Field metadata structure
|
|
135
|
+
*/
|
|
136
|
+
export interface FieldMetadata {
|
|
137
|
+
Id: string;
|
|
138
|
+
Name: string;
|
|
139
|
+
Type: string;
|
|
140
|
+
Required?: boolean;
|
|
141
|
+
Unique?: boolean;
|
|
142
|
+
Computed?: boolean;
|
|
143
|
+
Values?: {
|
|
144
|
+
Mode: "Static" | "Dynamic";
|
|
145
|
+
Items?: Array<{ Value: string; Label: string }>;
|
|
146
|
+
};
|
|
147
|
+
[key: string]: any;
|
|
148
|
+
}
|