@adula/kit 0.2.0-alpha.4 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -2
- package/build/agent/AGENTS.template.md +2 -2
- package/build/agent/capabilities.md +54 -7
- package/build/agent/skills/adula-frontend-design/SKILL.md +1 -1
- package/build/agent/skills/idea-review/SKILL.md +26 -1
- package/build/agent/skills/module-review/SKILL.md +22 -0
- package/build/agent/skills/perf-review/SKILL.md +24 -0
- package/build/agent/skills/schema-review/SKILL.md +22 -0
- package/build/agent/skills/security-review/SKILL.md +24 -0
- package/build/agent/skills/ui-review/SKILL.md +22 -0
- package/build/commands/capabilities.d.ts +4 -0
- package/build/commands/capabilities.js +35 -4
- package/build/commands/doctor.js +37 -1
- package/build/commands/gaps.js +16 -6
- package/build/commands/install.js +19 -5
- package/build/commands/main.d.ts +4 -2
- package/build/commands/main.js +2 -0
- package/build/commands/module_add.js +2 -2
- package/build/commands/resource.js +1 -1
- package/build/commands/resource_snapshot.d.ts +15 -0
- package/build/commands/resource_snapshot.js +61 -0
- package/build/database/migrations/1770000000004_kit_collaboration.d.ts +5 -0
- package/build/database/migrations/1770000000004_kit_collaboration.js +10 -0
- package/build/database/migrations/1770000000005_kit_assignments.d.ts +5 -0
- package/build/database/migrations/1770000000005_kit_assignments.js +10 -0
- package/build/database/migrations/1770000000006_kit_messaging.d.ts +5 -0
- package/build/database/migrations/1770000000006_kit_messaging.js +10 -0
- package/build/database/migrations/1770000000007_kit_webhooks.d.ts +5 -0
- package/build/database/migrations/1770000000007_kit_webhooks.js +10 -0
- package/build/database/migrations/1770000000008_kit_imports.d.ts +5 -0
- package/build/database/migrations/1770000000008_kit_imports.js +10 -0
- package/build/database/migrations/1770000000010_kit_workflows.d.ts +5 -0
- package/build/database/migrations/1770000000010_kit_workflows.js +10 -0
- package/build/database/migrations/1770000000011_kit_managed_assignments.d.ts +5 -0
- package/build/database/migrations/1770000000011_kit_managed_assignments.js +10 -0
- package/build/database/migrations/1770000000012_kit_role_keys.d.ts +5 -0
- package/build/database/migrations/1770000000012_kit_role_keys.js +10 -0
- package/build/database/migrations/1770000000013_kit_notification_targets.d.ts +5 -0
- package/build/database/migrations/1770000000013_kit_notification_targets.js +10 -0
- package/build/database/migrations/1770000000014_kit_upload_grants.d.ts +5 -0
- package/build/database/migrations/1770000000014_kit_upload_grants.js +10 -0
- package/build/database/migrations/1770000000015_kit_inbound_webhooks.d.ts +5 -0
- package/build/database/migrations/1770000000015_kit_inbound_webhooks.js +10 -0
- package/build/index.d.ts +31 -2
- package/build/index.js +17 -2
- package/build/src/admin/contracts.d.ts +7 -0
- package/build/src/admin/contracts.js +34 -12
- package/build/src/admin/controller.d.ts +2 -0
- package/build/src/admin/controller.js +52 -1
- package/build/src/admin/presentation.d.ts +6 -0
- package/build/src/admin/record_title.d.ts +14 -0
- package/build/src/admin/record_title.js +50 -0
- package/build/src/admin/resource_service.d.ts +184 -2
- package/build/src/admin/resource_service.js +713 -48
- package/build/src/attachments/attachment_service.d.ts +12 -0
- package/build/src/attachments/attachment_service.js +28 -2
- package/build/src/attachments/upload_grants.d.ts +44 -0
- package/build/src/attachments/upload_grants.js +105 -0
- package/build/src/auth/ability.d.ts +1 -1
- package/build/src/auth/ability.js +4 -1
- package/build/src/auth/actor_store.js +6 -1
- package/build/src/auth/conditions.d.ts +15 -0
- package/build/src/auth/conditions.js +36 -0
- package/build/src/auth/sql.js +6 -2
- package/build/src/collaboration/assignments.d.ts +129 -0
- package/build/src/collaboration/assignments.js +333 -0
- package/build/src/collaboration/record_collaboration.d.ts +86 -0
- package/build/src/collaboration/record_collaboration.js +348 -0
- package/build/src/commands/agent_assets.js +5 -0
- package/build/src/commands/capabilities.d.ts +19 -0
- package/build/src/commands/capabilities.js +179 -0
- package/build/src/commands/doctor.d.ts +31 -0
- package/build/src/commands/doctor.js +114 -0
- package/build/src/commands/gap_report.d.ts +50 -2
- package/build/src/commands/gap_report.js +102 -4
- package/build/src/commands/generator.js +3 -3
- package/build/src/commands/snapshot.d.ts +28 -0
- package/build/src/commands/snapshot.js +48 -0
- package/build/src/commands/source_markers.d.ts +10 -1
- package/build/src/commands/source_markers.js +36 -4
- package/build/src/core/administration_guard.js +3 -1
- package/build/src/core/message_templates.d.ts +83 -0
- package/build/src/core/message_templates.js +293 -0
- package/build/src/core/module_seed.d.ts +15 -0
- package/build/src/core/module_seed.js +31 -0
- package/build/src/core/notifications.d.ts +18 -1
- package/build/src/core/notifications.js +27 -1
- package/build/src/core/roles.d.ts +27 -1
- package/build/src/core/roles.js +133 -5
- package/build/src/database/schema.d.ts +45 -0
- package/build/src/database/schema.js +290 -0
- package/build/src/eslint/index.js +26 -0
- package/build/src/events/outbox.d.ts +1 -0
- package/build/src/events/outbox.js +1 -1
- package/build/src/events/record_mutation.d.ts +11 -0
- package/build/src/events/record_mutation.js +15 -2
- package/build/src/integrations/imports.d.ts +74 -0
- package/build/src/integrations/imports.js +333 -0
- package/build/src/integrations/inbound_webhooks.d.ts +94 -0
- package/build/src/integrations/inbound_webhooks.js +276 -0
- package/build/src/integrations/openapi.d.ts +39 -0
- package/build/src/integrations/openapi.js +323 -0
- package/build/src/integrations/print.d.ts +37 -0
- package/build/src/integrations/print.js +124 -0
- package/build/src/integrations/webhooks.d.ts +98 -0
- package/build/src/integrations/webhooks.js +298 -0
- package/build/src/resource/define_resource.d.ts +1 -0
- package/build/src/resource/define_resource.js +21 -1
- package/build/src/resource/registry.d.ts +3 -0
- package/build/src/resource/registry.js +42 -0
- package/build/src/resource/types.d.ts +67 -1
- package/build/src/resource/values.js +2 -1
- package/build/src/services/settings.d.ts +13 -1
- package/build/src/services/settings.js +9 -2
- package/build/src/workflows/define_workflow.d.ts +124 -0
- package/build/src/workflows/define_workflow.js +123 -0
- package/build/src/workflows/engine.d.ts +141 -0
- package/build/src/workflows/engine.js +752 -0
- package/build/stubs/resource_contract.txt +103 -41
- package/package.json +7 -3
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
2
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
3
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
4
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
5
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
6
|
+
};
|
|
7
|
+
import { BaseCommand, args } from '@adonisjs/core/ace';
|
|
8
|
+
import { readFile, writeFile } from 'node:fs/promises';
|
|
9
|
+
import { MigrationRunner } from '@adonisjs/lucid/migration';
|
|
10
|
+
import { embeddedResource, resourceSnapshot, rewriteResourceSnapshot, } from '../src/commands/snapshot.js';
|
|
11
|
+
/**
|
|
12
|
+
* Rewrites the definition embedded in a resource's generated create-migration from the
|
|
13
|
+
* current resource, while that migration has not run yet (#20). A migration that already
|
|
14
|
+
* ran is never edited: change the table with a new expand migration instead.
|
|
15
|
+
*/
|
|
16
|
+
export default class ResourceSnapshot extends BaseCommand {
|
|
17
|
+
static commandName = 'adula:resource:snapshot';
|
|
18
|
+
static description = "Refresh a pending generated create-migration from the resource's current definition";
|
|
19
|
+
static options = { startApp: true };
|
|
20
|
+
async run() {
|
|
21
|
+
const { default: db } = await import('@adonisjs/lucid/services/db');
|
|
22
|
+
const { registry } = (await this.app.import('#start/modules'));
|
|
23
|
+
let resource;
|
|
24
|
+
try {
|
|
25
|
+
resource = registry.get(this.name);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
this.logger.error(`Unknown resource: ${this.name}. Register it in its module first.`);
|
|
29
|
+
this.exitCode = 1;
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const migrations = await new MigrationRunner(db, this.app, { direction: 'up' }).getList();
|
|
33
|
+
const matches = [];
|
|
34
|
+
for (const entry of migrations)
|
|
35
|
+
for (const extension of ['.ts', '.js'])
|
|
36
|
+
try {
|
|
37
|
+
const file = `${entry.name}${extension}`;
|
|
38
|
+
const source = await readFile(this.app.makePath(file), 'utf8');
|
|
39
|
+
if (embeddedResource(source) === this.name)
|
|
40
|
+
matches.push({ file, source, pending: entry.status === 'pending' });
|
|
41
|
+
break;
|
|
42
|
+
}
|
|
43
|
+
catch { }
|
|
44
|
+
const pending = matches.filter((match) => match.pending);
|
|
45
|
+
if (!pending.length) {
|
|
46
|
+
this.logger.error(matches.length
|
|
47
|
+
? `${matches[0].file} already ran; never edit it. Add an expand migration for the new columns instead.`
|
|
48
|
+
: `No generated create-migration embeds ${this.name}.`);
|
|
49
|
+
this.exitCode = 1;
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
for (const match of pending) {
|
|
53
|
+
await writeFile(this.app.makePath(match.file), rewriteResourceSnapshot(match.source, resourceSnapshot(resource)));
|
|
54
|
+
this.logger.success(match.file);
|
|
55
|
+
}
|
|
56
|
+
this.logger.info('Update the model, factory and contract fixture to the same fields, then run migration:run.');
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
__decorate([
|
|
60
|
+
args.string({ description: 'Resource name' })
|
|
61
|
+
], ResourceSnapshot.prototype, "name", void 0);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createCollaborationSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitCollaboration extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createCollaborationSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createAssignmentsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitAssignments extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createAssignmentsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createMessagingSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitMessaging extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createMessagingSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createWebhooksSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitWebhooks extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createWebhooksSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createImportsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitImports extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createImportsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createWorkflowSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitWorkflows extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createWorkflowSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createManagedAssignmentsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitManagedAssignments extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createManagedAssignmentsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createRoleKeysSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitRoleKeys extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createRoleKeysSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createNotificationTargetsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitNotificationTargets extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createNotificationTargetsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createUploadGrantsSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitUploadGrants extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createUploadGrantsSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BaseSchema } from '@adonisjs/lucid/schema';
|
|
2
|
+
import { createInboundWebhooksSchema } from '../../src/database/schema.js';
|
|
3
|
+
export default class KitInboundWebhooks extends BaseSchema {
|
|
4
|
+
async up() {
|
|
5
|
+
await createInboundWebhooksSchema(this.db.getWriteClient());
|
|
6
|
+
}
|
|
7
|
+
async down() {
|
|
8
|
+
throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
|
|
9
|
+
}
|
|
10
|
+
}
|
package/build/index.d.ts
CHANGED
|
@@ -11,16 +11,41 @@ export { packedResourceRules } from './src/auth/packed_rules.js';
|
|
|
11
11
|
export type { Actor, Rule, KitAbility } from './src/auth/ability.js';
|
|
12
12
|
export { ActorStore } from './src/auth/actor_store.js';
|
|
13
13
|
export { accessibleBy, authorizationSql, conditionSql } from './src/auth/sql.js';
|
|
14
|
-
export {
|
|
14
|
+
export { ACTOR_ID, resolveActorConditions } from './src/auth/conditions.js';
|
|
15
|
+
export { ResourceService, canQueryField } from './src/admin/resource_service.js';
|
|
16
|
+
export type { AggregateOptions, AggregateRow, ListOptions } from './src/admin/resource_service.js';
|
|
15
17
|
export { serialize, writableInput, selectedFields } from './src/admin/contracts.js';
|
|
16
18
|
export { KitError } from './src/admin/errors.js';
|
|
17
|
-
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, } from './src/database/schema.js';
|
|
19
|
+
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, createCollaborationSchema, createAssignmentsSchema, createMessagingSchema, createWebhooksSchema, createImportsSchema, createWorkflowSchema, createManagedAssignmentsSchema, createRoleKeysSchema, createNotificationTargetsSchema, createUploadGrantsSchema, createInboundWebhooksSchema, } from './src/database/schema.js';
|
|
20
|
+
export { defineWorkflow, nextStep } from './src/workflows/define_workflow.js';
|
|
21
|
+
export type { WorkflowDefinition, WorkflowInput, WorkflowStep, WorkflowEvent, StepContext, Recipients, DecisionOutcome, } from './src/workflows/define_workflow.js';
|
|
22
|
+
export { WorkflowEngine, workflowListeners } from './src/workflows/engine.js';
|
|
23
|
+
export type { WorkflowRun, WorkflowRunStatus, WorkflowOptions, WorkflowDecisionForm, } from './src/workflows/engine.js';
|
|
24
|
+
export { ImportBatches, importCell, IMPORT_ROW_LIMIT } from './src/integrations/imports.js';
|
|
25
|
+
export type { ImportBatch, ImportStatus, ImportTarget, ActorSource, } from './src/integrations/imports.js';
|
|
26
|
+
export { openApiDocument } from './src/integrations/openapi.js';
|
|
27
|
+
export { renderPrintHtml, htmlToPdf } from './src/integrations/print.js';
|
|
28
|
+
export type { PrintIdentity, PrintInput } from './src/integrations/print.js';
|
|
29
|
+
export { Webhooks, signWebhook, WEBHOOK_MAX_ATTEMPTS } from './src/integrations/webhooks.js';
|
|
30
|
+
export { InboundWebhooks, inboundEventName, INBOUND_BODY_LIMIT, INBOUND_RETENTION_DAYS, } from './src/integrations/inbound_webhooks.js';
|
|
31
|
+
export type { InboundSource, InboundSourceInput, InboundDelivery, InboundReceipt, } from './src/integrations/inbound_webhooks.js';
|
|
32
|
+
export type { SecretBox, Webhook, WebhookDelivery, WebhookOptions, HttpPoster, } from './src/integrations/webhooks.js';
|
|
33
|
+
export { MessageTemplates, DEFAULT_TEMPLATES, renderTemplate, notifyWithTemplate, deliverNotificationMail, listenForNotifications, } from './src/core/message_templates.js';
|
|
34
|
+
export type { TemplateDefinition, MessageTemplate, RenderedMessage, MailSender, NotificationSignal, } from './src/core/message_templates.js';
|
|
35
|
+
export { Assignments } from './src/collaboration/assignments.js';
|
|
36
|
+
export type { Assignment, AssignmentPage, AssignmentOptions, CloseNotePolicy, AssignmentStatus, } from './src/collaboration/assignments.js';
|
|
37
|
+
export { RecordCollaboration, followerListeners } from './src/collaboration/record_collaboration.js';
|
|
38
|
+
export type { ActorLoader, CommentEntry, FieldChangeEntry, RecordCollaborationState, MentionCandidate, } from './src/collaboration/record_collaboration.js';
|
|
39
|
+
export type { FieldChange } from './src/events/record_mutation.js';
|
|
18
40
|
export { registerUpload, findAttachment, loadAttachments, claimAttachment, releaseAttachment, summarizeAttachment, attachmentUrl, isAttachmentId, isRelativeDiskPath, attachmentPolicy, pendingUploadCount, staleUploads, forgetUpload, DEFAULT_ATTACHMENT_EXTENSIONS, PENDING_UPLOAD_LIMIT, UNBOUND_UPLOAD_TTL_MS, } from './src/attachments/attachment_service.js';
|
|
19
41
|
export type { AttachmentRecord, AttachmentSummary, UploadInput, ClaimInput, } from './src/attachments/attachment_service.js';
|
|
42
|
+
export { grantUpload, redeemUploadGrant, pruneUploadGrants, UPLOAD_GRANT_MAX_TTL_MS, } from './src/attachments/upload_grants.js';
|
|
43
|
+
export type { UploadGrantInput, UploadGrant, RedeemedUploadGrant, } from './src/attachments/upload_grants.js';
|
|
20
44
|
export { migrateStorage } from './src/attachments/storage_migrate.js';
|
|
21
45
|
export type { StorageDisk, StorageMigrationOptions, StorageMigrationResult, } from './src/attachments/storage_migrate.js';
|
|
22
46
|
export { diagnoseAttachments } from './src/attachments/doctor.js';
|
|
23
47
|
export { Settings, sequence, notify } from './src/services/settings.js';
|
|
48
|
+
export type { NotificationTarget } from './src/services/settings.js';
|
|
24
49
|
export { uiPreferences, validateUiPreferences, UI_PREFERENCES_KEY, DEFAULT_UI_PREFERENCES, } from './src/core/ui_preferences.js';
|
|
25
50
|
export type { UiPreferences, CalendarSystem, CalendarPreference, } from './src/core/ui_preferences.js';
|
|
26
51
|
export { moveOrgUnit } from './src/org/org_service.js';
|
|
@@ -33,6 +58,8 @@ export type { BackupObject, BackupStatus } from './src/services/backup.js';
|
|
|
33
58
|
export { ActivityAdmin, logActivity } from './src/core/activity.js';
|
|
34
59
|
export type { ActivityEntry, ActivityFilters, ActivityPage, ActivityRow, } from './src/core/activity.js';
|
|
35
60
|
export { RolesAdmin, ALL_SUBJECT_LABEL } from './src/core/roles.js';
|
|
61
|
+
export { seedModules } from './src/core/module_seed.js';
|
|
62
|
+
export type { ModuleSeedResult } from './src/core/module_seed.js';
|
|
36
63
|
export type { RoleSummary, RoleDetail, RoleRule, RuleInput, RoleMatrix, MatrixSubject, MatrixField, } from './src/core/roles.js';
|
|
37
64
|
export { UsersAdmin } from './src/core/users.js';
|
|
38
65
|
export { UserInvitations, type InvitationDelivery } from './src/core/user_invitations.js';
|
|
@@ -49,3 +76,5 @@ export { runtimeHealth, isBackupStale, backupStale, heartbeat, HEARTBEAT_MAX_AGE
|
|
|
49
76
|
export type { RuntimeHealth, HeartbeatStatus, QueueSnapshot, QueueCounts, FailedJob, } from './src/core/health.js';
|
|
50
77
|
export { MailDeliveryTest, MAIL_TEST_KEY, type MailTestState } from './src/core/mail_test.js';
|
|
51
78
|
export { InitialSetup, type SetupCheck } from './src/core/setup.js';
|
|
79
|
+
export { KIT_VERSION } from './src/version.js';
|
|
80
|
+
export { capabilityCatalog, SERVICES as CAPABILITY_SERVICES, FIELD_TYPES, WORKFLOW_STEPS, } from './src/commands/capabilities.js';
|
package/build/index.js
CHANGED
|
@@ -7,11 +7,23 @@ export { buildAbility, canRecord, inOrgScope } from './src/auth/ability.js';
|
|
|
7
7
|
export { packedResourceRules } from './src/auth/packed_rules.js';
|
|
8
8
|
export { ActorStore } from './src/auth/actor_store.js';
|
|
9
9
|
export { accessibleBy, authorizationSql, conditionSql } from './src/auth/sql.js';
|
|
10
|
-
export {
|
|
10
|
+
export { ACTOR_ID, resolveActorConditions } from './src/auth/conditions.js';
|
|
11
|
+
export { ResourceService, canQueryField } from './src/admin/resource_service.js';
|
|
11
12
|
export { serialize, writableInput, selectedFields } from './src/admin/contracts.js';
|
|
12
13
|
export { KitError } from './src/admin/errors.js';
|
|
13
|
-
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, } from './src/database/schema.js';
|
|
14
|
+
export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, createCollaborationSchema, createAssignmentsSchema, createMessagingSchema, createWebhooksSchema, createImportsSchema, createWorkflowSchema, createManagedAssignmentsSchema, createRoleKeysSchema, createNotificationTargetsSchema, createUploadGrantsSchema, createInboundWebhooksSchema, } from './src/database/schema.js';
|
|
15
|
+
export { defineWorkflow, nextStep } from './src/workflows/define_workflow.js';
|
|
16
|
+
export { WorkflowEngine, workflowListeners } from './src/workflows/engine.js';
|
|
17
|
+
export { ImportBatches, importCell, IMPORT_ROW_LIMIT } from './src/integrations/imports.js';
|
|
18
|
+
export { openApiDocument } from './src/integrations/openapi.js';
|
|
19
|
+
export { renderPrintHtml, htmlToPdf } from './src/integrations/print.js';
|
|
20
|
+
export { Webhooks, signWebhook, WEBHOOK_MAX_ATTEMPTS } from './src/integrations/webhooks.js';
|
|
21
|
+
export { InboundWebhooks, inboundEventName, INBOUND_BODY_LIMIT, INBOUND_RETENTION_DAYS, } from './src/integrations/inbound_webhooks.js';
|
|
22
|
+
export { MessageTemplates, DEFAULT_TEMPLATES, renderTemplate, notifyWithTemplate, deliverNotificationMail, listenForNotifications, } from './src/core/message_templates.js';
|
|
23
|
+
export { Assignments } from './src/collaboration/assignments.js';
|
|
24
|
+
export { RecordCollaboration, followerListeners } from './src/collaboration/record_collaboration.js';
|
|
14
25
|
export { registerUpload, findAttachment, loadAttachments, claimAttachment, releaseAttachment, summarizeAttachment, attachmentUrl, isAttachmentId, isRelativeDiskPath, attachmentPolicy, pendingUploadCount, staleUploads, forgetUpload, DEFAULT_ATTACHMENT_EXTENSIONS, PENDING_UPLOAD_LIMIT, UNBOUND_UPLOAD_TTL_MS, } from './src/attachments/attachment_service.js';
|
|
26
|
+
export { grantUpload, redeemUploadGrant, pruneUploadGrants, UPLOAD_GRANT_MAX_TTL_MS, } from './src/attachments/upload_grants.js';
|
|
15
27
|
export { migrateStorage } from './src/attachments/storage_migrate.js';
|
|
16
28
|
export { diagnoseAttachments } from './src/attachments/doctor.js';
|
|
17
29
|
export { Settings, sequence, notify } from './src/services/settings.js';
|
|
@@ -23,6 +35,7 @@ export { recordMutation } from './src/events/record_mutation.js';
|
|
|
23
35
|
export { assessBackup, verifyBackup } from './src/services/backup.js';
|
|
24
36
|
export { ActivityAdmin, logActivity } from './src/core/activity.js';
|
|
25
37
|
export { RolesAdmin, ALL_SUBJECT_LABEL } from './src/core/roles.js';
|
|
38
|
+
export { seedModules } from './src/core/module_seed.js';
|
|
26
39
|
export { UsersAdmin } from './src/core/users.js';
|
|
27
40
|
export { UserInvitations } from './src/core/user_invitations.js';
|
|
28
41
|
export { OrgUnitsAdmin } from './src/core/org_units.js';
|
|
@@ -32,3 +45,5 @@ export { SettingsAdmin, isProtectedSetting, parseSettingValue, SETTING_SCOPES, P
|
|
|
32
45
|
export { runtimeHealth, isBackupStale, backupStale, heartbeat, HEARTBEAT_MAX_AGE_MS, BACKUP_MAX_AGE_MS, } from './src/core/health.js';
|
|
33
46
|
export { MailDeliveryTest, MAIL_TEST_KEY } from './src/core/mail_test.js';
|
|
34
47
|
export { InitialSetup } from './src/core/setup.js';
|
|
48
|
+
export { KIT_VERSION } from './src/version.js';
|
|
49
|
+
export { capabilityCatalog, SERVICES as CAPABILITY_SERVICES, FIELD_TYPES, WORKFLOW_STEPS, } from './src/commands/capabilities.js';
|
|
@@ -10,3 +10,10 @@ export declare function serialize(resource: Resource, record: RecordData, abilit
|
|
|
10
10
|
export declare function writableInput(resource: Resource, input: RecordData): {
|
|
11
11
|
[k: string]: unknown;
|
|
12
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* Values module code may write through ResourceService.systemSave: every stored field
|
|
15
|
+
* except sequences and inline children, plus the organization unit when it is not inherited.
|
|
16
|
+
*/
|
|
17
|
+
export declare function systemInput(resource: Resource, input: RecordData): {
|
|
18
|
+
[k: string]: unknown;
|
|
19
|
+
};
|
|
@@ -13,24 +13,33 @@ export function selectedFields(resource, ability, options = {}) {
|
|
|
13
13
|
...(options.write
|
|
14
14
|
? Object.keys(resource.fields)
|
|
15
15
|
: (resource.serialize ?? [...resource.list, ...resource.show])),
|
|
16
|
-
...Object.keys(resource.fields).filter((k) => resource.fields[k].type
|
|
16
|
+
...Object.keys(resource.fields).filter((k) => ['belongsTo', 'user'].includes(resource.fields[k].type)),
|
|
17
17
|
...(options.extra ?? []),
|
|
18
18
|
...conditionFields(ability, resource),
|
|
19
19
|
]),
|
|
20
20
|
].filter((key) => key !== 'orgPath' && resource.fields[key]?.type !== 'hasMany');
|
|
21
21
|
}
|
|
22
|
+
const rowKeys = new WeakMap();
|
|
23
|
+
/** Record keys and their columns for a resource, computed once per definition. */
|
|
24
|
+
function keysOf(resource) {
|
|
25
|
+
let keys = rowKeys.get(resource);
|
|
26
|
+
if (!keys) {
|
|
27
|
+
keys = [
|
|
28
|
+
...standard,
|
|
29
|
+
'orgUnitId',
|
|
30
|
+
'version',
|
|
31
|
+
'docStatus',
|
|
32
|
+
'amendedFromId',
|
|
33
|
+
'orgPath',
|
|
34
|
+
...Object.keys(resource.fields),
|
|
35
|
+
].map((key) => [key, resource.fields[key]?.column ?? columnName(key)]);
|
|
36
|
+
rowKeys.set(resource, keys);
|
|
37
|
+
}
|
|
38
|
+
return keys;
|
|
39
|
+
}
|
|
22
40
|
export function fromRow(row, resource) {
|
|
23
41
|
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);
|
|
42
|
+
for (const [key, column] of keysOf(resource)) {
|
|
34
43
|
if (column in row) {
|
|
35
44
|
const value = row[column];
|
|
36
45
|
result[key] =
|
|
@@ -83,7 +92,7 @@ export function serialize(resource, record, ability, actor) {
|
|
|
83
92
|
export function writableInput(resource, input) {
|
|
84
93
|
const allowed = new Set([
|
|
85
94
|
...resource.form,
|
|
86
|
-
...(resource.scoped ? ['orgUnitId'] : []),
|
|
95
|
+
...(resource.scoped && !resource.scope ? ['orgUnitId'] : []),
|
|
87
96
|
...(resource.version ? ['version'] : []),
|
|
88
97
|
]);
|
|
89
98
|
for (const key of Object.keys(input))
|
|
@@ -91,3 +100,16 @@ export function writableInput(resource, input) {
|
|
|
91
100
|
throw new KitError(422, 'E_FIELD_NOT_WRITABLE', `Field is not writable: ${key}`);
|
|
92
101
|
return Object.fromEntries(Object.entries(input).filter(([key]) => resource.form.includes(key)));
|
|
93
102
|
}
|
|
103
|
+
/**
|
|
104
|
+
* Values module code may write through ResourceService.systemSave: every stored field
|
|
105
|
+
* except sequences and inline children, plus the organization unit when it is not inherited.
|
|
106
|
+
*/
|
|
107
|
+
export function systemInput(resource, input) {
|
|
108
|
+
for (const key of Object.keys(input)) {
|
|
109
|
+
const field = resource.fields[key];
|
|
110
|
+
const unit = key === 'orgUnitId' && resource.scoped && !resource.scope;
|
|
111
|
+
if (!unit && (!field || field.type === 'hasMany' || field.sequence))
|
|
112
|
+
throw new KitError(422, 'E_FIELD_NOT_WRITABLE', `Field is not writable: ${key}`);
|
|
113
|
+
}
|
|
114
|
+
return Object.fromEntries(Object.entries(input).filter(([key]) => key in resource.fields));
|
|
115
|
+
}
|
|
@@ -22,9 +22,11 @@ export interface ResourceController {
|
|
|
22
22
|
destroy(ctx: HttpContext): Promise<unknown>;
|
|
23
23
|
submit(ctx: HttpContext): Promise<unknown>;
|
|
24
24
|
cancel(ctx: HttpContext): Promise<unknown>;
|
|
25
|
+
amend(ctx: HttpContext): Promise<unknown>;
|
|
25
26
|
create(ctx: HttpContext): Promise<unknown>;
|
|
26
27
|
edit(ctx: HttpContext): Promise<unknown>;
|
|
27
28
|
options(ctx: HttpContext): Promise<unknown>;
|
|
29
|
+
aggregate(ctx: HttpContext): Promise<unknown>;
|
|
28
30
|
}
|
|
29
31
|
/** The host supplies its authenticated actor; ResourceService authorizes every action. */
|
|
30
32
|
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;
|
|
@@ -4,7 +4,13 @@ export function createResourceController(resolveRuntime, renderList, renderForm,
|
|
|
4
4
|
return class ResourcesController {
|
|
5
5
|
async create(ctx) {
|
|
6
6
|
return this.#execute(ctx, async ({ resources, actor }, resource) => {
|
|
7
|
-
|
|
7
|
+
// `?defaults[field]=value` pre-fills the form; the service authorizes each value.
|
|
8
|
+
const defaults = ctx.request.qs().defaults;
|
|
9
|
+
const editor = await resources.editor(resource.name, actor, undefined, {
|
|
10
|
+
defaults: defaults && typeof defaults === 'object' && !Array.isArray(defaults)
|
|
11
|
+
? defaults
|
|
12
|
+
: undefined,
|
|
13
|
+
});
|
|
8
14
|
return renderForm && ctx.request.accepts(['html', 'json']) === 'html'
|
|
9
15
|
? renderForm(ctx, resource, editor)
|
|
10
16
|
: editor;
|
|
@@ -27,6 +33,7 @@ export function createResourceController(resolveRuntime, renderList, renderForm,
|
|
|
27
33
|
sort: ctx.request.input('sort'),
|
|
28
34
|
direction: ctx.request.input('direction'),
|
|
29
35
|
filters: ctx.request.input('filters'),
|
|
36
|
+
tag: ctx.request.input('tag'),
|
|
30
37
|
estimate: ctx.request.input('estimate') !== 'false' && ctx.request.input('estimate') !== false,
|
|
31
38
|
});
|
|
32
39
|
return renderList && ctx.request.accepts(['html', 'json']) === 'html'
|
|
@@ -49,8 +56,47 @@ export function createResourceController(resolveRuntime, renderList, renderForm,
|
|
|
49
56
|
: this.#positiveId(ctx.request.input('id')),
|
|
50
57
|
search: ctx.request.input('search'),
|
|
51
58
|
cursor: ctx.request.input('cursor'),
|
|
59
|
+
orgUnitId: ctx.request.input('orgUnitId') === undefined || ctx.request.input('orgUnitId') === ''
|
|
60
|
+
? undefined
|
|
61
|
+
: this.#positiveId(ctx.request.input('orgUnitId')),
|
|
62
|
+
purpose: ctx.request.input('purpose') === 'filter' ? 'filter' : 'form',
|
|
52
63
|
}));
|
|
53
64
|
}
|
|
65
|
+
/**
|
|
66
|
+
* GET …/aggregate?groupBy=status,priority&sum=total&filters[x]=…&where={json}
|
|
67
|
+
* Counts and totals over the records the actor may view (ResourceService.aggregate).
|
|
68
|
+
*/
|
|
69
|
+
async aggregate(ctx) {
|
|
70
|
+
return this.#execute(ctx, async ({ resources, actor }, resource) => {
|
|
71
|
+
const list = (value) => value === undefined || value === ''
|
|
72
|
+
? []
|
|
73
|
+
: Array.isArray(value)
|
|
74
|
+
? value.map(String)
|
|
75
|
+
: String(value).split(',').filter(Boolean);
|
|
76
|
+
let where;
|
|
77
|
+
const raw = ctx.request.input('where');
|
|
78
|
+
if (typeof raw === 'string' && raw) {
|
|
79
|
+
try {
|
|
80
|
+
where = JSON.parse(raw);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
throw new KitError(422, 'E_FILTER', 'where must be a JSON object');
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
else if (raw && typeof raw === 'object')
|
|
87
|
+
where = raw;
|
|
88
|
+
return {
|
|
89
|
+
data: await resources.aggregate(resource.name, actor, {
|
|
90
|
+
groupBy: list(ctx.request.input('groupBy')),
|
|
91
|
+
sum: list(ctx.request.input('sum')),
|
|
92
|
+
count: ctx.request.input('count') !== 'false',
|
|
93
|
+
filters: ctx.request.input('filters'),
|
|
94
|
+
where: where,
|
|
95
|
+
search: ctx.request.input('search'),
|
|
96
|
+
}),
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
}
|
|
54
100
|
async store(ctx) {
|
|
55
101
|
return this.#execute(ctx, async ({ resources, actor }, resource) => ctx.response.created({
|
|
56
102
|
data: await resources.save(resource.name, actor, ctx.request.body()),
|
|
@@ -70,6 +116,11 @@ export function createResourceController(resolveRuntime, renderList, renderForm,
|
|
|
70
116
|
async cancel(ctx) {
|
|
71
117
|
return this.#transition(ctx, 'cancel');
|
|
72
118
|
}
|
|
119
|
+
async amend(ctx) {
|
|
120
|
+
return this.#execute(ctx, async ({ resources, actor }, resource) => ctx.response.created({
|
|
121
|
+
data: await resources.amend(resource.name, this.#id(ctx), actor),
|
|
122
|
+
}));
|
|
123
|
+
}
|
|
73
124
|
#id(ctx) {
|
|
74
125
|
return this.#positiveId(ctx.params.id);
|
|
75
126
|
}
|
|
@@ -6,6 +6,10 @@ export type RecordPermissions = Partial<Record<Action, boolean>>;
|
|
|
6
6
|
export type ResourceDescription = {
|
|
7
7
|
name: string;
|
|
8
8
|
label: string;
|
|
9
|
+
/** Singular record noun in Arabic, or null when the resource does not declare one. */
|
|
10
|
+
recordLabel: string | null;
|
|
11
|
+
/** Arabic create-button text, or null to derive «إضافة <recordLabel>» (or «إضافة سجل»). */
|
|
12
|
+
createLabel: string | null;
|
|
9
13
|
fields: ResourceField[];
|
|
10
14
|
list: string[];
|
|
11
15
|
show: string[];
|
|
@@ -19,4 +23,6 @@ export type ResourceNavigation = {
|
|
|
19
23
|
label: string;
|
|
20
24
|
href: string;
|
|
21
25
|
module: string;
|
|
26
|
+
/** Arabic module label, for grouping the navigation by module (1.2; optional for compatibility). */
|
|
27
|
+
moduleLabel?: string;
|
|
22
28
|
}[];
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Resource, SerializedRecord } from '../resource/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* The fields that name a record wherever it is referenced (#47, #32): the resource's
|
|
4
|
+
* `title`, or else its first sequence field and its first text field in `list`. Lookup
|
|
5
|
+
* keys are never shown raw; declared lookup fields are shown by their Arabic label.
|
|
6
|
+
*/
|
|
7
|
+
export declare function titleFields(resource: Pick<Resource, 'fields' | 'list' | 'title'>): string[];
|
|
8
|
+
/** Definition check: title fields exist, are readable and have a displayable type. */
|
|
9
|
+
export declare function assertTitle(resource: Pick<Resource, 'name' | 'fields' | 'list' | 'show' | 'serialize' | 'title'>): void;
|
|
10
|
+
/**
|
|
11
|
+
* The title of one serialized record, read after field-level filtering so it never shows
|
|
12
|
+
* a value the viewer may not read. Returns null when no title field has a value.
|
|
13
|
+
*/
|
|
14
|
+
export declare function formatTitle(resource: Pick<Resource, 'fields' | 'list' | 'title'>, record: SerializedRecord, lookupLabel: (group: string, key: string) => string | undefined): string | null;
|