@adula/kit 0.2.0-alpha.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.
Files changed (141) hide show
  1. package/LICENSE.md +10 -0
  2. package/README.md +31 -0
  3. package/build/agent/AGENTS.template.md +28 -0
  4. package/build/agent/capabilities.md +13 -0
  5. package/build/agent/skills/adula-frontend-design/SKILL.md +59 -0
  6. package/build/agent/skills/idea-review/SKILL.md +6 -0
  7. package/build/commands/capabilities.d.ts +6 -0
  8. package/build/commands/capabilities.js +9 -0
  9. package/build/commands/doctor.d.ts +9 -0
  10. package/build/commands/doctor.js +32 -0
  11. package/build/commands/gaps.d.ts +12 -0
  12. package/build/commands/gaps.js +46 -0
  13. package/build/commands/install.d.ts +9 -0
  14. package/build/commands/install.js +91 -0
  15. package/build/commands/main.d.ts +6 -0
  16. package/build/commands/main.js +27 -0
  17. package/build/commands/module_add.d.ts +8 -0
  18. package/build/commands/module_add.js +57 -0
  19. package/build/commands/module_remove.d.ts +10 -0
  20. package/build/commands/module_remove.js +94 -0
  21. package/build/commands/resource.d.ts +8 -0
  22. package/build/commands/resource.js +29 -0
  23. package/build/commands/storage_migrate.d.ts +12 -0
  24. package/build/commands/storage_migrate.js +39 -0
  25. package/build/commands/ui.d.ts +11 -0
  26. package/build/commands/ui.js +210 -0
  27. package/build/configure.d.ts +2 -0
  28. package/build/configure.js +79 -0
  29. package/build/database/migrations/1770000000000_kit_core.d.ts +5 -0
  30. package/build/database/migrations/1770000000000_kit_core.js +10 -0
  31. package/build/database/migrations/1770000000001_kit_attachments.d.ts +5 -0
  32. package/build/database/migrations/1770000000001_kit_attachments.js +10 -0
  33. package/build/database/migrations/1770000000002_kit_saved_views.d.ts +5 -0
  34. package/build/database/migrations/1770000000002_kit_saved_views.js +10 -0
  35. package/build/database/migrations/1770000000003_kit_user_invitations.d.ts +5 -0
  36. package/build/database/migrations/1770000000003_kit_user_invitations.js +18 -0
  37. package/build/index.d.ts +51 -0
  38. package/build/index.js +34 -0
  39. package/build/providers/kit_provider.d.ts +6 -0
  40. package/build/providers/kit_provider.js +10 -0
  41. package/build/src/admin/contracts.d.ts +12 -0
  42. package/build/src/admin/contracts.js +93 -0
  43. package/build/src/admin/controller.d.ts +30 -0
  44. package/build/src/admin/controller.js +116 -0
  45. package/build/src/admin/errors.d.ts +5 -0
  46. package/build/src/admin/errors.js +9 -0
  47. package/build/src/admin/presentation.d.ts +22 -0
  48. package/build/src/admin/presentation.js +1 -0
  49. package/build/src/admin/resource_service.d.ts +170 -0
  50. package/build/src/admin/resource_service.js +763 -0
  51. package/build/src/attachments/attachment_service.d.ts +71 -0
  52. package/build/src/attachments/attachment_service.js +182 -0
  53. package/build/src/attachments/doctor.d.ts +4 -0
  54. package/build/src/attachments/doctor.js +28 -0
  55. package/build/src/attachments/storage_migrate.d.ts +39 -0
  56. package/build/src/attachments/storage_migrate.js +64 -0
  57. package/build/src/auth/ability.d.ts +22 -0
  58. package/build/src/auth/ability.js +31 -0
  59. package/build/src/auth/actor_store.d.ts +14 -0
  60. package/build/src/auth/actor_store.js +65 -0
  61. package/build/src/auth/conditions.d.ts +11 -0
  62. package/build/src/auth/conditions.js +81 -0
  63. package/build/src/auth/packed_rules.d.ts +4 -0
  64. package/build/src/auth/packed_rules.js +13 -0
  65. package/build/src/auth/sql.d.ts +11 -0
  66. package/build/src/auth/sql.js +114 -0
  67. package/build/src/commands/agent_assets.d.ts +7 -0
  68. package/build/src/commands/agent_assets.js +54 -0
  69. package/build/src/commands/doctor.d.ts +11 -0
  70. package/build/src/commands/doctor.js +261 -0
  71. package/build/src/commands/generator.d.ts +1 -0
  72. package/build/src/commands/generator.js +70 -0
  73. package/build/src/commands/source_markers.d.ts +2 -0
  74. package/build/src/commands/source_markers.js +9 -0
  75. package/build/src/core/activity.d.ts +43 -0
  76. package/build/src/core/activity.js +77 -0
  77. package/build/src/core/administration_guard.d.ts +3 -0
  78. package/build/src/core/administration_guard.js +37 -0
  79. package/build/src/core/health.d.ts +42 -0
  80. package/build/src/core/health.js +44 -0
  81. package/build/src/core/mail_test.d.ts +18 -0
  82. package/build/src/core/mail_test.js +88 -0
  83. package/build/src/core/notifications.d.ts +25 -0
  84. package/build/src/core/notifications.js +65 -0
  85. package/build/src/core/org_units.d.ts +30 -0
  86. package/build/src/core/org_units.js +123 -0
  87. package/build/src/core/roles.d.ts +72 -0
  88. package/build/src/core/roles.js +319 -0
  89. package/build/src/core/saved_views.d.ts +37 -0
  90. package/build/src/core/saved_views.js +139 -0
  91. package/build/src/core/settings.d.ts +29 -0
  92. package/build/src/core/settings.js +113 -0
  93. package/build/src/core/setup.d.ts +14 -0
  94. package/build/src/core/setup.js +89 -0
  95. package/build/src/core/ui_preferences.d.ts +12 -0
  96. package/build/src/core/ui_preferences.js +30 -0
  97. package/build/src/core/user_invitations.d.ts +23 -0
  98. package/build/src/core/user_invitations.js +144 -0
  99. package/build/src/core/users.d.ts +44 -0
  100. package/build/src/core/users.js +182 -0
  101. package/build/src/database/configure.d.ts +3 -0
  102. package/build/src/database/configure.js +41 -0
  103. package/build/src/database/schema.d.ts +7 -0
  104. package/build/src/database/schema.js +248 -0
  105. package/build/src/eslint/index.d.ts +3 -0
  106. package/build/src/eslint/index.js +64 -0
  107. package/build/src/events/adonis_jobs.d.ts +9 -0
  108. package/build/src/events/adonis_jobs.js +13 -0
  109. package/build/src/events/outbox.d.ts +18 -0
  110. package/build/src/events/outbox.js +33 -0
  111. package/build/src/events/record_mutation.d.ts +11 -0
  112. package/build/src/events/record_mutation.js +45 -0
  113. package/build/src/mcp/tools.d.ts +8 -0
  114. package/build/src/mcp/tools.js +156 -0
  115. package/build/src/org/org_service.d.ts +2 -0
  116. package/build/src/org/org_service.js +16 -0
  117. package/build/src/resource/define_resource.d.ts +4 -0
  118. package/build/src/resource/define_resource.js +48 -0
  119. package/build/src/resource/registry.d.ts +9 -0
  120. package/build/src/resource/registry.js +59 -0
  121. package/build/src/resource/types.d.ts +80 -0
  122. package/build/src/resource/types.js +1 -0
  123. package/build/src/resource/values.d.ts +5 -0
  124. package/build/src/resource/values.js +87 -0
  125. package/build/src/services/backup.d.ts +14 -0
  126. package/build/src/services/backup.js +59 -0
  127. package/build/src/services/settings.d.ts +9 -0
  128. package/build/src/services/settings.js +23 -0
  129. package/build/src/version.d.ts +1 -0
  130. package/build/src/version.js +2 -0
  131. package/build/stubs/README.md +6 -0
  132. package/build/stubs/controller.stub +8 -0
  133. package/build/stubs/main.d.ts +5 -0
  134. package/build/stubs/main.js +5 -0
  135. package/build/stubs/main.ts +5 -0
  136. package/build/stubs/modules.stub +6 -0
  137. package/build/stubs/resource_contract.stub +1 -0
  138. package/build/stubs/resource_contract.txt +390 -0
  139. package/build/stubs/routes.stub +16 -0
  140. package/build/stubs/service.stub +9 -0
  141. package/package.json +104 -0
