@ram_28/kf-ai-sdk 2.0.2 → 2.0.4
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/dist/BaseField-B6da88U7.js +40 -0
- package/dist/BaseField-Drp0-OxL.cjs +1 -0
- package/dist/api/client.d.ts +7 -0
- package/dist/api/client.d.ts.map +1 -1
- package/dist/api/index.d.ts +1 -1
- package/dist/api/index.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/bdo/core/BaseBdo.d.ts +4 -0
- package/dist/bdo/core/BaseBdo.d.ts.map +1 -1
- package/dist/bdo.cjs +1 -1
- package/dist/bdo.mjs +91 -118
- package/dist/client-BULEEaCP.js +222 -0
- package/dist/client-DtPpfJc1.cjs +1 -0
- 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 +15 -2
- package/dist/components/hooks/useForm/types.d.ts.map +1 -1
- package/dist/components/hooks/useForm/useDraftInteraction.d.ts +26 -0
- package/dist/components/hooks/useForm/useDraftInteraction.d.ts.map +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts +1 -0
- package/dist/components/hooks/useForm/useForm.d.ts.map +1 -1
- package/dist/{constants-CM9xOACN.js → constants-BQrBcCON.js} +5 -5
- package/dist/error-handling-CAoD0Kwb.cjs +1 -0
- package/dist/error-handling-CrhTtD88.js +14 -0
- package/dist/filter.mjs +1 -1
- package/dist/form.cjs +1 -1
- package/dist/form.mjs +313 -1187
- package/dist/form.types.d.ts +1 -1
- package/dist/form.types.d.ts.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm-Cj63v5ny.js +1014 -0
- package/dist/index.esm-DuwT11sx.cjs +1 -0
- package/dist/{metadata-BN57S6W9.cjs → metadata-BJWukIqS.cjs} +1 -1
- package/dist/{metadata-P7DGCgIG.js → metadata-CJuFxytC.js} +1 -1
- package/dist/table.cjs +1 -1
- package/dist/table.mjs +83 -93
- package/dist/types/constants.d.ts +2 -2
- package/dist/types/constants.d.ts.map +1 -1
- package/dist/workflow/Activity.d.ts +85 -0
- package/dist/workflow/Activity.d.ts.map +1 -0
- package/dist/workflow/ActivityInstance.d.ts +96 -0
- package/dist/workflow/ActivityInstance.d.ts.map +1 -0
- package/dist/workflow/client.d.ts +39 -0
- package/dist/workflow/client.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts +16 -0
- package/dist/workflow/components/useActivityForm/createActivityItemProxy.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts +22 -0
- package/dist/workflow/components/useActivityForm/createActivityResolver.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/index.d.ts +3 -0
- package/dist/workflow/components/useActivityForm/index.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/types.d.ts +80 -0
- package/dist/workflow/components/useActivityForm/types.d.ts.map +1 -0
- package/dist/workflow/components/useActivityForm/useActivityForm.d.ts +4 -0
- package/dist/workflow/components/useActivityForm/useActivityForm.d.ts.map +1 -0
- package/dist/workflow/index.d.ts +8 -0
- package/dist/workflow/index.d.ts.map +1 -0
- package/dist/workflow/types.d.ts +53 -0
- package/dist/workflow/types.d.ts.map +1 -0
- package/dist/workflow.cjs +1 -0
- package/dist/workflow.d.ts +8 -0
- package/dist/workflow.d.ts.map +1 -0
- package/dist/workflow.mjs +565 -0
- package/dist/workflow.types.cjs +1 -0
- package/dist/workflow.types.d.ts +2 -0
- package/dist/workflow.types.d.ts.map +1 -0
- package/dist/workflow.types.mjs +1 -0
- package/docs/workflow.md +703 -0
- package/package.json +21 -1
- package/sdk/api/client.ts +85 -52
- package/sdk/api/index.ts +1 -0
- package/sdk/api/metadata.ts +4 -4
- package/sdk/bdo/core/BaseBdo.ts +10 -0
- package/sdk/components/hooks/useForm/index.ts +1 -0
- package/sdk/components/hooks/useForm/types.ts +17 -3
- package/sdk/components/hooks/useForm/useDraftInteraction.ts +251 -0
- package/sdk/components/hooks/useForm/useForm.ts +115 -24
- package/sdk/form.types.ts +1 -0
- package/sdk/index.ts +6 -0
- package/sdk/types/constants.ts +2 -2
- package/sdk/workflow/Activity.ts +181 -0
- package/sdk/workflow/ActivityInstance.ts +339 -0
- package/sdk/workflow/client.ts +208 -0
- package/sdk/workflow/components/useActivityForm/createActivityItemProxy.ts +126 -0
- package/sdk/workflow/components/useActivityForm/createActivityResolver.ts +61 -0
- package/sdk/workflow/components/useActivityForm/index.ts +5 -0
- package/sdk/workflow/components/useActivityForm/types.ts +166 -0
- package/sdk/workflow/components/useActivityForm/useActivityForm.ts +386 -0
- package/sdk/workflow/index.ts +20 -0
- package/sdk/workflow/types.ts +84 -0
- package/sdk/workflow.ts +25 -0
- package/sdk/workflow.types.ts +11 -0
- package/dist/client-Bo-RLKJi.cjs +0 -1
- package/dist/client-eA4VvNTo.js +0 -178
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// ACTIVITY BASE CLASS
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Lean abstract base class for typed workflow activities.
|
|
5
|
+
// Replaces ActivityForm — no public getFields(), no phantom types,
|
|
6
|
+
// no exported meta type.
|
|
7
|
+
//
|
|
8
|
+
// Each activity subclass defines:
|
|
9
|
+
// - meta: { businessProcessId, activityId }
|
|
10
|
+
// - Typed field instances as class properties
|
|
11
|
+
//
|
|
12
|
+
// Methods:
|
|
13
|
+
// activity.getInstanceList(options) // list activity instances
|
|
14
|
+
// activity.instanceMetrics(options) // get aggregated metrics
|
|
15
|
+
// activity.getInstance(instanceId) // get typed ActivityInstance
|
|
16
|
+
|
|
17
|
+
import { Workflow } from "./client";
|
|
18
|
+
import { createActivityInstance } from "./ActivityInstance";
|
|
19
|
+
import type { ActivityInstanceType } from "./ActivityInstance";
|
|
20
|
+
import type { ActivityInstanceFieldsType, ActivityOperations } from "./types";
|
|
21
|
+
import type {
|
|
22
|
+
ListOptionsType,
|
|
23
|
+
ListResponseType,
|
|
24
|
+
MetricOptionsType,
|
|
25
|
+
MetricResponseType,
|
|
26
|
+
} from "../types/common";
|
|
27
|
+
import { BaseField } from "../bdo/fields/BaseField";
|
|
28
|
+
|
|
29
|
+
// ============================================================
|
|
30
|
+
// ABSTRACT BASE CLASS
|
|
31
|
+
// ============================================================
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Abstract base class for workflow activities.
|
|
35
|
+
*
|
|
36
|
+
* Extend this class to define typed activity input fields.
|
|
37
|
+
* Each activity is a typed class with field definitions and data operations.
|
|
38
|
+
*
|
|
39
|
+
* @template TEntity - The full entity type with all fields
|
|
40
|
+
* @template TEditable - Fields the user can edit
|
|
41
|
+
* @template TReadonly - Fields that are read-only (computed / system)
|
|
42
|
+
*
|
|
43
|
+
* @example
|
|
44
|
+
* ```typescript
|
|
45
|
+
* class EmployeeInputActivity extends Activity<
|
|
46
|
+
* EmployeeInputEntityType,
|
|
47
|
+
* EmployeeInputEditable,
|
|
48
|
+
* EmployeeInputReadonly
|
|
49
|
+
* > {
|
|
50
|
+
* readonly meta = {
|
|
51
|
+
* businessProcessId: "SimpleLeaveProcess",
|
|
52
|
+
* activityId: "EMPLOYEE_INPUT",
|
|
53
|
+
* };
|
|
54
|
+
*
|
|
55
|
+
* readonly StartDate = new DateTimeField({ id: "StartDate", label: "Start Date" });
|
|
56
|
+
* readonly EndDate = new DateTimeField({ id: "EndDate", label: "End Date" });
|
|
57
|
+
* readonly LeaveDays = new NumberField({ id: "LeaveDays", label: "Leave Days", editable: false });
|
|
58
|
+
* }
|
|
59
|
+
*
|
|
60
|
+
* const activity = new EmployeeInputActivity();
|
|
61
|
+
* const items = await activity.getInstanceList({ Page: 1, PageSize: 10 });
|
|
62
|
+
* const instance = await activity.getInstance("inst_123");
|
|
63
|
+
* instance.StartDate.get(); // typed value
|
|
64
|
+
* instance.StartDate.set("2026-03-01");
|
|
65
|
+
* await instance.update({ StartDate: "2026-03-01" });
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export abstract class Activity<
|
|
69
|
+
TEntity extends Record<string, unknown>,
|
|
70
|
+
TEditable extends Record<string, unknown> = TEntity,
|
|
71
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
72
|
+
TReadonly extends Record<string, unknown> = {},
|
|
73
|
+
> {
|
|
74
|
+
/**
|
|
75
|
+
* Activity metadata — identifies the business process and activity
|
|
76
|
+
*/
|
|
77
|
+
abstract readonly meta: {
|
|
78
|
+
readonly businessProcessId: string;
|
|
79
|
+
readonly activityId: string;
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// ============================================================
|
|
83
|
+
// ACTIVITY OPERATIONS (internal)
|
|
84
|
+
// ============================================================
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get ActivityOperations for this activity.
|
|
88
|
+
* @internal
|
|
89
|
+
*/
|
|
90
|
+
private _ops(): ActivityOperations<TEntity> {
|
|
91
|
+
return new Workflow<TEntity>(this.meta.businessProcessId)
|
|
92
|
+
.activity(this.meta.activityId);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ============================================================
|
|
96
|
+
// FIELD DISCOVERY (internal)
|
|
97
|
+
// ============================================================
|
|
98
|
+
|
|
99
|
+
private _fieldsCache: Record<string, BaseField<unknown>> | null = null;
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Discover BaseField instances from subclass properties.
|
|
103
|
+
* @internal
|
|
104
|
+
*/
|
|
105
|
+
private _discoverFields(): Record<string, BaseField<unknown>> {
|
|
106
|
+
if (this._fieldsCache) return this._fieldsCache;
|
|
107
|
+
|
|
108
|
+
const fields: Record<string, BaseField<unknown>> = {};
|
|
109
|
+
for (const key of Object.keys(this)) {
|
|
110
|
+
const value = (this as Record<string, unknown>)[key];
|
|
111
|
+
if (value instanceof BaseField) {
|
|
112
|
+
fields[key] = value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
this._fieldsCache = fields;
|
|
117
|
+
return fields;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// ============================================================
|
|
121
|
+
// PUBLIC METHODS
|
|
122
|
+
// ============================================================
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* List activity instances with optional filtering/pagination.
|
|
126
|
+
*/
|
|
127
|
+
async getInstanceList(
|
|
128
|
+
options?: ListOptionsType,
|
|
129
|
+
): Promise<ListResponseType<ActivityInstanceFieldsType & TEntity>> {
|
|
130
|
+
return this._ops().list(options);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Get aggregated metrics for activity instances.
|
|
135
|
+
*/
|
|
136
|
+
async instanceMetrics(
|
|
137
|
+
options: Omit<MetricOptionsType, "Type">,
|
|
138
|
+
): Promise<MetricResponseType> {
|
|
139
|
+
return this._ops().metric(options);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Get a typed ActivityInstance with field accessors and persistence methods.
|
|
144
|
+
*
|
|
145
|
+
* @param instanceId - The activity instance identifier
|
|
146
|
+
* @returns ActivityInstance with typed field accessors
|
|
147
|
+
*/
|
|
148
|
+
async getInstance(
|
|
149
|
+
instanceId: string,
|
|
150
|
+
): Promise<ActivityInstanceType<TEntity, TEditable, TReadonly>> {
|
|
151
|
+
const ops = this._ops();
|
|
152
|
+
const data = await ops.read(instanceId);
|
|
153
|
+
const fields = this._discoverFields();
|
|
154
|
+
return createActivityInstance<TEntity, TEditable, TReadonly>(
|
|
155
|
+
ops,
|
|
156
|
+
instanceId,
|
|
157
|
+
data as TEntity,
|
|
158
|
+
fields,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// ============================================================
|
|
163
|
+
// INTERNAL ACCESSORS (used by useActivityForm hook)
|
|
164
|
+
// ============================================================
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Get discovered fields — used internally by useActivityForm hook.
|
|
168
|
+
* @internal
|
|
169
|
+
*/
|
|
170
|
+
_getFields(): Record<string, BaseField<unknown>> {
|
|
171
|
+
return this._discoverFields();
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Get ActivityOperations — used internally by useActivityForm hook.
|
|
176
|
+
* @internal
|
|
177
|
+
*/
|
|
178
|
+
_getOps(): ActivityOperations<TEntity> {
|
|
179
|
+
return this._ops();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,339 @@
|
|
|
1
|
+
// ============================================================
|
|
2
|
+
// ACTIVITY INSTANCE CLASS
|
|
3
|
+
// ============================================================
|
|
4
|
+
// Wraps an activity instance record with field accessors (BDO Item pattern)
|
|
5
|
+
// plus workflow-specific persistence methods.
|
|
6
|
+
//
|
|
7
|
+
// Field Accessor Pattern:
|
|
8
|
+
// instance.StartDate.get() // read value
|
|
9
|
+
// instance.StartDate.set("2026-03-01") // set value (editable only)
|
|
10
|
+
// instance.StartDate.meta // field metadata
|
|
11
|
+
// instance.LeaveDays.get() // read computed/readonly
|
|
12
|
+
// instance._id // instance ID
|
|
13
|
+
// instance.toJSON() // plain object
|
|
14
|
+
// instance.validate() // validate all fields
|
|
15
|
+
//
|
|
16
|
+
// Persistence Methods:
|
|
17
|
+
// instance.update(data) // regular update -> ops.update()
|
|
18
|
+
// instance.save(data) // commit draft -> ops.draftEnd()
|
|
19
|
+
// instance.complete() // complete -> ops.complete()
|
|
20
|
+
// instance.progress() // get progress -> ops.progress()
|
|
21
|
+
|
|
22
|
+
import type { ValidationResultType, BaseFieldMetaType } from "../bdo/core/types";
|
|
23
|
+
import type { BaseField } from "../bdo/fields/BaseField";
|
|
24
|
+
import type { ActivityOperations, ActivityProgressType } from "./types";
|
|
25
|
+
import type { CreateUpdateResponseType } from "../types/common";
|
|
26
|
+
|
|
27
|
+
// ============================================================
|
|
28
|
+
// ACCESSOR TYPES
|
|
29
|
+
// ============================================================
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Editable field accessor — has get(), set(), validate(), meta
|
|
33
|
+
*/
|
|
34
|
+
export interface EditableFieldAccessor<T> {
|
|
35
|
+
readonly label: string;
|
|
36
|
+
readonly required: boolean;
|
|
37
|
+
readonly readOnly: boolean;
|
|
38
|
+
readonly defaultValue: unknown;
|
|
39
|
+
readonly meta: BaseFieldMetaType;
|
|
40
|
+
get(): T | undefined;
|
|
41
|
+
set(value: T): void;
|
|
42
|
+
validate(): ValidationResultType;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Readonly field accessor — has get(), validate(), meta (NO set)
|
|
47
|
+
*/
|
|
48
|
+
export interface ReadonlyFieldAccessor<T> {
|
|
49
|
+
readonly label: string;
|
|
50
|
+
readonly required: boolean;
|
|
51
|
+
readonly readOnly: boolean;
|
|
52
|
+
readonly defaultValue: unknown;
|
|
53
|
+
readonly meta: BaseFieldMetaType;
|
|
54
|
+
get(): T | undefined;
|
|
55
|
+
validate(): ValidationResultType;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============================================================
|
|
59
|
+
// MAPPED ACCESSOR TYPES
|
|
60
|
+
// ============================================================
|
|
61
|
+
|
|
62
|
+
type EditableAccessors<T> = {
|
|
63
|
+
[K in keyof T]: EditableFieldAccessor<T[K]>;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
type ReadonlyAccessors<T> = {
|
|
67
|
+
[K in keyof T]: ReadonlyFieldAccessor<T[K]>;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* Full ActivityInstance type with field accessors and persistence methods.
|
|
72
|
+
*/
|
|
73
|
+
export type ActivityInstanceType<
|
|
74
|
+
TEntity extends Record<string, unknown>,
|
|
75
|
+
TEditable extends Record<string, unknown> = TEntity,
|
|
76
|
+
TReadonly extends Record<string, unknown> = {},
|
|
77
|
+
> = ActivityInstance<TEntity, TEditable> &
|
|
78
|
+
EditableAccessors<TEditable> &
|
|
79
|
+
ReadonlyAccessors<TReadonly> &
|
|
80
|
+
{ readonly _id: string };
|
|
81
|
+
|
|
82
|
+
// ============================================================
|
|
83
|
+
// ACTIVITY INSTANCE CLASS
|
|
84
|
+
// ============================================================
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* ActivityInstance wraps a single activity instance record with:
|
|
88
|
+
* - BDO Item-style field accessors (get/set/meta/validate)
|
|
89
|
+
* - Workflow persistence methods (update, save, complete, progress)
|
|
90
|
+
*
|
|
91
|
+
* @template TEntity - Full entity type (all fields)
|
|
92
|
+
* @template TEditable - Editable subset of fields
|
|
93
|
+
*/
|
|
94
|
+
export class ActivityInstance<
|
|
95
|
+
TEntity extends Record<string, unknown>,
|
|
96
|
+
TEditable extends Record<string, unknown> = TEntity,
|
|
97
|
+
> {
|
|
98
|
+
readonly _id: string;
|
|
99
|
+
private readonly _data: Record<string, unknown>;
|
|
100
|
+
private readonly _ops: ActivityOperations<TEntity>;
|
|
101
|
+
private readonly _fields: Record<string, BaseField<unknown>>;
|
|
102
|
+
private readonly _accessorCache: Map<string, EditableFieldAccessor<unknown> | ReadonlyFieldAccessor<unknown>> = new Map();
|
|
103
|
+
|
|
104
|
+
constructor(
|
|
105
|
+
ops: ActivityOperations<TEntity>,
|
|
106
|
+
instanceId: string,
|
|
107
|
+
data: Record<string, unknown>,
|
|
108
|
+
fields: Record<string, BaseField<unknown>>,
|
|
109
|
+
) {
|
|
110
|
+
this._ops = ops;
|
|
111
|
+
this._id = instanceId;
|
|
112
|
+
this._data = { ...data };
|
|
113
|
+
this._fields = fields;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
// ============================================================
|
|
117
|
+
// BDO ITEM METHODS
|
|
118
|
+
// ============================================================
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Convert the instance to a plain object
|
|
122
|
+
*/
|
|
123
|
+
toJSON(): Partial<TEntity> {
|
|
124
|
+
return { ...this._data } as Partial<TEntity>;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Validate all fields and return combined results
|
|
129
|
+
*/
|
|
130
|
+
validate(): ValidationResultType {
|
|
131
|
+
const allErrors: string[] = [];
|
|
132
|
+
|
|
133
|
+
for (const [fieldId, fieldDef] of Object.entries(this._fields)) {
|
|
134
|
+
const value = this._data[fieldId];
|
|
135
|
+
const result = fieldDef.validate(value);
|
|
136
|
+
if (!result.valid) {
|
|
137
|
+
allErrors.push(...result.errors);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
return {
|
|
142
|
+
valid: allErrors.length === 0,
|
|
143
|
+
errors: allErrors,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// ============================================================
|
|
148
|
+
// WORKFLOW PERSISTENCE METHODS
|
|
149
|
+
// ============================================================
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Regular update — calls ActivityOperations.update()
|
|
153
|
+
*/
|
|
154
|
+
async update(data: Partial<TEditable>): Promise<CreateUpdateResponseType> {
|
|
155
|
+
return this._ops.update(this._id, data as Partial<TEntity>);
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Commit draft — calls ActivityOperations.draftEnd()
|
|
160
|
+
*/
|
|
161
|
+
async save(data: Partial<TEditable>): Promise<CreateUpdateResponseType> {
|
|
162
|
+
return this._ops.draftEnd(this._id, data as Partial<TEntity>);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Complete the activity — calls ActivityOperations.complete()
|
|
167
|
+
*/
|
|
168
|
+
async complete(): Promise<CreateUpdateResponseType> {
|
|
169
|
+
return this._ops.complete(this._id);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* Get activity progress — calls ActivityOperations.progress()
|
|
174
|
+
*/
|
|
175
|
+
async progress(): Promise<ActivityProgressType> {
|
|
176
|
+
return this._ops.progress(this._id);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// ============================================================
|
|
180
|
+
// FIELD ACCESSOR (internal)
|
|
181
|
+
// ============================================================
|
|
182
|
+
|
|
183
|
+
/** @internal */
|
|
184
|
+
_getAccessor(fieldId: string): EditableFieldAccessor<unknown> | ReadonlyFieldAccessor<unknown> {
|
|
185
|
+
if (this._accessorCache.has(fieldId)) {
|
|
186
|
+
return this._accessorCache.get(fieldId)!;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const fieldDef = this._fields[fieldId];
|
|
190
|
+
const meta: BaseFieldMetaType = fieldDef?.meta ?? {
|
|
191
|
+
_id: fieldId,
|
|
192
|
+
Name: fieldId,
|
|
193
|
+
Type: "String",
|
|
194
|
+
};
|
|
195
|
+
const isReadOnly = fieldDef?.readOnly ?? false;
|
|
196
|
+
|
|
197
|
+
const validate = (): ValidationResultType => {
|
|
198
|
+
if (fieldDef) {
|
|
199
|
+
return fieldDef.validate(this._data[fieldId]);
|
|
200
|
+
}
|
|
201
|
+
return { valid: true, errors: [] };
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
let accessor: EditableFieldAccessor<unknown> | ReadonlyFieldAccessor<unknown>;
|
|
205
|
+
|
|
206
|
+
if (!isReadOnly) {
|
|
207
|
+
accessor = {
|
|
208
|
+
label: fieldDef?.label ?? fieldId,
|
|
209
|
+
required: fieldDef?.required ?? false,
|
|
210
|
+
readOnly: false,
|
|
211
|
+
defaultValue: fieldDef?.defaultValue,
|
|
212
|
+
meta,
|
|
213
|
+
get: () => this._data[fieldId],
|
|
214
|
+
set: (value: unknown) => {
|
|
215
|
+
this._data[fieldId] = value;
|
|
216
|
+
},
|
|
217
|
+
validate,
|
|
218
|
+
};
|
|
219
|
+
} else {
|
|
220
|
+
accessor = {
|
|
221
|
+
label: fieldDef?.label ?? fieldId,
|
|
222
|
+
required: fieldDef?.required ?? false,
|
|
223
|
+
readOnly: true,
|
|
224
|
+
defaultValue: fieldDef?.defaultValue,
|
|
225
|
+
meta,
|
|
226
|
+
get: () => this._data[fieldId],
|
|
227
|
+
validate,
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
this._accessorCache.set(fieldId, accessor);
|
|
232
|
+
return accessor;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// ============================================================
|
|
237
|
+
// FACTORY FUNCTION
|
|
238
|
+
// ============================================================
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Creates an ActivityInstance with Proxy-based field accessors.
|
|
242
|
+
* Fields are discovered from the provided fields map.
|
|
243
|
+
*
|
|
244
|
+
* @param ops - ActivityOperations for API calls
|
|
245
|
+
* @param instanceId - The activity instance ID
|
|
246
|
+
* @param data - Raw instance data from the API
|
|
247
|
+
* @param fields - Map of field name -> BaseField instance
|
|
248
|
+
* @returns Proxied ActivityInstance with typed field accessors
|
|
249
|
+
*/
|
|
250
|
+
export function createActivityInstance<
|
|
251
|
+
TEntity extends Record<string, unknown>,
|
|
252
|
+
TEditable extends Record<string, unknown> = TEntity,
|
|
253
|
+
TReadonly extends Record<string, unknown> = {},
|
|
254
|
+
>(
|
|
255
|
+
ops: ActivityOperations<TEntity>,
|
|
256
|
+
instanceId: string,
|
|
257
|
+
data: TEntity,
|
|
258
|
+
fields: Record<string, BaseField<unknown>>,
|
|
259
|
+
): ActivityInstanceType<TEntity, TEditable, TReadonly> {
|
|
260
|
+
const instance = new ActivityInstance<TEntity, TEditable>(
|
|
261
|
+
ops,
|
|
262
|
+
instanceId,
|
|
263
|
+
data as Record<string, unknown>,
|
|
264
|
+
fields,
|
|
265
|
+
);
|
|
266
|
+
|
|
267
|
+
return new Proxy(instance, {
|
|
268
|
+
get(target, prop, receiver) {
|
|
269
|
+
// Handle ActivityInstance's own methods and properties first
|
|
270
|
+
if (
|
|
271
|
+
prop === "validate" ||
|
|
272
|
+
prop === "toJSON" ||
|
|
273
|
+
prop === "update" ||
|
|
274
|
+
prop === "save" ||
|
|
275
|
+
prop === "complete" ||
|
|
276
|
+
prop === "progress" ||
|
|
277
|
+
prop === "_ops" ||
|
|
278
|
+
prop === "_data" ||
|
|
279
|
+
prop === "_fields" ||
|
|
280
|
+
prop === "_accessorCache" ||
|
|
281
|
+
prop === "_getAccessor"
|
|
282
|
+
) {
|
|
283
|
+
return Reflect.get(target, prop, receiver);
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
// Handle symbol properties
|
|
287
|
+
if (typeof prop === "symbol") {
|
|
288
|
+
return Reflect.get(target, prop, receiver);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// _id is returned directly
|
|
292
|
+
if (prop === "_id") {
|
|
293
|
+
return target._id;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
// Return field accessor
|
|
297
|
+
return target._getAccessor(prop as string);
|
|
298
|
+
},
|
|
299
|
+
|
|
300
|
+
has(target, prop) {
|
|
301
|
+
if (typeof prop === "symbol") return false;
|
|
302
|
+
if (
|
|
303
|
+
prop === "validate" ||
|
|
304
|
+
prop === "toJSON" ||
|
|
305
|
+
prop === "update" ||
|
|
306
|
+
prop === "save" ||
|
|
307
|
+
prop === "complete" ||
|
|
308
|
+
prop === "progress" ||
|
|
309
|
+
prop === "_id"
|
|
310
|
+
) {
|
|
311
|
+
return true;
|
|
312
|
+
}
|
|
313
|
+
return prop in target["_fields"];
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
ownKeys(target) {
|
|
317
|
+
return [
|
|
318
|
+
...Object.keys(target["_fields"]),
|
|
319
|
+
"_id",
|
|
320
|
+
"validate",
|
|
321
|
+
"toJSON",
|
|
322
|
+
"update",
|
|
323
|
+
"save",
|
|
324
|
+
"complete",
|
|
325
|
+
"progress",
|
|
326
|
+
];
|
|
327
|
+
},
|
|
328
|
+
|
|
329
|
+
getOwnPropertyDescriptor(_, prop) {
|
|
330
|
+
if (typeof prop === "symbol") return undefined;
|
|
331
|
+
return {
|
|
332
|
+
configurable: true,
|
|
333
|
+
enumerable: prop !== "validate" && prop !== "toJSON" &&
|
|
334
|
+
prop !== "update" && prop !== "save" &&
|
|
335
|
+
prop !== "complete" && prop !== "progress",
|
|
336
|
+
};
|
|
337
|
+
},
|
|
338
|
+
}) as ActivityInstanceType<TEntity, TEditable, TReadonly>;
|
|
339
|
+
}
|