@objectql/types 1.5.0 → 1.6.1

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.
@@ -0,0 +1,391 @@
1
+ /**
2
+ * Permission and Security Metadata Types
3
+ *
4
+ * This module defines the TypeScript interfaces for ObjectQL's permission system,
5
+ * implementing role-based access control (RBAC), field-level security, and
6
+ * record-level rules.
7
+ *
8
+ * Based on specification: docs/spec/permission.md
9
+ */
10
+ /**
11
+ * Basic CRUD operations for object-level permissions
12
+ */
13
+ export type ObjectOperation = 'create' | 'read' | 'update' | 'delete' | 'view_all' | 'modify_all';
14
+ /**
15
+ * Field-level operations
16
+ */
17
+ export type FieldOperation = 'read' | 'update';
18
+ /**
19
+ * Comparison operators for permission conditions
20
+ */
21
+ export type PermissionOperator = '=' | '!=' | '>' | '>=' | '<' | '<=' | 'in' | 'not_in' | 'contains' | 'not_contains' | 'starts_with' | 'ends_with';
22
+ /**
23
+ * Object-level permissions controlling CRUD operations
24
+ */
25
+ export interface ObjectPermissions {
26
+ /** Roles that can create new records */
27
+ create?: string[];
28
+ /** Roles that can view records */
29
+ read?: string[];
30
+ /** Roles that can update records */
31
+ update?: string[];
32
+ /** Roles that can delete records */
33
+ delete?: string[];
34
+ /** Roles that can view all records (bypass ownership rules) */
35
+ view_all?: string[];
36
+ /** Roles that can modify all records (bypass ownership rules) */
37
+ modify_all?: string[];
38
+ }
39
+ /**
40
+ * Field-level permissions for a specific field
41
+ */
42
+ export interface FieldPermission {
43
+ /** Roles that can read this field */
44
+ read?: string[];
45
+ /** Roles that can update this field */
46
+ update?: string[];
47
+ }
48
+ /**
49
+ * Map of field names to their permissions
50
+ */
51
+ export type FieldPermissions = Record<string, FieldPermission>;
52
+ /**
53
+ * Condition type for record-level rules
54
+ */
55
+ export type ConditionType = 'simple' | 'complex' | 'formula' | 'lookup';
56
+ /**
57
+ * Simple condition for a single field comparison
58
+ */
59
+ export interface SimpleCondition {
60
+ type?: 'simple';
61
+ /** Field to check */
62
+ field: string;
63
+ /** Comparison operator */
64
+ operator: PermissionOperator;
65
+ /** Value to compare against (can include variables like $current_user.id) */
66
+ value: any;
67
+ }
68
+ /**
69
+ * Simple condition element (inline form for complex expressions)
70
+ */
71
+ export interface ConditionElement {
72
+ field: string;
73
+ operator: PermissionOperator;
74
+ value: any;
75
+ }
76
+ /**
77
+ * Expression element in complex conditions
78
+ */
79
+ export type ConditionExpression = SimpleCondition | ConditionElement | 'and' | 'or';
80
+ /**
81
+ * Complex condition with multiple clauses
82
+ */
83
+ export interface ComplexCondition {
84
+ type: 'complex';
85
+ /** Array of conditions and logical operators */
86
+ expression: ConditionExpression[];
87
+ }
88
+ /**
89
+ * Formula-based condition using custom logic
90
+ */
91
+ export interface FormulaCondition {
92
+ type: 'formula';
93
+ /** JavaScript expression or formula */
94
+ formula: string;
95
+ }
96
+ /**
97
+ * Lookup condition checking related record data
98
+ */
99
+ export interface LookupCondition {
100
+ type: 'lookup';
101
+ /** Related object to check */
102
+ object: string;
103
+ /** Field linking to related object */
104
+ via: string;
105
+ /** Condition to check on related object */
106
+ condition: RecordRuleCondition;
107
+ }
108
+ /**
109
+ * Union type for all condition types
110
+ */
111
+ export type RecordRuleCondition = SimpleCondition | ComplexCondition | FormulaCondition | LookupCondition;
112
+ /**
113
+ * Permissions granted by a record rule
114
+ */
115
+ export interface RecordRulePermissions {
116
+ /** Grant read permission */
117
+ read?: boolean;
118
+ /** Grant update permission */
119
+ update?: boolean;
120
+ /** Grant delete permission */
121
+ delete?: boolean;
122
+ }
123
+ /**
124
+ * Record-level rule for dynamic access control
125
+ */
126
+ export interface RecordRule {
127
+ /** Unique name of the rule */
128
+ name: string;
129
+ /** Priority (higher priority rules take precedence, default: 0) */
130
+ priority?: number;
131
+ /** Human-readable description */
132
+ description?: string;
133
+ /** Condition for applying this rule */
134
+ condition: RecordRuleCondition;
135
+ /** Permissions granted when condition matches */
136
+ permissions: RecordRulePermissions;
137
+ }
138
+ /**
139
+ * Sharing rule type
140
+ */
141
+ export type SharingRuleType = 'manual' | 'criteria' | 'team';
142
+ /**
143
+ * Who to share with
144
+ */
145
+ export interface SharedWith {
146
+ type: 'role' | 'team' | 'user' | 'group';
147
+ roles?: string[];
148
+ teams?: string[];
149
+ users?: string[];
150
+ groups?: string[];
151
+ }
152
+ /**
153
+ * Base sharing rule
154
+ */
155
+ export interface BaseSharingRule {
156
+ /** Unique name of the rule */
157
+ name: string;
158
+ /** Type of sharing rule */
159
+ type: SharingRuleType;
160
+ /** Description */
161
+ description?: string;
162
+ /** Whether this rule is enabled */
163
+ enabled?: boolean;
164
+ /** Permissions granted through sharing */
165
+ permissions: RecordRulePermissions;
166
+ }
167
+ /**
168
+ * Manual sharing rule - users can manually share records
169
+ */
170
+ export interface ManualSharingRule extends BaseSharingRule {
171
+ type: 'manual';
172
+ }
173
+ /**
174
+ * Criteria-based sharing rule - automatic sharing
175
+ */
176
+ export interface CriteriaSharingRule extends BaseSharingRule {
177
+ type: 'criteria';
178
+ /** Condition for automatic sharing */
179
+ condition: RecordRuleCondition;
180
+ /** Who to share with */
181
+ shared_with: SharedWith;
182
+ }
183
+ /**
184
+ * Team-based sharing rule
185
+ */
186
+ export interface TeamSharingRule extends BaseSharingRule {
187
+ type: 'team';
188
+ /** Field containing team ID */
189
+ team_field: string;
190
+ }
191
+ /**
192
+ * Union type for all sharing rules
193
+ */
194
+ export type SharingRule = ManualSharingRule | CriteriaSharingRule | TeamSharingRule;
195
+ /**
196
+ * Condition for action execution
197
+ */
198
+ export interface ActionCondition {
199
+ /** Field to check */
200
+ field: string;
201
+ /** Comparison operator */
202
+ operator: PermissionOperator;
203
+ /** Value to compare */
204
+ value: any;
205
+ }
206
+ /**
207
+ * Rate limiting configuration for actions
208
+ */
209
+ export interface ActionRateLimit {
210
+ /** Maximum requests per hour */
211
+ requests_per_hour?: number;
212
+ /** Maximum requests per day */
213
+ requests_per_day?: number;
214
+ }
215
+ /**
216
+ * Permission configuration for a specific action
217
+ */
218
+ export interface ActionPermission {
219
+ /** Roles that can execute this action */
220
+ execute: string[];
221
+ /** Conditions that must be met for execution */
222
+ conditions?: ActionCondition[];
223
+ /** Rate limiting */
224
+ rate_limit?: ActionRateLimit;
225
+ }
226
+ /**
227
+ * Map of action names to their permissions
228
+ */
229
+ export type ActionPermissions = Record<string, ActionPermission>;
230
+ /**
231
+ * Field restrictions for a view
232
+ */
233
+ export interface ViewFieldRestriction {
234
+ /** Field name */
235
+ [fieldName: string]: {
236
+ /** Roles that can see this field in the view */
237
+ visible_to: string[];
238
+ };
239
+ }
240
+ /**
241
+ * Permission configuration for a specific view
242
+ */
243
+ export interface ViewPermission {
244
+ /** Roles that can access this view */
245
+ access: string[];
246
+ /** Field-level restrictions within the view */
247
+ field_restrictions?: ViewFieldRestriction;
248
+ }
249
+ /**
250
+ * Map of view names to their permissions
251
+ */
252
+ export type ViewPermissions = Record<string, ViewPermission>;
253
+ /**
254
+ * Row-level security configuration
255
+ */
256
+ export interface RowLevelSecurity {
257
+ /** Whether RLS is enabled */
258
+ enabled: boolean;
259
+ /** Default rule applied to all users */
260
+ default_rule?: SimpleCondition;
261
+ /** Exceptions to the default rule */
262
+ exceptions?: Array<{
263
+ /** Role to apply exception to */
264
+ role: string;
265
+ /** Whether to bypass RLS entirely */
266
+ bypass?: boolean;
267
+ /** Custom condition for this role */
268
+ condition?: RecordRuleCondition;
269
+ }>;
270
+ }
271
+ /**
272
+ * Field masking configuration for a specific field
273
+ */
274
+ export interface FieldMaskConfig {
275
+ /** Mask format (e.g., "****-****-****-{last4}") */
276
+ mask_format: string;
277
+ /** Roles that can see the unmasked value */
278
+ visible_to: string[];
279
+ }
280
+ /**
281
+ * Map of field names to their masking configuration
282
+ */
283
+ export type FieldMasking = Record<string, FieldMaskConfig>;
284
+ /**
285
+ * Audit event type
286
+ */
287
+ export type AuditEventType = 'permission_grant' | 'permission_revoke' | 'access_denied' | 'sensitive_field_access';
288
+ /**
289
+ * Alert configuration for suspicious activity
290
+ */
291
+ export interface AuditAlert {
292
+ /** Event type to alert on */
293
+ event: AuditEventType;
294
+ /** Number of events to trigger alert */
295
+ threshold: number;
296
+ /** Time window in minutes */
297
+ window_minutes: number;
298
+ /** Who to notify (roles or user IDs) */
299
+ notify: string[];
300
+ }
301
+ /**
302
+ * Audit trail configuration
303
+ */
304
+ export interface AuditConfig {
305
+ /** Whether auditing is enabled */
306
+ enabled: boolean;
307
+ /** Events to log */
308
+ events?: AuditEventType[];
309
+ /** Retention period in days */
310
+ retention_days?: number;
311
+ /** Alert configurations */
312
+ alerts?: AuditAlert[];
313
+ }
314
+ /**
315
+ * Complete permission configuration for an object
316
+ */
317
+ export interface PermissionConfig {
318
+ /** Unique name of the permission configuration */
319
+ name: string;
320
+ /** Object this permission applies to */
321
+ object: string;
322
+ /** Description */
323
+ description?: string;
324
+ /**
325
+ * Roles referenced in this permission configuration.
326
+ *
327
+ * Best Practice: Define roles centrally in ApplicationConfig and reference them here.
328
+ * This field serves to:
329
+ * 1. Document which roles apply to this object
330
+ * 2. Validate that only defined roles are used
331
+ * 3. Support standalone usage without application context
332
+ *
333
+ * Example:
334
+ * - Define in app: permissions.roles: [admin, manager, user]
335
+ * - Reference here: roles: [admin, manager, user]
336
+ */
337
+ roles?: string[];
338
+ /** Object-level permissions */
339
+ object_permissions?: ObjectPermissions;
340
+ /** Field-level security */
341
+ field_permissions?: FieldPermissions;
342
+ /** Record-level access rules */
343
+ record_rules?: RecordRule[];
344
+ /** Sharing rules */
345
+ sharing_rules?: SharingRule[];
346
+ /** Action permissions */
347
+ action_permissions?: ActionPermissions;
348
+ /** View permissions */
349
+ view_permissions?: ViewPermissions;
350
+ /** Row-level security */
351
+ row_level_security?: RowLevelSecurity;
352
+ /** Field masking */
353
+ field_masking?: FieldMasking;
354
+ /** Audit configuration */
355
+ audit?: AuditConfig;
356
+ }
357
+ /**
358
+ * Context for permission checks
359
+ */
360
+ export interface PermissionCheckContext {
361
+ /** Current user */
362
+ user: {
363
+ id: string;
364
+ /** User roles (array for consistency, single role represented as one-element array) */
365
+ roles?: string[];
366
+ department_id?: string;
367
+ team_id?: string;
368
+ [key: string]: any;
369
+ };
370
+ /** Object name */
371
+ object: string;
372
+ /** Operation to check */
373
+ operation: ObjectOperation | FieldOperation;
374
+ /** Record ID (for record-level checks) */
375
+ recordId?: string;
376
+ /** Field name (for field-level checks) */
377
+ field?: string;
378
+ /** Record data (for condition evaluation) */
379
+ record?: any;
380
+ }
381
+ /**
382
+ * Result of a permission check
383
+ */
384
+ export interface PermissionCheckResult {
385
+ /** Whether permission is granted */
386
+ granted: boolean;
387
+ /** Reason if denied */
388
+ reason?: string;
389
+ /** Rule that granted/denied access */
390
+ rule?: string;
391
+ }
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ /**
3
+ * Permission and Security Metadata Types
4
+ *
5
+ * This module defines the TypeScript interfaces for ObjectQL's permission system,
6
+ * implementing role-based access control (RBAC), field-level security, and
7
+ * record-level rules.
8
+ *
9
+ * Based on specification: docs/spec/permission.md
10
+ */
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ //# sourceMappingURL=permission.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"permission.js","sourceRoot":"","sources":["../src/permission.ts"],"names":[],"mappings":";AAAA;;;;;;;;GAQG"}
package/dist/registry.js CHANGED
@@ -13,7 +13,10 @@ class MetadataRegistry {
13
13
  this.store.get(type).set(metadata.id, metadata);
14
14
  }
