@ram_28/kf-ai-sdk 2.0.1 → 2.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +36 -39
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/metadata.d.ts +26 -22
- package/dist/api/metadata.d.ts.map +1 -1
- package/dist/api.cjs +1 -1
- package/dist/api.mjs +3 -3
- package/dist/auth.cjs +1 -1
- package/dist/auth.mjs +2 -2
- package/dist/base-types.d.ts +1 -1
- package/dist/base-types.d.ts.map +1 -1
- package/dist/bdo/core/BaseBdo.d.ts +8 -20
- package/dist/bdo/core/BaseBdo.d.ts.map +1 -1
- package/dist/bdo/core/Item.d.ts +8 -44
- package/dist/bdo/core/Item.d.ts.map +1 -1
- package/dist/bdo/core/types.d.ts +124 -41
- package/dist/bdo/core/types.d.ts.map +1 -1
- package/dist/bdo/fields/ArrayField.d.ts +5 -4
- package/dist/bdo/fields/ArrayField.d.ts.map +1 -1
- package/dist/bdo/fields/BaseField.d.ts +14 -19
- package/dist/bdo/fields/BaseField.d.ts.map +1 -1
- package/dist/bdo/fields/BooleanField.d.ts +3 -4
- package/dist/bdo/fields/BooleanField.d.ts.map +1 -1
- package/dist/bdo/fields/DateField.d.ts +3 -4
- package/dist/bdo/fields/DateField.d.ts.map +1 -1
- package/dist/bdo/fields/DateTimeField.d.ts +5 -4
- package/dist/bdo/fields/DateTimeField.d.ts.map +1 -1
- package/dist/bdo/fields/FileField.d.ts +18 -0
- package/dist/bdo/fields/FileField.d.ts.map +1 -0
- package/dist/bdo/fields/NumberField.d.ts +6 -4
- package/dist/bdo/fields/NumberField.d.ts.map +1 -1
- package/dist/bdo/fields/ObjectField.d.ts +5 -4
- package/dist/bdo/fields/ObjectField.d.ts.map +1 -1
- package/dist/bdo/fields/ReferenceField.d.ts +13 -14
- package/dist/bdo/fields/ReferenceField.d.ts.map +1 -1
- package/dist/bdo/fields/SelectField.d.ts +9 -16
- package/dist/bdo/fields/SelectField.d.ts.map +1 -1
- package/dist/bdo/fields/StringField.d.ts +6 -4
- package/dist/bdo/fields/StringField.d.ts.map +1 -1
- package/dist/bdo/fields/TextAreaField.d.ts +1 -18
- package/dist/bdo/fields/TextAreaField.d.ts.map +1 -1
- package/dist/bdo/fields/TextField.d.ts +22 -0
- package/dist/bdo/fields/TextField.d.ts.map +1 -0
- package/dist/bdo/fields/UserField.d.ts +20 -0
- package/dist/bdo/fields/UserField.d.ts.map +1 -0
- package/dist/bdo/fields/index.d.ts +5 -2
- package/dist/bdo/fields/index.d.ts.map +1 -1
- package/dist/bdo/index.d.ts +2 -2
- package/dist/bdo/index.d.ts.map +1 -1
- package/dist/bdo.cjs +1 -1
- package/dist/bdo.d.ts +1 -5
- package/dist/bdo.d.ts.map +1 -1
- package/dist/bdo.mjs +312 -242
- package/dist/bdo.types.d.ts +2 -3
- package/dist/bdo.types.d.ts.map +1 -1
- package/dist/client-Bo-RLKJi.cjs +1 -0
- package/dist/client-eA4VvNTo.js +178 -0
- package/dist/components/hooks/useFilter/useFilter.d.ts.map +1 -1
- package/dist/components/hooks/useForm/createItemProxy.d.ts.map +1 -1
- package/dist/components/hooks/useForm/createResolver.d.ts +12 -2
- package/dist/components/hooks/useForm/createResolver.d.ts.map +1 -1
- package/dist/components/hooks/useForm/index.d.ts +1 -1
- package/dist/components/hooks/useForm/index.d.ts.map +1 -1
- package/dist/components/hooks/useForm/types.d.ts +62 -6
- package/dist/components/hooks/useForm/types.d.ts.map +1 -1
- package/dist/components/hooks/useForm/useForm.d.ts +1 -27
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
- package/dist/components/hooks/useTable/useTable.d.ts.map +1 -1
- package/dist/{constants-DaX7GLgl.js → constants-CM9xOACN.js} +37 -13
- package/dist/constants-D0J69if5.cjs +1 -0
- package/dist/filter.cjs +1 -1
- package/dist/filter.mjs +2 -2
- package/dist/form.cjs +1 -1
- package/dist/form.d.ts +1 -1
- package/dist/form.d.ts.map +1 -1
- package/dist/form.mjs +879 -809
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/{metadata-Bz8zJqC1.cjs → metadata-BN57S6W9.cjs} +1 -1
- package/dist/{metadata-VbQzyD2C.js → metadata-P7DGCgIG.js} +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +74 -70
- package/dist/types/base-fields.d.ts +24 -59
- package/dist/types/base-fields.d.ts.map +1 -1
- package/dist/useFilter-Bg0jvIL6.cjs +1 -0
- package/dist/useFilter-DPNLKY3H.js +118 -0
- package/dist/utils/formatting.d.ts +10 -1
- package/dist/utils/formatting.d.ts.map +1 -1
- package/docs/api.md +140 -572
- package/docs/bdo.md +742 -0
- package/docs/useAuth.md +10 -4
- package/docs/useFilter.md +40 -40
- package/docs/useForm.md +91 -62
- package/docs/useTable.md +38 -38
- package/package.json +1 -1
- package/sdk/api/client.ts +52 -65
- package/sdk/api/metadata.ts +22 -20
- package/sdk/base-types.ts +5 -9
- package/sdk/bdo/core/BaseBdo.ts +13 -38
- package/sdk/bdo/core/Item.ts +34 -56
- package/sdk/bdo/core/types.ts +147 -45
- package/sdk/bdo/fields/ArrayField.ts +9 -5
- package/sdk/bdo/fields/BaseField.ts +19 -29
- package/sdk/bdo/fields/BooleanField.ts +4 -5
- package/sdk/bdo/fields/DateField.ts +4 -5
- package/sdk/bdo/fields/DateTimeField.ts +9 -5
- package/sdk/bdo/fields/FileField.ts +39 -0
- package/sdk/bdo/fields/NumberField.ts +8 -5
- package/sdk/bdo/fields/ObjectField.ts +9 -5
- package/sdk/bdo/fields/ReferenceField.ts +22 -28
- package/sdk/bdo/fields/SelectField.ts +13 -26
- package/sdk/bdo/fields/StringField.ts +10 -5
- package/sdk/bdo/fields/TextAreaField.ts +3 -32
- package/sdk/bdo/fields/TextField.ts +42 -0
- package/sdk/bdo/fields/UserField.ts +52 -0
- package/sdk/bdo/fields/index.ts +5 -2
- package/sdk/bdo/index.ts +19 -4
- package/sdk/bdo.ts +4 -31
- package/sdk/bdo.types.ts +26 -21
- package/sdk/components/hooks/useFilter/useFilter.ts +13 -30
- package/sdk/components/hooks/useForm/createItemProxy.ts +47 -11
- package/sdk/components/hooks/useForm/createResolver.ts +65 -6
- package/sdk/components/hooks/useForm/index.ts +3 -0
- package/sdk/components/hooks/useForm/types.ts +75 -6
- package/sdk/components/hooks/useForm/useForm.ts +35 -50
- package/sdk/components/hooks/useTable/useTable.ts +10 -2
- package/sdk/form.ts +1 -12
- package/sdk/index.ts +3 -3
- package/sdk/types/base-fields.ts +28 -72
- package/sdk/utils/formatting.ts +13 -1
- package/dist/client-BIkaIr2y.js +0 -217
- package/dist/client-DxjRcEtN.cjs +0 -1
- package/dist/constants-C49b9Exc.cjs +0 -1
- package/dist/useFilter-DzpP_ag0.cjs +0 -1
- package/dist/useFilter-H5bgAZQF.js +0 -120
package/sdk/api/client.ts
CHANGED
|
@@ -161,24 +161,31 @@ export function getApiBaseUrl(): string {
|
|
|
161
161
|
return apiConfig.baseUrl || "";
|
|
162
162
|
}
|
|
163
163
|
|
|
164
|
+
/**
|
|
165
|
+
* Parse error response body and throw an Error with the server's message.
|
|
166
|
+
*/
|
|
167
|
+
async function throwApiError(response: Response, context: string): Promise<never> {
|
|
168
|
+
let errorBody: any;
|
|
169
|
+
try { errorBody = await response.json(); } catch {}
|
|
170
|
+
const message = errorBody?.error || errorBody?.message || response.statusText;
|
|
171
|
+
throw new Error(`${context}: ${message}`);
|
|
172
|
+
}
|
|
173
|
+
|
|
164
174
|
/**
|
|
165
175
|
* Create a resource client for the specified Business Object
|
|
166
176
|
* @param bo_id - Business Object identifier (e.g., "user", "leave", "vendor")
|
|
167
177
|
* @returns Resource client with CRUD operations matching API spec
|
|
168
178
|
*/
|
|
169
179
|
export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
170
|
-
const baseUrl = apiConfig.baseUrl;
|
|
171
|
-
const defaultHeaders = apiConfig.headers;
|
|
172
|
-
|
|
173
180
|
return {
|
|
174
181
|
async get(id: string): Promise<T> {
|
|
175
|
-
const response = await fetch(`${
|
|
182
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/${id}/read`, {
|
|
176
183
|
method: "GET",
|
|
177
|
-
headers:
|
|
184
|
+
headers: getDefaultHeaders(),
|
|
178
185
|
});
|
|
179
186
|
|
|
180
187
|
if (!response.ok) {
|
|
181
|
-
|
|
188
|
+
await throwApiError(response, `Failed to get ${bo_id} ${id}`);
|
|
182
189
|
}
|
|
183
190
|
|
|
184
191
|
const responseData: ReadResponseType<T> = await response.json();
|
|
@@ -188,45 +195,41 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
188
195
|
async create(
|
|
189
196
|
data: Partial<T> & { _id?: string }
|
|
190
197
|
): Promise<CreateUpdateResponseType> {
|
|
191
|
-
const response = await fetch(`${
|
|
198
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/create`, {
|
|
192
199
|
method: "POST",
|
|
193
|
-
headers:
|
|
200
|
+
headers: getDefaultHeaders(),
|
|
194
201
|
body: JSON.stringify(data),
|
|
195
202
|
});
|
|
196
203
|
|
|
197
204
|
if (!response.ok) {
|
|
198
|
-
|
|
205
|
+
await throwApiError(response, `Failed to create ${bo_id}`);
|
|
199
206
|
}
|
|
200
207
|
|
|
201
208
|
return response.json();
|
|
202
209
|
},
|
|
203
210
|
|
|
204
211
|
async update(id: string, data: Partial<T>): Promise<CreateUpdateResponseType> {
|
|
205
|
-
const response = await fetch(`${
|
|
212
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/${id}/update`, {
|
|
206
213
|
method: "POST",
|
|
207
|
-
headers:
|
|
214
|
+
headers: getDefaultHeaders(),
|
|
208
215
|
body: JSON.stringify(data),
|
|
209
216
|
});
|
|
210
217
|
|
|
211
218
|
if (!response.ok) {
|
|
212
|
-
|
|
213
|
-
`Failed to update ${bo_id} ${id}: ${response.statusText}`
|
|
214
|
-
);
|
|
219
|
+
await throwApiError(response, `Failed to update ${bo_id} ${id}`);
|
|
215
220
|
}
|
|
216
221
|
|
|
217
222
|
return response.json();
|
|
218
223
|
},
|
|
219
224
|
|
|
220
225
|
async delete(id: string): Promise<DeleteResponseType> {
|
|
221
|
-
const response = await fetch(`${
|
|
226
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/${id}/delete`, {
|
|
222
227
|
method: "DELETE",
|
|
223
|
-
headers:
|
|
228
|
+
headers: getDefaultHeaders(),
|
|
224
229
|
});
|
|
225
230
|
|
|
226
231
|
if (!response.ok) {
|
|
227
|
-
|
|
228
|
-
`Failed to delete ${bo_id} ${id}: ${response.statusText}`
|
|
229
|
-
);
|
|
232
|
+
await throwApiError(response, `Failed to delete ${bo_id} ${id}`);
|
|
230
233
|
}
|
|
231
234
|
|
|
232
235
|
return response.json();
|
|
@@ -238,14 +241,14 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
238
241
|
...options,
|
|
239
242
|
};
|
|
240
243
|
|
|
241
|
-
const response = await fetch(`${
|
|
244
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/list`, {
|
|
242
245
|
method: "POST",
|
|
243
|
-
headers:
|
|
246
|
+
headers: getDefaultHeaders(),
|
|
244
247
|
body: JSON.stringify(requestBody),
|
|
245
248
|
});
|
|
246
249
|
|
|
247
250
|
if (!response.ok) {
|
|
248
|
-
|
|
251
|
+
await throwApiError(response, `Failed to list ${bo_id}`);
|
|
249
252
|
}
|
|
250
253
|
|
|
251
254
|
const responseData: ListResponseType<T> = await response.json();
|
|
@@ -261,14 +264,14 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
261
264
|
...(options?.Filter && { Filter: options.Filter }),
|
|
262
265
|
};
|
|
263
266
|
|
|
264
|
-
const response = await fetch(`${
|
|
267
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/metric`, {
|
|
265
268
|
method: "POST",
|
|
266
|
-
headers:
|
|
269
|
+
headers: getDefaultHeaders(),
|
|
267
270
|
body: JSON.stringify(requestBody),
|
|
268
271
|
});
|
|
269
272
|
|
|
270
273
|
if (!response.ok) {
|
|
271
|
-
|
|
274
|
+
await throwApiError(response, `Failed to count ${bo_id}`);
|
|
272
275
|
}
|
|
273
276
|
|
|
274
277
|
const result = await response.json();
|
|
@@ -282,16 +285,14 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
282
285
|
// ============================================================
|
|
283
286
|
|
|
284
287
|
async draft(data: Partial<T>): Promise<DraftResponseType> {
|
|
285
|
-
const response = await fetch(`${
|
|
288
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/draft`, {
|
|
286
289
|
method: "POST",
|
|
287
|
-
headers:
|
|
290
|
+
headers: getDefaultHeaders(),
|
|
288
291
|
body: JSON.stringify(data),
|
|
289
292
|
});
|
|
290
293
|
|
|
291
294
|
if (!response.ok) {
|
|
292
|
-
|
|
293
|
-
`Failed to create draft for ${bo_id}: ${response.statusText}`
|
|
294
|
-
);
|
|
295
|
+
await throwApiError(response, `Failed to create draft for ${bo_id}`);
|
|
295
296
|
}
|
|
296
297
|
|
|
297
298
|
return response.json();
|
|
@@ -301,32 +302,28 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
301
302
|
id: string,
|
|
302
303
|
data: Partial<T>
|
|
303
304
|
): Promise<CreateUpdateResponseType> {
|
|
304
|
-
const response = await fetch(`${
|
|
305
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/${id}/draft`, {
|
|
305
306
|
method: "POST",
|
|
306
|
-
headers:
|
|
307
|
+
headers: getDefaultHeaders(),
|
|
307
308
|
body: JSON.stringify(data),
|
|
308
309
|
});
|
|
309
310
|
|
|
310
311
|
if (!response.ok) {
|
|
311
|
-
|
|
312
|
-
`Failed to update draft for ${bo_id} ${id}: ${response.statusText}`
|
|
313
|
-
);
|
|
312
|
+
await throwApiError(response, `Failed to update draft for ${bo_id} ${id}`);
|
|
314
313
|
}
|
|
315
314
|
|
|
316
315
|
return response.json();
|
|
317
316
|
},
|
|
318
317
|
|
|
319
318
|
async draftPatch(id: string, data: Partial<T>): Promise<DraftResponseType> {
|
|
320
|
-
const response = await fetch(`${
|
|
319
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/${id}/draft`, {
|
|
321
320
|
method: "PATCH",
|
|
322
|
-
headers:
|
|
321
|
+
headers: getDefaultHeaders(),
|
|
323
322
|
body: JSON.stringify(data),
|
|
324
323
|
});
|
|
325
324
|
|
|
326
325
|
if (!response.ok) {
|
|
327
|
-
|
|
328
|
-
`Failed to patch draft for ${bo_id} ${id}: ${response.statusText}`
|
|
329
|
-
);
|
|
326
|
+
await throwApiError(response, `Failed to patch draft for ${bo_id} ${id}`);
|
|
330
327
|
}
|
|
331
328
|
|
|
332
329
|
return response.json();
|
|
@@ -335,16 +332,14 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
335
332
|
async draftInteraction(
|
|
336
333
|
data: Partial<T> & { _id?: string }
|
|
337
334
|
): Promise<DraftResponseType & { _id: string }> {
|
|
338
|
-
const response = await fetch(`${
|
|
335
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/draft`, {
|
|
339
336
|
method: "PATCH",
|
|
340
|
-
headers:
|
|
337
|
+
headers: getDefaultHeaders(),
|
|
341
338
|
body: JSON.stringify(data),
|
|
342
339
|
});
|
|
343
340
|
|
|
344
341
|
if (!response.ok) {
|
|
345
|
-
|
|
346
|
-
`Failed to create interactive draft for ${bo_id}: ${response.statusText}`
|
|
347
|
-
);
|
|
342
|
+
await throwApiError(response, `Failed to create interactive draft for ${bo_id}`);
|
|
348
343
|
}
|
|
349
344
|
|
|
350
345
|
const json = await response.json();
|
|
@@ -368,16 +363,14 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
368
363
|
...options,
|
|
369
364
|
};
|
|
370
365
|
|
|
371
|
-
const response = await fetch(`${
|
|
366
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/metric`, {
|
|
372
367
|
method: "POST",
|
|
373
|
-
headers:
|
|
368
|
+
headers: getDefaultHeaders(),
|
|
374
369
|
body: JSON.stringify(requestBody),
|
|
375
370
|
});
|
|
376
371
|
|
|
377
372
|
if (!response.ok) {
|
|
378
|
-
|
|
379
|
-
`Failed to get metrics for ${bo_id}: ${response.statusText}`
|
|
380
|
-
);
|
|
373
|
+
await throwApiError(response, `Failed to get metrics for ${bo_id}`);
|
|
381
374
|
}
|
|
382
375
|
|
|
383
376
|
return response.json();
|
|
@@ -389,16 +382,14 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
389
382
|
...options,
|
|
390
383
|
};
|
|
391
384
|
|
|
392
|
-
const response = await fetch(`${
|
|
385
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/pivot`, {
|
|
393
386
|
method: "POST",
|
|
394
|
-
headers:
|
|
387
|
+
headers: getDefaultHeaders(),
|
|
395
388
|
body: JSON.stringify(requestBody),
|
|
396
389
|
});
|
|
397
390
|
|
|
398
391
|
if (!response.ok) {
|
|
399
|
-
|
|
400
|
-
`Failed to get pivot data for ${bo_id}: ${response.statusText}`
|
|
401
|
-
);
|
|
392
|
+
await throwApiError(response, `Failed to get pivot data for ${bo_id}`);
|
|
402
393
|
}
|
|
403
394
|
|
|
404
395
|
return response.json();
|
|
@@ -409,15 +400,13 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
409
400
|
// ============================================================
|
|
410
401
|
|
|
411
402
|
async fields(): Promise<FieldsResponseType> {
|
|
412
|
-
const response = await fetch(`${
|
|
403
|
+
const response = await fetch(`${getApiBaseUrl()}/api/app/${bo_id}/fields`, {
|
|
413
404
|
method: "GET",
|
|
414
|
-
headers:
|
|
405
|
+
headers: getDefaultHeaders(),
|
|
415
406
|
});
|
|
416
407
|
|
|
417
408
|
if (!response.ok) {
|
|
418
|
-
|
|
419
|
-
`Failed to get fields for ${bo_id}: ${response.statusText}`
|
|
420
|
-
);
|
|
409
|
+
await throwApiError(response, `Failed to get fields for ${bo_id}`);
|
|
421
410
|
}
|
|
422
411
|
|
|
423
412
|
return response.json();
|
|
@@ -428,17 +417,15 @@ export function api<T = any>(bo_id: string): ResourceClientType<T> {
|
|
|
428
417
|
fieldId: string
|
|
429
418
|
): Promise<TResult[]> {
|
|
430
419
|
const response = await fetch(
|
|
431
|
-
`${
|
|
420
|
+
`${getApiBaseUrl()}/api/app/${bo_id}/${instanceId}/field/${fieldId}/fetch`,
|
|
432
421
|
{
|
|
433
422
|
method: "GET",
|
|
434
|
-
headers:
|
|
423
|
+
headers: getDefaultHeaders(),
|
|
435
424
|
}
|
|
436
425
|
);
|
|
437
426
|
|
|
438
427
|
if (!response.ok) {
|
|
439
|
-
|
|
440
|
-
`Failed to fetch field ${fieldId} for ${bo_id}: ${response.statusText}`
|
|
441
|
-
);
|
|
428
|
+
await throwApiError(response, `Failed to fetch field ${fieldId} for ${bo_id}`);
|
|
442
429
|
}
|
|
443
430
|
|
|
444
431
|
const responseData: { Data: TResult[] } = await response.json();
|
package/sdk/api/metadata.ts
CHANGED
|
@@ -81,20 +81,6 @@ export interface MetadataItemType {
|
|
|
81
81
|
*
|
|
82
82
|
* @param options - Optional list options (filters, sorting, pagination)
|
|
83
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
84
|
*/
|
|
99
85
|
export async function listMetadata(
|
|
100
86
|
options?: ListOptionsType
|
|
@@ -131,18 +117,34 @@ export async function listMetadata(
|
|
|
131
117
|
}
|
|
132
118
|
|
|
133
119
|
/**
|
|
134
|
-
* Field metadata structure
|
|
120
|
+
* Field metadata structure — matches new Constraint/View/Property backend shape
|
|
135
121
|
*/
|
|
136
122
|
export interface FieldMetadataType {
|
|
137
123
|
Id: string;
|
|
138
124
|
Name: string;
|
|
139
125
|
Type: string;
|
|
126
|
+
ReadOnly?: boolean;
|
|
140
127
|
Required?: boolean;
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
128
|
+
Constraint?: {
|
|
129
|
+
Required?: boolean;
|
|
130
|
+
Enum?: string[];
|
|
131
|
+
Length?: number;
|
|
132
|
+
IntegerPart?: number;
|
|
133
|
+
FractionPart?: number;
|
|
134
|
+
PrimaryKey?: boolean;
|
|
135
|
+
DefaultValue?: unknown;
|
|
136
|
+
Precision?: "Second" | "Millisecond";
|
|
137
|
+
Format?: "Plain" | "Markdown";
|
|
138
|
+
};
|
|
139
|
+
View?: {
|
|
140
|
+
DataObject?: { Type: string; Id: string };
|
|
141
|
+
Fields?: Record<string, { Type: string }>;
|
|
142
|
+
Search?: string[];
|
|
143
|
+
Filter?: Record<string, unknown>;
|
|
144
|
+
Sort?: unknown[];
|
|
145
|
+
BusinessEntity?: string;
|
|
146
146
|
};
|
|
147
|
+
Property?: FieldMetadataType | Record<string, FieldMetadataType>;
|
|
148
|
+
DefaultValue?: unknown;
|
|
147
149
|
[key: string]: any;
|
|
148
150
|
}
|
package/sdk/base-types.ts
CHANGED
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
export type {
|
|
7
7
|
// String fields
|
|
8
8
|
StringFieldType,
|
|
9
|
+
TextFieldType,
|
|
9
10
|
TextAreaFieldType,
|
|
10
11
|
|
|
11
12
|
// Numeric fields
|
|
12
13
|
NumberFieldType,
|
|
13
|
-
LongFieldType,
|
|
14
14
|
|
|
15
15
|
// Boolean field
|
|
16
16
|
BooleanFieldType,
|
|
@@ -20,21 +20,17 @@ export type {
|
|
|
20
20
|
DateTimeFieldType,
|
|
21
21
|
|
|
22
22
|
// Complex fields
|
|
23
|
-
CurrencyFieldType,
|
|
24
|
-
CurrencyValueType,
|
|
25
|
-
JSONFieldType,
|
|
26
23
|
ReferenceFieldType,
|
|
27
24
|
ExtractReferenceType,
|
|
28
25
|
ExtractFetchFieldType,
|
|
29
26
|
|
|
30
|
-
// JSON types
|
|
31
|
-
JSONValueType,
|
|
32
|
-
JSONObjectType,
|
|
33
|
-
JSONArrayType,
|
|
34
|
-
|
|
35
27
|
// Select fields
|
|
36
28
|
SelectFieldType,
|
|
37
29
|
|
|
30
|
+
// New field types
|
|
31
|
+
UserFieldType,
|
|
32
|
+
FileFieldType,
|
|
33
|
+
|
|
38
34
|
// Container types
|
|
39
35
|
ArrayFieldType,
|
|
40
36
|
ObjectFieldType,
|
package/sdk/bdo/core/BaseBdo.ts
CHANGED
|
@@ -13,22 +13,19 @@ import type {
|
|
|
13
13
|
PivotResponseType,
|
|
14
14
|
DraftResponseType,
|
|
15
15
|
} from "../../types/common";
|
|
16
|
-
import type {
|
|
16
|
+
import type { SystemFields } from "../../types/base-fields";
|
|
17
17
|
import { api } from "../../api/client";
|
|
18
18
|
import { Item, type ItemType } from "./Item";
|
|
19
19
|
import { BaseField } from "../fields/BaseField";
|
|
20
20
|
import { StringField } from "../fields/StringField";
|
|
21
21
|
import { DateTimeField } from "../fields/DateTimeField";
|
|
22
|
-
import {
|
|
22
|
+
import { UserField } from "../fields/UserField";
|
|
23
23
|
import type { ValidationResultType, BdoMetaType } from "./types";
|
|
24
24
|
import { ExpressionEngine, type BDOMetadata } from "../expressions";
|
|
25
25
|
|
|
26
26
|
// Re-export SystemFields type for consumers
|
|
27
27
|
export type { SystemFields } from "../../types/base-fields";
|
|
28
28
|
|
|
29
|
-
// System BDO ID for user references
|
|
30
|
-
const USER_BO_ID = "SYS_User";
|
|
31
|
-
|
|
32
29
|
/**
|
|
33
30
|
* Abstract base class for Business Data Objects
|
|
34
31
|
*
|
|
@@ -38,18 +35,6 @@ const USER_BO_ID = "SYS_User";
|
|
|
38
35
|
* @template TEntity - The full entity type with all fields
|
|
39
36
|
* @template TEditable - Fields that this role can create/update (defaults to TEntity without system fields)
|
|
40
37
|
* @template TReadonly - Fields that this role can only read (defaults to empty)
|
|
41
|
-
*
|
|
42
|
-
* @example
|
|
43
|
-
* ```typescript
|
|
44
|
-
* class AdminProduct extends BaseBdo<ProductType> {
|
|
45
|
-
* readonly meta = { _id: "BDO_Product", name: "Product" };
|
|
46
|
-
*
|
|
47
|
-
* // Re-expose only methods this role can use
|
|
48
|
-
* public async get(id: StringFieldType) { return super.get(id); }
|
|
49
|
-
* public async list(options?: ListOptionsType) { return super.list(options); }
|
|
50
|
-
* // create, update, delete NOT exposed - TypeScript error if called
|
|
51
|
-
* }
|
|
52
|
-
* ```
|
|
53
38
|
*/
|
|
54
39
|
export abstract class BaseBdo<
|
|
55
40
|
TEntity extends Record<string, unknown>,
|
|
@@ -65,23 +50,13 @@ export abstract class BaseBdo<
|
|
|
65
50
|
// SYSTEM FIELDS (inherited by all BDOs)
|
|
66
51
|
// ============================================================
|
|
67
52
|
|
|
68
|
-
readonly _id = new StringField({
|
|
69
|
-
readonly _created_at = new DateTimeField({
|
|
70
|
-
readonly _modified_at = new DateTimeField({
|
|
71
|
-
readonly _created_by = new
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
referenceFields: ["_id", "username"],
|
|
76
|
-
});
|
|
77
|
-
readonly _modified_by = new ReferenceField<UserRefType>({
|
|
78
|
-
id: "_modified_by",
|
|
79
|
-
label: "Modified By",
|
|
80
|
-
referenceBdo: USER_BO_ID,
|
|
81
|
-
referenceFields: ["_id", "username"],
|
|
82
|
-
});
|
|
83
|
-
readonly _version = new StringField({ id: "_version", label: "Version" });
|
|
84
|
-
readonly _m_version = new StringField({ id: "_m_version", label: "Metadata Version" });
|
|
53
|
+
readonly _id = new StringField({ _id: "_id", Name: "ID", Type: "String", ReadOnly: true });
|
|
54
|
+
readonly _created_at = new DateTimeField({ _id: "_created_at", Name: "Created At", Type: "DateTime", ReadOnly: true });
|
|
55
|
+
readonly _modified_at = new DateTimeField({ _id: "_modified_at", Name: "Modified At", Type: "DateTime", ReadOnly: true });
|
|
56
|
+
readonly _created_by = new UserField({ _id: "_created_by", Name: "Created By", Type: "User", ReadOnly: true });
|
|
57
|
+
readonly _modified_by = new UserField({ _id: "_modified_by", Name: "Modified By", Type: "User", ReadOnly: true });
|
|
58
|
+
readonly _version = new StringField({ _id: "_version", Name: "Version", Type: "String", ReadOnly: true });
|
|
59
|
+
readonly _m_version = new StringField({ _id: "_m_version", Name: "Metadata Version", Type: "String", ReadOnly: true });
|
|
85
60
|
|
|
86
61
|
// ============================================================
|
|
87
62
|
// FIELD DEFINITIONS (auto-discovered)
|
|
@@ -190,7 +165,7 @@ export abstract class BaseBdo<
|
|
|
190
165
|
/**
|
|
191
166
|
* Get a single record by ID
|
|
192
167
|
*/
|
|
193
|
-
protected async get(id:
|
|
168
|
+
protected async get(id: string): Promise<ItemType<TEditable, TReadonly>> {
|
|
194
169
|
const data = await api<TEditable & TReadonly>(this.meta._id).get(id);
|
|
195
170
|
return new Item<TEditable & TReadonly>(this, data as Partial<TEditable & TReadonly>) as ItemType<TEditable, TReadonly>;
|
|
196
171
|
}
|
|
@@ -237,7 +212,7 @@ export abstract class BaseBdo<
|
|
|
237
212
|
* Update an existing record
|
|
238
213
|
*/
|
|
239
214
|
protected async update(
|
|
240
|
-
id:
|
|
215
|
+
id: string,
|
|
241
216
|
data: Partial<TEditable>
|
|
242
217
|
): Promise<CreateUpdateResponseType> {
|
|
243
218
|
return api<TEntity>(this.meta._id).update(id, data as Partial<TEntity>);
|
|
@@ -250,7 +225,7 @@ export abstract class BaseBdo<
|
|
|
250
225
|
/**
|
|
251
226
|
* Delete a record by ID
|
|
252
227
|
*/
|
|
253
|
-
protected async delete(id:
|
|
228
|
+
protected async delete(id: string): Promise<DeleteResponseType> {
|
|
254
229
|
return api<TEntity>(this.meta._id).delete(id);
|
|
255
230
|
}
|
|
256
231
|
|
|
@@ -287,7 +262,7 @@ export abstract class BaseBdo<
|
|
|
287
262
|
* Patch an existing draft - compute fields during editing
|
|
288
263
|
*/
|
|
289
264
|
protected async draftPatch(
|
|
290
|
-
id:
|
|
265
|
+
id: string,
|
|
291
266
|
data: Partial<TEditable>
|
|
292
267
|
): Promise<DraftResponseType> {
|
|
293
268
|
return api<TEntity>(this.meta._id).draftPatch(id, data as Partial<TEntity>);
|
package/sdk/bdo/core/Item.ts
CHANGED
|
@@ -3,7 +3,13 @@
|
|
|
3
3
|
// Wraps a record with field accessors for type-safe manipulation
|
|
4
4
|
// ============================================================
|
|
5
5
|
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
ValidationResultType,
|
|
8
|
+
BaseFieldMetaType,
|
|
9
|
+
EditableFieldAccessorType,
|
|
10
|
+
ReadonlyFieldAccessorType,
|
|
11
|
+
FieldAccessorType,
|
|
12
|
+
} from "./types";
|
|
7
13
|
import type { BaseField } from "../fields/BaseField";
|
|
8
14
|
|
|
9
15
|
/**
|
|
@@ -19,32 +25,8 @@ interface BdoLike {
|
|
|
19
25
|
): ValidationResultType;
|
|
20
26
|
}
|
|
21
27
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
*/
|
|
25
|
-
export interface EditableFieldAccessorType<T> {
|
|
26
|
-
readonly meta: FieldMetaType;
|
|
27
|
-
get(): T | undefined;
|
|
28
|
-
set(value: T): void;
|
|
29
|
-
validate(): ValidationResultType;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
/**
|
|
33
|
-
* Readonly field accessor — has get(), validate(), NO set()
|
|
34
|
-
*/
|
|
35
|
-
export interface ReadonlyFieldAccessorType<T> {
|
|
36
|
-
readonly meta: FieldMetaType;
|
|
37
|
-
get(): T | undefined;
|
|
38
|
-
validate(): ValidationResultType;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
/**
|
|
42
|
-
* Field accessor with get/set/validate methods + meta object (union type)
|
|
43
|
-
*/
|
|
44
|
-
export type FieldAccessorType<T> = EditableFieldAccessorType<T> | ReadonlyFieldAccessorType<T>;
|
|
45
|
-
|
|
46
|
-
// Re-export FieldMetaType for convenience
|
|
47
|
-
export type { FieldMetaType };
|
|
28
|
+
// Re-export accessor types for convenience
|
|
29
|
+
export type { EditableFieldAccessorType, ReadonlyFieldAccessorType, FieldAccessorType, BaseFieldMetaType };
|
|
48
30
|
|
|
49
31
|
/**
|
|
50
32
|
* Create editable accessor type for each field in TEditable
|
|
@@ -78,31 +60,16 @@ export type ItemType<
|
|
|
78
60
|
* Item class that wraps a record with field accessors
|
|
79
61
|
*
|
|
80
62
|
* Each field is accessible as a property returning an accessor with:
|
|
81
|
-
* -
|
|
82
|
-
* -
|
|
63
|
+
* - label: display name
|
|
64
|
+
* - required: whether field is required
|
|
65
|
+
* - readOnly: whether field is read-only
|
|
66
|
+
* - defaultValue: default value
|
|
67
|
+
* - meta: full raw backend meta
|
|
83
68
|
* - get(): get current value
|
|
84
|
-
* - set(value): set value
|
|
69
|
+
* - set(value): set value (editable fields only)
|
|
85
70
|
* - validate(): validate current value
|
|
86
71
|
*
|
|
87
72
|
* @template T - The type of the underlying data
|
|
88
|
-
*
|
|
89
|
-
* @example
|
|
90
|
-
* ```typescript
|
|
91
|
-
* const product = new AdminProduct();
|
|
92
|
-
* const item = await product.get("product_123");
|
|
93
|
-
*
|
|
94
|
-
* // Field accessor access
|
|
95
|
-
* item.Title.get() // get value
|
|
96
|
-
* item.Title.set("New Title") // set value (editable fields only)
|
|
97
|
-
* item.Title.meta.id // "Title"
|
|
98
|
-
* item.Title.meta.label // "Product Title"
|
|
99
|
-
* item.Title.meta.isEditable // true if field is editable
|
|
100
|
-
* item.Title.validate() // validate
|
|
101
|
-
*
|
|
102
|
-
* // Methods
|
|
103
|
-
* const result = item.validate(); // validate all fields
|
|
104
|
-
* const raw = item.toJSON(); // get raw data
|
|
105
|
-
* ```
|
|
106
73
|
*/
|
|
107
74
|
export class Item<T extends Record<string, unknown>> {
|
|
108
75
|
private _data: Partial<T>;
|
|
@@ -201,13 +168,13 @@ export class Item<T extends Record<string, unknown>> {
|
|
|
201
168
|
const fields = this._bdo.getFields();
|
|
202
169
|
const fieldDef = fields[fieldId];
|
|
203
170
|
|
|
204
|
-
//
|
|
205
|
-
const meta:
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
171
|
+
// Get raw meta from field definition
|
|
172
|
+
const meta: BaseFieldMetaType = fieldDef?.meta ?? {
|
|
173
|
+
_id: fieldId,
|
|
174
|
+
Name: fieldId,
|
|
175
|
+
Type: "String",
|
|
209
176
|
};
|
|
210
|
-
const
|
|
177
|
+
const isReadOnly = fieldDef?.readOnly ?? false;
|
|
211
178
|
|
|
212
179
|
// Shared validate function
|
|
213
180
|
const validate = (): ValidationResultType => {
|
|
@@ -231,11 +198,15 @@ export class Item<T extends Record<string, unknown>> {
|
|
|
231
198
|
return { valid: true, errors: [] };
|
|
232
199
|
};
|
|
233
200
|
|
|
234
|
-
// Create accessor — only add set() for
|
|
201
|
+
// Create accessor — only add set() for non-readOnly fields
|
|
235
202
|
let accessor: FieldAccessorType<unknown>;
|
|
236
203
|
|
|
237
|
-
if (
|
|
204
|
+
if (!isReadOnly) {
|
|
238
205
|
accessor = {
|
|
206
|
+
label: fieldDef?.label ?? fieldId,
|
|
207
|
+
required: fieldDef?.required ?? false,
|
|
208
|
+
readOnly: false,
|
|
209
|
+
defaultValue: fieldDef?.defaultValue,
|
|
239
210
|
meta,
|
|
240
211
|
get: () => this._data[fieldId as keyof T],
|
|
241
212
|
set: (value: unknown) => {
|
|
@@ -245,6 +216,10 @@ export class Item<T extends Record<string, unknown>> {
|
|
|
245
216
|
};
|
|
246
217
|
} else {
|
|
247
218
|
accessor = {
|
|
219
|
+
label: fieldDef?.label ?? fieldId,
|
|
220
|
+
required: fieldDef?.required ?? false,
|
|
221
|
+
readOnly: true,
|
|
222
|
+
defaultValue: fieldDef?.defaultValue,
|
|
248
223
|
meta,
|
|
249
224
|
get: () => this._data[fieldId as keyof T],
|
|
250
225
|
validate,
|
|
@@ -265,6 +240,9 @@ export class Item<T extends Record<string, unknown>> {
|
|
|
265
240
|
const allValues = this.toJSON() as Record<string, unknown>;
|
|
266
241
|
|
|
267
242
|
for (const [fieldId, fieldDef] of Object.entries(fields)) {
|
|
243
|
+
// Skip readonly fields — users can't edit them, so validation errors are confusing
|
|
244
|
+
if (fieldDef.readOnly) continue;
|
|
245
|
+
|
|
268
246
|
const value = this._data[fieldId as keyof T];
|
|
269
247
|
|
|
270
248
|
// 1. Type validation
|