@@ -0,0 +1,93 @@
1
+ import { subject } from '@casl/ability';
2
+ import { conditionFields } from '../auth/ability.js';
3
+ import { columnName } from '../resource/define_resource.js';
4
+ import { KitError } from './errors.js';
5
+ const standard = ['id', 'createdBy', 'updatedBy', 'createdAt', 'updatedAt', 'deletedAt'];
6
+ export function selectedFields(resource, ability, options = {}) {
7
+ return [
8
+ ...new Set([
9
+ ...standard,
10
+ ...(resource.scoped ? ['orgUnitId'] : []),
11
+ ...(resource.version ? ['version'] : []),
12
+ ...(resource.submittable ? ['docStatus', 'amendedFromId'] : []),
13
+ ...(options.write
14
+ ? Object.keys(resource.fields)
15
+ : (resource.serialize ?? [...resource.list, ...resource.show])),
16
+ ...Object.keys(resource.fields).filter((k) => resource.fields[k].type === 'belongsTo'),
17
+ ...(options.extra ?? []),
18
+ ...conditionFields(ability, resource),
19
+ ]),
20
+ ].filter((key) => key !== 'orgPath' && resource.fields[key]?.type !== 'hasMany');
21
+ }
22
+ export function fromRow(row, resource) {
23
+ const result = {};
24
+ for (const key of [
25
+ ...standard,
26
+ 'orgUnitId',
27
+ 'version',
28
+ 'docStatus',
29
+ 'amendedFromId',
30
+ 'orgPath',
31
+ ...Object.keys(resource.fields),
32
+ ]) {
33
+ const column = resource.fields[key]?.column ?? columnName(key);
34
+ if (column in row) {
35
+ const value = row[column];
36
+ result[key] =
37
+ value instanceof Date
38
+ ? resource.fields[key]?.type === 'date'
39
+ ? // pg parses DATE as local midnight. Preserve its calendar day;
40
+ // converting to UTC first shifts it in positive-offset time zones.
41
+ `${String(value.getFullYear()).padStart(4, '0')}-${String(value.getMonth() + 1).padStart(2, '0')}-${String(value.getDate()).padStart(2, '0')}`
42
+ : value.toISOString()
43
+ : value;
44
+ }
45
+ }
46
+ return result;
47
+ }
48
+ export function jsonValue(value) {
49
+ if (value === null || value === undefined)
50
+ return null;
51
+ if (typeof value === 'string' || typeof value === 'boolean')
52
+ return value;
53
+ if (typeof value === 'number' && Number.isFinite(value))
54
+ return value;
55
+ if (typeof value === 'bigint')
56
+ return value.toString();
57
+ if (value instanceof Date)
58
+ return value.toISOString();
59
+ if (Array.isArray(value))
60
+ return value.map(jsonValue);
61
+ if (typeof value === 'object')
62
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [key, jsonValue(entry)]));
63
+ throw new Error('Non-serializable resource value');
64
+ }
65
+ export function serialize(resource, record, ability, actor) {
66
+ const result = { id: jsonValue(record.id) };
67
+ const fields = resource.serialize ?? [...new Set([...resource.list, ...resource.show])];
68
+ for (const key of fields) {
69
+ const minimum = Math.max(resource.fields[key]?.permissionLevel ?? 0, resource.hidden?.includes(key) ? 1 : 0);
70
+ if (actor.permissionLevel >= minimum &&
71
+ ability.can('view', subject(resource.name, record), key) &&
72
+ key in record)
73
+ result[key] = jsonValue(record[key]);
74
+ }
75
+ if (resource.version)
76
+ result.version = jsonValue(record.version);
77
+ if (resource.submittable)
78
+ result.docStatus = jsonValue(record.docStatus);
79
+ if (resource.scoped)
80
+ result.orgUnitId = jsonValue(record.orgUnitId);
81
+ return result;
82
+ }
83
+ export function writableInput(resource, input) {
84
+ const allowed = new Set([
85
+ ...resource.form,
86
+ ...(resource.scoped ? ['orgUnitId'] : []),
87
+ ...(resource.version ? ['version'] : []),
88
+ ]);
89
+ for (const key of Object.keys(input))
90
+ if (!allowed.has(key))
91
+ throw new KitError(422, 'E_FIELD_NOT_WRITABLE', `Field is not writable: ${key}`);
92
+ return Object.fromEntries(Object.entries(input).filter(([key]) => resource.form.includes(key)));
93
+ }
@@ -0,0 +1,30 @@
1
+ import type { HttpContext } from '@adonisjs/core/http';
2
+ import type { Actor } from '../auth/ability.js';
3
+ import type { ResourceRegistry } from '../resource/registry.js';
4
+ import type { Resource } from '../resource/types.js';
5
+ import type { ResourceService } from './resource_service.js';
6
+ export type ResourceRuntime = {
7
+ registry: ResourceRegistry;
8
+ resources: ResourceService;
9
+ actor: Actor;
10
+ };
11
+ export type ResourceList = Awaited<ReturnType<ResourceService['list']>>;
12
+ export type ResourceEditor = Awaited<ReturnType<ResourceService['editor']>>;
13
+ export type ResourceShow = Awaited<ReturnType<ResourceService['show']>>;
14
+ export type ResourceChildren = Awaited<ReturnType<ResourceService['children']>>;
15
+ export type ResourceLookups = Awaited<ReturnType<ResourceService['lookups']>>;
16
+ export type ResourceActivity = Awaited<ReturnType<ResourceService['activity']>>;
17
+ export interface ResourceController {
18
+ index(ctx: HttpContext): Promise<unknown>;
19
+ show(ctx: HttpContext): Promise<unknown>;
20
+ store(ctx: HttpContext): Promise<unknown>;
21
+ update(ctx: HttpContext): Promise<unknown>;
22
+ destroy(ctx: HttpContext): Promise<unknown>;
23
+ submit(ctx: HttpContext): Promise<unknown>;
24
+ cancel(ctx: HttpContext): Promise<unknown>;
25
+ create(ctx: HttpContext): Promise<unknown>;
26
+ edit(ctx: HttpContext): Promise<unknown>;
27
+ options(ctx: HttpContext): Promise<unknown>;
28
+ }
29
+ /** The host supplies its authenticated actor; ResourceService authorizes every action. */
30
+ export declare function createResourceController(resolveRuntime: (ctx: HttpContext) => Promise<ResourceRuntime>, renderList?: (ctx: HttpContext, resource: Resource, result: ResourceList) => unknown, renderForm?: (ctx: HttpContext, resource: Resource, editor: ResourceEditor) => unknown, renderShow?: (ctx: HttpContext, resource: Resource, result: ResourceShow) => unknown): new () => ResourceController;
@@ -0,0 +1,116 @@
1
+ import { KitError } from './errors.js';
2
+ /** The host supplies its authenticated actor; ResourceService authorizes every action. */
3
+ export function createResourceController(resolveRuntime, renderList, renderForm, renderShow) {
4
+ return class ResourcesController {
5
+ async create(ctx) {
6
+ return this.#execute(ctx, async ({ resources, actor }, resource) => {
7
+ const editor = await resources.editor(resource.name, actor);
8
+ return renderForm && ctx.request.accepts(['html', 'json']) === 'html'
9
+ ? renderForm(ctx, resource, editor)
10
+ : editor;
11
+ });
12
+ }
13
+ async edit(ctx) {
14
+ return this.#execute(ctx, async ({ resources, actor }, resource) => {
15
+ const editor = await resources.editor(resource.name, actor, this.#id(ctx));
16
+ return renderForm && ctx.request.accepts(['html', 'json']) === 'html'
17
+ ? renderForm(ctx, resource, editor)
18
+ : editor;
19
+ });
20
+ }
21
+ async index(ctx) {
22
+ return this.#execute(ctx, async ({ resources, actor }, resource) => {
23
+ const result = await resources.list(resource.name, actor, {
24
+ limit: ctx.request.input('limit'),
25
+ cursor: ctx.request.input('cursor'),
26
+ search: ctx.request.input('search'),
27
+ sort: ctx.request.input('sort'),
28
+ direction: ctx.request.input('direction'),
29
+ filters: ctx.request.input('filters'),
30
+ estimate: ctx.request.input('estimate') !== 'false' && ctx.request.input('estimate') !== false,
31
+ });
32
+ return renderList && ctx.request.accepts(['html', 'json']) === 'html'
33
+ ? renderList(ctx, resource, result)
34
+ : result;
35
+ });
36
+ }
37
+ async show(ctx) {
38
+ return this.#execute(ctx, async ({ resources, actor }, resource) => {
39
+ const result = await resources.show(resource.name, this.#id(ctx), actor);
40
+ return renderShow && ctx.request.accepts(['html', 'json']) === 'html'
41
+ ? renderShow(ctx, resource, result)
42
+ : result;
43
+ });
44
+ }
45
+ async options(ctx) {
46
+ return this.#execute(ctx, ({ resources, actor }, resource) => resources.relationOptions(resource.name, ctx.params.field, actor, {
47
+ id: ctx.request.input('id') === undefined
48
+ ? undefined
49
+ : this.#positiveId(ctx.request.input('id')),
50
+ search: ctx.request.input('search'),
51
+ cursor: ctx.request.input('cursor'),
52
+ }));
53
+ }
54
+ async store(ctx) {
55
+ return this.#execute(ctx, async ({ resources, actor }, resource) => ctx.response.created({
56
+ data: await resources.save(resource.name, actor, ctx.request.body()),
57
+ }));
58
+ }
59
+ async update(ctx) {
60
+ return this.#execute(ctx, async ({ resources, actor }, resource) => ({
61
+ data: await resources.save(resource.name, actor, ctx.request.body(), this.#id(ctx)),
62
+ }));
63
+ }
64
+ async destroy(ctx) {
65
+ return this.#transition(ctx, 'delete');
66
+ }
67
+ async submit(ctx) {
68
+ return this.#transition(ctx, 'submit');
69
+ }
70
+ async cancel(ctx) {
71
+ return this.#transition(ctx, 'cancel');
72
+ }
73
+ #id(ctx) {
74
+ return this.#positiveId(ctx.params.id);
75
+ }
76
+ #positiveId(value) {
77
+ const id = Number(value);
78
+ if (!Number.isSafeInteger(id) || id <= 0)
79
+ throw new KitError(404, 'E_NOT_FOUND', 'السجل غير موجود');
80
+ return id;
81
+ }
82
+ async #transition(ctx, action) {
83
+ return this.#execute(ctx, async ({ resources, actor }, resource) => ({
84
+ data: await resources.transition(resource.name, this.#id(ctx), actor, action, ctx.request.input('version')),
85
+ }));
86
+ }
87
+ async #execute(ctx, action) {
88
+ try {
89
+ const runtime = await resolveRuntime(ctx);
90
+ let resource;
91
+ try {
92
+ resource = runtime.registry.get(ctx.params.resource);
93
+ }
94
+ catch {
95
+ throw new KitError(404, 'E_NOT_FOUND', 'الكيان غير موجود');
96
+ }
97
+ return await action(runtime, resource);
98
+ }
99
+ catch (error) {
100
+ if (error instanceof KitError)
101
+ return ctx.response
102
+ .status(error.status)
103
+ .send({ error: { code: error.code, message: error.message } });
104
+ if (error?.code === '23505')
105
+ return ctx.response.conflict({
106
+ error: { code: 'E_DUPLICATE', message: 'هذه القيمة مستخدمة في سجل آخر' },
107
+ });
108
+ if (error?.code === '23503')
109
+ return ctx.response.unprocessableEntity({
110
+ error: { code: 'E_RELATION', message: 'تحقق من السجلات المرتبطة' },
111
+ });
112
+ throw error;
113
+ }
114
+ }
115
+ };
116
+ }
@@ -0,0 +1,5 @@
1
+ export declare class KitError extends Error {
2
+ status: number;
3
+ code: string;
4
+ constructor(status: number, code: string, message: string);
5
+ }
@@ -0,0 +1,9 @@
1
+ export class KitError extends Error {
2
+ status;
3
+ code;
4
+ constructor(status, code, message) {
5
+ super(message);
6
+ this.status = status;
7
+ this.code = code;
8
+ }
9
+ }
@@ -0,0 +1,22 @@
1
+ import type { Action, Field } from '../resource/types.js';
2
+ export type ResourceField = Field & {
3
+ key: string;
4
+ };
5
+ export type RecordPermissions = Partial<Record<Action, boolean>>;
6
+ export type ResourceDescription = {
7
+ name: string;
8
+ label: string;
9
+ fields: ResourceField[];
10
+ list: string[];
11
+ show: string[];
12
+ searchable: boolean;
13
+ canCreate: boolean;
14
+ scoped: boolean;
15
+ submittable: boolean;
16
+ };
17
+ export type ResourceNavigation = {
18
+ name: string;
19
+ label: string;
20
+ href: string;
21
+ module: string;
22
+ }[];
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,170 @@
1
+ import type { Knex } from 'knex';
2
+ import type { ResourceRegistry } from '../resource/registry.js';
3
+ import type { Action, RecordData, SerializedRecord } from '../resource/types.js';
4
+ import { type Actor } from '../auth/ability.js';
5
+ import type { ResourceDescription, ResourceNavigation, ResourceField } from './presentation.js';
6
+ export type ListOptions = {
7
+ limit?: number;
8
+ cursor?: string;
9
+ search?: string;
10
+ sort?: string;
11
+ direction?: 'asc' | 'desc';
12
+ filters?: Record<string, unknown>;
13
+ estimate?: boolean;
14
+ };
15
+ export declare class ResourceService {
16
+ private db;
17
+ private registry;
18
+ constructor(db: Knex, registry: ResourceRegistry);
19
+ /** Project navigation is derived from registered resources and the current actor. */
20
+ navigation(actor: Actor): ResourceNavigation;
21
+ describe(name: string, actor: Actor): ResourceDescription;
22
+ private permissions;
23
+ private normalizeValues;
24
+ /** Stored attachment ids become summaries for readers; copies keep policy checks on raw rows. */
25
+ private hydrate;
26
+ private hydrateOne;
27
+ private authorizeAction;
28
+ private scopedQuery;
29
+ private columns;
30
+ private find;
31
+ private requireRecord;
32
+ list(name: string, actor: Actor, options?: ListOptions): Promise<{
33
+ data: SerializedRecord[];
34
+ permissions: {
35
+ [k: string]: Partial<Record<Action, boolean>>;
36
+ };
37
+ meta: {
38
+ limit: number;
39
+ estimatedTotal: number | undefined;
40
+ nextCursor: string | null;
41
+ };
42
+ related: Record<string, SerializedRecord[]>;
43
+ }>;
44
+ private canQueryField;
45
+ private preload;
46
+ show(name: string, id: number, actor: Actor): Promise<{
47
+ data: SerializedRecord;
48
+ permissions: Partial<Record<Action, boolean>>;
49
+ related: Record<string, SerializedRecord[]>;
50
+ }>;
51
+ relationOptions(name: string, key: string, actor: Actor, options?: {
52
+ id?: number;
53
+ search?: string;
54
+ cursor?: string;
55
+ }): Promise<{
56
+ data: {
57
+ value: string;
58
+ label: string;
59
+ }[];
60
+ nextCursor: string | null;
61
+ }>;
62
+ /** Deferred relation reads re-authorize the parent and each child on every request. */
63
+ children(name: string, id: number, actor: Actor): Promise<Record<string, {
64
+ rows: SerializedRecord[];
65
+ hasMore: boolean;
66
+ }>>;
67
+ /** Active lookup labels for the lookup fields the actor may read on this resource. */
68
+ lookups(name: string, actor: Actor): Promise<Record<string, {
69
+ value: string;
70
+ label: string;
71
+ }[]>>;
72
+ /** The last 50 recorded mutations of one record, after authorizing the record itself. */
73
+ activity(name: string, id: number, actor: Actor): Promise<{
74
+ id: number;
75
+ action: Action;
76
+ fields: string[];
77
+ actorId: number;
78
+ actorEmail: string | null;
79
+ createdAt: string;
80
+ }[]>;
81
+ editor(name: string, actor: Actor, id?: number): Promise<{
82
+ mode: string;
83
+ name: string;
84
+ label: string;
85
+ fields: ({
86
+ label: import("../resource/types.js").Label;
87
+ column?: string;
88
+ required?: boolean;
89
+ unique?: boolean;
90
+ sortable?: boolean;
91
+ searchable?: boolean;
92
+ filterable?: boolean;
93
+ permissionLevel?: number;
94
+ sequence?: string;
95
+ type: "string" | "text" | "integer" | "money" | "boolean" | "date" | "datetime" | "json" | "attachment";
96
+ key: string;
97
+ } | {
98
+ label: import("../resource/types.js").Label;
99
+ column?: string;
100
+ required?: boolean;
101
+ unique?: boolean;
102
+ sortable?: boolean;
103
+ searchable?: boolean;
104
+ filterable?: boolean;
105
+ permissionLevel?: number;
106
+ sequence?: string;
107
+ type: "belongsTo";
108
+ resource: string;
109
+ key: string;
110
+ } | {
111
+ label: import("../resource/types.js").Label;
112
+ column?: string;
113
+ required?: boolean;
114
+ unique?: boolean;
115
+ sortable?: boolean;
116
+ searchable?: boolean;
117
+ filterable?: boolean;
118
+ permissionLevel?: number;
119
+ sequence?: string;
120
+ type: "hasMany";
121
+ resource: string;
122
+ foreignKey: string;
123
+ inline?: boolean;
124
+ key: string;
125
+ } | {
126
+ label: import("../resource/types.js").Label;
127
+ column?: string;
128
+ required?: boolean;
129
+ unique?: boolean;
130
+ sortable?: boolean;
131
+ searchable?: boolean;
132
+ filterable?: boolean;
133
+ permissionLevel?: number;
134
+ sequence?: string;
135
+ type: "lookup";
136
+ group: string;
137
+ key: string;
138
+ })[];
139
+ inline: Record<string, {
140
+ rows: SerializedRecord[];
141
+ hasMore: boolean;
142
+ canCreate: boolean;
143
+ permissions: Record<string, {
144
+ update: boolean;
145
+ delete: boolean;
146
+ }>;
147
+ fields: ResourceField[];
148
+ createFields: string[];
149
+ updateFields: Record<string, string[]>;
150
+ }>;
151
+ options: Record<string, {
152
+ value: string;
153
+ label: string;
154
+ }[]>;
155
+ relationSearch: Record<string, boolean>;
156
+ orgUnits: {
157
+ value: string;
158
+ label: string;
159
+ }[];
160
+ scoped: boolean;
161
+ record: SerializedRecord | null;
162
+ }>;
163
+ save(name: string, actor: Actor, input: RecordData, id?: number, transaction?: Knex.Transaction): Promise<SerializedRecord>;
164
+ private persist;
165
+ private requireVersion;
166
+ /** Inline children share the parent's draft state, organization and update authority. */
167
+ private requireInlineParents;
168
+ transition(name: string, id: number, actor: Actor, action: 'delete' | 'submit' | 'cancel', version?: unknown, transaction?: Knex.Transaction): Promise<SerializedRecord>;
169
+ private audit;
170
+ }