15
15
  unregister(type, id) {
16
- this.store.get(type)?.delete(id);
16
+ const map = this.store.get(type);
17
+ if (map) {
18
+ map.delete(id);
19
+ }
17
20
  }
18
21
  unregisterPackage(packageName) {
19
22
  for (const [type, map] of this.store.entries()) {
@@ -30,7 +33,11 @@ class MetadataRegistry {
30
33
  }
31
34
  }
32
35
  get(type, id) {
33
- return this.store.get(type)?.get(id)?.content;
36
+ const map = this.store.get(type);
37
+ if (!map)
38
+ return undefined;
39
+ const entry = map.get(id);
40
+ return entry ? entry.content : undefined;
34
41
  }
35
42
  list(type) {
36
43
  const map = this.store.get(type);
@@ -39,7 +46,8 @@ class MetadataRegistry {
39
46
  return Array.from(map.values()).map(m => m.content);
40
47
  }
41
48
  getEntry(type, id) {
42
- return this.store.get(type)?.get(id);
49
+ const map = this.store.get(type);
50
+ return map ? map.get(id) : undefined;
43
51
  }
44
52
  }
45
53
  exports.MetadataRegistry = MetadataRegistry;
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":";;;AAQA,MAAa,gBAAgB;IAA7B;QACI,+BAA+B;QACvB,UAAK,GAAuC,IAAI,GAAG,EAAE,CAAC;IA2ClE,CAAC;IAzCG,QAAQ,CAAC,IAAY,EAAE,QAAkB;QACrC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,UAAU,CAAC,IAAY,EAAE,EAAU;QAC/B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;IACrC,CAAC;IAED,iBAAiB,CAAC,WAAmB;QACjC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7C,MAAM,eAAe,GAAa,EAAE,CAAC;YAErC,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,OAAO,KAAK,WAAW,EAAE,CAAC;oBAC/B,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC;YACL,CAAC;YAED,+BAA+B;YAC/B,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;gBAC/B,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;QACL,CAAC;IACL,CAAC;IAED,GAAG,CAAU,IAAY,EAAE,EAAU;QACjC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,OAAY,CAAC;IACvD,CAAC;IAED,IAAI,CAAU,IAAY;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAY,CAAC,CAAC;IAC7D,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,EAAU;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACzC,CAAC;CACJ;AA7CD,4CA6CC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":";;;AAQA,MAAa,gBAAgB;IAA7B;QACI,+BAA+B;QACvB,UAAK,GAAuC,IAAI,GAAG,EAAE,CAAC;IAkDlE,CAAC;IAhDG,QAAQ,CAAC,IAAY,EAAE,QAAkB;QACrC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACpC,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,UAAU,CAAC,IAAY,EAAE,EAAU;QAC/B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,GAAG,EAAE,CAAC;YACN,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;QACnB,CAAC;IACL,CAAC;IAED,iBAAiB,CAAC,WAAmB;QACjC,KAAK,MAAM,CAAC,IAAI,EAAE,GAAG,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;YAC7C,MAAM,eAAe,GAAa,EAAE,CAAC;YAErC,KAAK,MAAM,CAAC,EAAE,EAAE,IAAI,CAAC,IAAI,GAAG,CAAC,OAAO,EAAE,EAAE,CAAC;gBACrC,IAAI,IAAI,CAAC,OAAO,KAAK,WAAW,EAAE,CAAC;oBAC/B,eAAe,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;gBAC7B,CAAC;YACL,CAAC;YAED,+BAA+B;YAC/B,KAAK,MAAM,EAAE,IAAI,eAAe,EAAE,CAAC;gBAC/B,GAAG,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;YACnB,CAAC;QACL,CAAC;IACL,CAAC;IAED,GAAG,CAAU,IAAY,EAAE,EAAU;QACjC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,SAAS,CAAC;QAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1B,OAAO,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAY,CAAC,CAAC,CAAC,SAAS,CAAC;IAClD,CAAC;IAED,IAAI,CAAU,IAAY;QACtB,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,IAAI,CAAC,GAAG;YAAE,OAAO,EAAE,CAAC;QACpB,OAAO,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,OAAY,CAAC,CAAC;IAC7D,CAAC;IAED,QAAQ,CAAC,IAAY,EAAE,EAAU;QAC7B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACjC,OAAO,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACzC,CAAC;CACJ;AApDD,4CAoDC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@objectql/types",
3
- "version": "1.5.0",
3
+ "version": "1.6.1",
4
4
  "main": "dist/index.js",
5
5
  "types": "dist/index.d.ts",
6
6
  "dependencies": {},
package/src/app.ts CHANGED
@@ -10,18 +10,10 @@ export interface IObjectQL {
10
10
  getConfigs(): Record<string, ObjectConfig>;
11
11
  datasource(name: string): Driver;
12
12
  init(): Promise<void>;
13
- addPackage(name: string): void;
14
13
  removePackage(name: string): void;
15
14
  metadata: MetadataRegistry;
16
15
 
17
16
  registerObject(object: ObjectConfig): void;
18
- loadFromDirectory(dir: string): void;
19
- addLoader(plugin: LoaderPlugin): void;
20
- /**
21
- * Updates and persists metadata content.
22
- * Only works if the metadata was loaded from a writable file source (e.g. local disk).
23
- */
24
- updateMetadata(type: string, id: string, content: any): Promise<void>;
25
17
 
26
18
  on(event: HookName, objectName: string, handler: HookHandler): void;
27
19
  triggerHook(event: HookName, objectName: string, ctx: HookContext): Promise<void>;
@@ -0,0 +1,46 @@
1
+ export interface AppConfig {
2
+ /**
3
+ * Unique identifier for the application
4
+ */
5
+ name: string;
6
+
7
+ /**
8
+ * Display label for the application
9
+ */
10
+ label: string;
11
+
12
+ /**
13
+ * Description of what this application does
14
+ */
15
+ description?: string;
16
+
17
+ /**
18
+ * Icon name/class for the application
19
+ */
20
+ icon?: string;
21
+
22
+ /**
23
+ * URL to the application logo
24
+ */
25
+ logo?: string;
26
+
27
+ /**
28
+ * Default path to redirect when opening the app
29
+ */
30
+ homepage?: string;
31
+
32
+ /**
33
+ * Sort order for display
34
+ */
35
+ sort_no?: number;
36
+
37
+ /**
38
+ * Whether the application is enabled
39
+ */
40
+ is_active?: boolean;
41
+
42
+ /**
43
+ * Custom metadata/settings
44
+ */
45
+ [key: string]: any;
46
+ }
package/src/field.ts CHANGED
@@ -135,4 +135,15 @@ export interface FieldConfig {
135
135
  // Vector properties
136
136
  /** Dimension of the vector for 'vector' type fields. */
137
137
  dimension?: number;
138
+
139
+ // Formula & Summary
140
+ /** Formula expression. */
141
+ formula?: string;
142
+ /** Object to summarize. */
143
+ summary_object?: string;
144
+ /** Field on the summary object. */
145
+ summary_field?: string;
146
+ /** Type of summary (count, sum, min, max, avg). */
147
+ summary_type?: string;
148
+ filters?: any[];
138
149
  }
package/src/index.ts CHANGED
@@ -11,6 +11,8 @@ export * from './plugin';
11
11
  export * from './config';
12
12
  export * from './context';
13
13
  export * from './validation';
14
-
15
-
14
+ export * from './permission';
15
+ export * from './page';
16
16
  export * from './loader';
17
+ export * from './application';
18
+ export * from './menu';
package/src/menu.ts ADDED
@@ -0,0 +1,102 @@
1
+ export type MenuType = 'sidebar' | 'topnav' | 'context' | 'mobile' | 'admin';
2
+
3
+ export type MenuItemType = 'page' | 'section' | 'url' | 'folder' | 'object' | 'action';
4
+
5
+ export interface MenuItem {
6
+ /**
7
+ * Unique identifier for the menu item
8
+ */
9
+ name: string;
10
+
11
+ /**
12
+ * Display label
13
+ */
14
+ label: string;
15
+
16
+ /**
17
+ * Icon name
18
+ */
19
+ icon?: string;
20
+
21
+ /**
22
+ * Item type
23
+ */
24
+ type?: MenuItemType;
25
+
26
+ /**
27
+ * Navigation path (for type: page/url)
28
+ */
29
+ path?: string;
30
+
31
+ /**
32
+ * Associated Object name (for type: object)
33
+ */
34
+ object?: string;
35
+
36
+ /**
37
+ * Object View name (for type: object)
38
+ */
39
+ view?: string;
40
+
41
+ /**
42
+ * Nested menu items
43
+ */
44
+ items?: MenuItem[];
45
+
46
+ /**
47
+ * Link target (e.g. _blank)
48
+ */
49
+ target?: string;
50
+
51
+ /**
52
+ * Visibility condition
53
+ */
54
+ hidden?: boolean | string;
55
+
56
+ /**
57
+ * Badge value or expression
58
+ */
59
+ badge?: string;
60
+
61
+ /**
62
+ * Custom properties
63
+ */
64
+ [key: string]: any;
65
+ }
66
+
67
+ export interface MenuConfig {
68
+ /**
69
+ * Unique identifier for the menu
70
+ */
71
+ name: string;
72
+
73
+ /**
74
+ * Display label
75
+ */
76
+ label: string;
77
+
78
+ /**
79
+ * Menu type/location
80
+ */
81
+ type?: MenuType;
82
+
83
+ /**
84
+ * The application this menu belongs to
85
+ */
86
+ app?: string;
87
+
88
+ /**
89
+ * Menu items
90
+ */
91
+ items: MenuItem[];
92
+
93
+ /**
94
+ * Whether the menu is active
95
+ */
96
+ is_active?: boolean;
97
+
98
+ /**
99
+ * Custom properties
100
+ */
101
+ [key: string]: any;
102
+ }