@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,29 @@
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, flags } from '@adonisjs/core/ace';
8
+ import { generateResource } from '../src/commands/generator.js';
9
+ import { fileURLToPath } from 'node:url';
10
+ export default class Resource extends BaseCommand {
11
+ static commandName = 'adula:resource';
12
+ static description = 'Generate a scoped resource, migration, model, validator, factory and security contract';
13
+ async run() {
14
+ if (!this.module) {
15
+ this.logger.error('--module is required');
16
+ this.exitCode = 1;
17
+ return;
18
+ }
19
+ const files = await generateResource(fileURLToPath(this.app.appRoot), this.name, this.module);
20
+ files.forEach((file) => this.logger.success(file));
21
+ this.logger.info('Set bilingual labels, fill the resource definition, migrate, and run the generated security contract.');
22
+ }
23
+ }
24
+ __decorate([
25
+ args.string()
26
+ ], Resource.prototype, "name", void 0);
27
+ __decorate([
28
+ flags.string()
29
+ ], Resource.prototype, "module", void 0);
@@ -0,0 +1,12 @@
1
+ import { BaseCommand } from '@adonisjs/core/ace';
2
+ export default class StorageMigrate extends BaseCommand {
3
+ static commandName: string;
4
+ static description: string;
5
+ static options: {
6
+ startApp: boolean;
7
+ };
8
+ from: string;
9
+ to: string;
10
+ dryRun: boolean;
11
+ run(): Promise<void>;
12
+ }
@@ -0,0 +1,39 @@
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, flags } from '@adonisjs/core/ace';
8
+ import { migrateStorage } from '../src/attachments/storage_migrate.js';
9
+ export default class StorageMigrate extends BaseCommand {
10
+ static commandName = 'adula:storage:migrate';
11
+ static description = 'Copy attachment files from one Drive disk to another and repoint their rows';
12
+ static options = { startApp: true };
13
+ async run() {
14
+ const { default: db } = await import('@adonisjs/lucid/services/db');
15
+ const { default: drive } = await import('@adonisjs/drive/services/main');
16
+ const { configProvider } = await import('@adonisjs/core');
17
+ const resolved = await configProvider.resolve(this.app, this.app.config.get('drive'));
18
+ const result = await migrateStorage(db.connection().getWriteClient(), {
19
+ from: this.from,
20
+ to: this.to,
21
+ disks: Object.keys(resolved?.config.services ?? {}),
22
+ dryRun: Boolean(this.dryRun),
23
+ use: (name) => drive.use(name),
24
+ report: (line) => this.logger.info(line),
25
+ });
26
+ this.logger.log(JSON.stringify(result));
27
+ if (result.failed.length)
28
+ this.exitCode = 1;
29
+ }
30
+ }
31
+ __decorate([
32
+ args.string({ description: 'Source disk name' })
33
+ ], StorageMigrate.prototype, "from", void 0);
34
+ __decorate([
35
+ args.string({ description: 'Target disk name' })
36
+ ], StorageMigrate.prototype, "to", void 0);
37
+ __decorate([
38
+ flags.boolean({ description: 'List the files that would move without copying anything' })
39
+ ], StorageMigrate.prototype, "dryRun", void 0);
@@ -0,0 +1,11 @@
1
+ import { BaseCommand } from '@adonisjs/core/ace';
2
+ export default class Ui extends BaseCommand {
3
+ static commandName: string;
4
+ static description: string;
5
+ action: string;
6
+ component: string;
7
+ preview: boolean;
8
+ accept: boolean;
9
+ run(): Promise<void>;
10
+ private initialize;
11
+ }
@@ -0,0 +1,210 @@
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, flags } from '@adonisjs/core/ace';
8
+ import { createRequire } from 'node:module';
9
+ import { readFile, writeFile, mkdir, access } from 'node:fs/promises';
10
+ import { dirname, join, resolve, relative, isAbsolute } from 'node:path';
11
+ import { spawn } from 'node:child_process';
12
+ import { digest } from '../src/commands/agent_assets.js';
13
+ export default class Ui extends BaseCommand {
14
+ static commandName = 'adula:ui';
15
+ static description = 'Install reviewed RTL components through the project-owned shadcn registry';
16
+ async run() {
17
+ if (this.action !== 'add')
18
+ throw new Error('Usage: adula:ui add <component|all> [--preview|--accept]');
19
+ if (this.preview && this.accept)
20
+ throw new Error('Use either --preview or --accept, not both');
21
+ if (this.app.inProduction)
22
+ throw new Error('Install UI components in the source checkout');
23
+ const root = this.app.makePath();
24
+ const require = createRequire(this.app.makeURL('package.json'));
25
+ const uiRoot = dirname(require.resolve('@adula/ui/package.json'));
26
+ const manifest = JSON.parse(await readFile(join(uiRoot, 'build/manifest.json'), 'utf8'));
27
+ const available = new Set(manifest.items.map((item) => item.name));
28
+ if (this.component !== 'all' && !available.has(this.component))
29
+ throw new Error(`Unknown UI component: ${this.component}`);
30
+ const collected = new Map();
31
+ const load = async (name) => {
32
+ if (collected.has(name))
33
+ return;
34
+ if (!available.has(name))
35
+ throw new Error(`Unreviewed registry dependency: ${name}`);
36
+ const item = JSON.parse(await readFile(join(uiRoot, 'build', `${name}.json`), 'utf8'));
37
+ collected.set(name, item);
38
+ for (const dependency of item.registryDependencies ?? [])
39
+ await load(dependency);
40
+ };
41
+ for (const name of this.component === 'all' ? available : [this.component])
42
+ await load(name);
43
+ let lock = {
44
+ version: manifest.version,
45
+ kitCompatibility: manifest.kitCompatibility,
46
+ files: {},
47
+ };
48
+ try {
49
+ lock = JSON.parse(await readFile(this.app.makePath('ui.lock.json'), 'utf8'));
50
+ }
51
+ catch (error) {
52
+ if (error.code !== 'ENOENT')
53
+ throw error;
54
+ }
55
+ const customized = new Map();
56
+ for (const item of collected.values())
57
+ for (const file of item.files) {
58
+ const path = resolve(root, file.target);
59
+ const local = relative(root, path);
60
+ if (local.startsWith('..') ||
61
+ isAbsolute(local) ||
62
+ !file.target.startsWith('inertia/components/ui/'))
63
+ throw new Error('Registry files must stay in inertia/components/ui');
64
+ try {
65
+ const current = await readFile(path, 'utf8');
66
+ if (digest(current) !== lock.files[file.target]?.hash) {
67
+ // --accept is the documented end of a review: the developer merged by hand,
68
+ // so the file stays exactly as it is and only its recorded hash moves.
69
+ if (this.accept)
70
+ customized.set(file.target, current);
71
+ else if (!this.preview)
72
+ throw new Error(`Project customized ${file.target}; review it with --preview, merge the changes, then re-run with --accept`);
73
+ }
74
+ }
75
+ catch (error) {
76
+ if (error.code !== 'ENOENT')
77
+ throw error;
78
+ }
79
+ }
80
+ if (!this.preview)
81
+ await this.initialize(uiRoot);
82
+ else
83
+ await access(this.app.makePath('components.json'));
84
+ const bundle = {
85
+ $schema: 'https://ui.shadcn.com/schema/registry-item.json',
86
+ name: 'adula-ui',
87
+ type: 'registry:ui',
88
+ dependencies: [
89
+ ...new Set([
90
+ ...[...collected.values()].flatMap((item) => item.dependencies ?? []),
91
+ ...['tw-animate-css', '@fontsource/noto-sans-arabic'].map((name) => `${name}@${manifest.dependencies[name]}`),
92
+ ]),
93
+ ],
94
+ files: [...collected.values()].flatMap((item) => item.files),
95
+ };
96
+ const bundlePath = this.app.tmpPath('adula-ui.json');
97
+ await mkdir(dirname(bundlePath), { recursive: true });
98
+ await writeFile(bundlePath, JSON.stringify(bundle, null, 2));
99
+ const command = require.resolve('shadcn');
100
+ const bundleArgument = `./${relative(root, bundlePath).replaceAll('\\', '/')}`;
101
+ await new Promise((done, reject) => {
102
+ const child = spawn(process.execPath, [
103
+ command,
104
+ 'add',
105
+ bundleArgument,
106
+ '--yes',
107
+ ...(this.preview ? ['--dry-run'] : ['--overwrite']),
108
+ ], { cwd: root, stdio: 'inherit', shell: false });
109
+ child.once('error', reject);
110
+ child.once('exit', (code) => code === 0 ? done() : reject(new Error(`shadcn exited with ${code}`)));
111
+ });
112
+ if (this.preview)
113
+ return;
114
+ // shadcn overwrites unconditionally; reviewed customizations are put back untouched.
115
+ for (const [target, content] of customized)
116
+ await writeFile(this.app.makePath(target), content);
117
+ for (const item of collected.values())
118
+ for (const file of item.files)
119
+ lock.files[file.target] = {
120
+ hash: digest(await readFile(this.app.makePath(file.target), 'utf8')),
121
+ component: item.name,
122
+ };
123
+ lock.version = manifest.version;
124
+ lock.kitCompatibility = manifest.kitCompatibility;
125
+ await writeFile(this.app.makePath('ui.lock.json'), JSON.stringify(lock, null, 2) + '\n');
126
+ this.logger.success(`Installed ${collected.size} registry items; project file hashes recorded in ui.lock.json`);
127
+ if (customized.size)
128
+ this.logger.info(`Preserved ${customized.size} reviewed customization(s): ${[...customized.keys()].join(', ')}`);
129
+ }
130
+ async initialize(uiRoot) {
131
+ const root = this.app.makePath();
132
+ const create = async (path, content) => {
133
+ await mkdir(dirname(path), { recursive: true });
134
+ try {
135
+ await writeFile(path, content, { flag: 'wx' });
136
+ }
137
+ catch (error) {
138
+ if (error.code !== 'EEXIST')
139
+ throw error;
140
+ }
141
+ };
142
+ await create(join(root, 'components.json'), JSON.stringify({
143
+ $schema: 'https://ui.shadcn.com/schema.json',
144
+ style: 'new-york',
145
+ rsc: false,
146
+ tsx: true,
147
+ rtl: true,
148
+ tailwind: {
149
+ config: '',
150
+ css: 'inertia/css/kit.css',
151
+ baseColor: 'neutral',
152
+ cssVariables: true,
153
+ },
154
+ aliases: {
155
+ components: '~/components',
156
+ ui: '~/components/ui',
157
+ utils: '~/lib/utils',
158
+ lib: '~/lib',
159
+ hooks: '~/hooks',
160
+ },
161
+ iconLibrary: 'lucide',
162
+ }, null, 2) + '\n');
163
+ await create(join(root, 'inertia/css/kit.css'), await readFile(join(uiRoot, 'build/theme.css'), 'utf8'));
164
+ await create(join(root, 'inertia/lib/utils.ts'), "export { cn } from 'cn'\n");
165
+ const tsPath = join(root, 'tsconfig.json');
166
+ const ts = JSON.parse(await readFile(tsPath, 'utf8'));
167
+ ts.compilerOptions ??= {};
168
+ ts.compilerOptions.paths = { ...ts.compilerOptions.paths, '~/*': ['./inertia/*'] };
169
+ await writeFile(tsPath, JSON.stringify(ts, null, 2) + '\n');
170
+ const cssPath = join(root, 'inertia/css/app.css');
171
+ const css = await readFile(cssPath, 'utf8');
172
+ if (!css.includes('/* adula:legacy-layer */'))
173
+ await writeFile(cssPath, `/* adula:legacy-layer */\n@layer theme, base, legacy, components, utilities;\n@layer legacy {\n${css}\n}\n`);
174
+ const codemods = await this.createCodemods();
175
+ // The framework codemod only supports an object config. A configured host
176
+ // may use a callback (for test aliases, for example); do not rewrite it.
177
+ const vite = await readFile(join(root, 'vite.config.ts'), 'utf8');
178
+ if (!vite.includes("from '@tailwindcss/vite'") && !vite.includes('from "@tailwindcss/vite"'))
179
+ await codemods.registerVitePlugin('tailwindcss()', [
180
+ { module: '@tailwindcss/vite', identifier: 'tailwindcss', isNamed: false },
181
+ ]);
182
+ const project = await codemods.getTsMorphProject();
183
+ if (!project)
184
+ throw new Error('UI installation requires @adonisjs/assembler');
185
+ const entry = project.addSourceFileAtPathIfExists(join(root, 'inertia/app.tsx'));
186
+ // One CSS entry fixes layer ordering in development and production bundlers.
187
+ const kitCssPath = join(root, 'inertia/css/kit.css');
188
+ const kitCss = await readFile(kitCssPath, 'utf8');
189
+ if (!kitCss.includes('@import "./app.css"'))
190
+ await writeFile(kitCssPath, `@layer theme, base, legacy, components, utilities;\n@import "./app.css";\n${kitCss}`);
191
+ entry.getImportDeclaration('./css/app.css')?.remove();
192
+ if (!entry.getImportDeclaration('./css/kit.css'))
193
+ entry.addImportDeclaration({ moduleSpecifier: './css/kit.css' });
194
+ await entry.save();
195
+ }
196
+ }
197
+ __decorate([
198
+ args.string()
199
+ ], Ui.prototype, "action", void 0);
200
+ __decorate([
201
+ args.string()
202
+ ], Ui.prototype, "component", void 0);
203
+ __decorate([
204
+ flags.boolean({ description: 'Show shadcn changes without modifying UI files' })
205
+ ], Ui.prototype, "preview", void 0);
206
+ __decorate([
207
+ flags.boolean({
208
+ description: 'Keep already reviewed customizations, re-record their hashes and update others',
209
+ })
210
+ ], Ui.prototype, "accept", void 0);
@@ -0,0 +1,2 @@
1
+ import type Configure from '@adonisjs/core/commands/configure';
2
+ export declare function configure(command: Configure): Promise<void>;
@@ -0,0 +1,79 @@
1
+ /*
2
+ |--------------------------------------------------------------------------
3
+ | Configure hook
4
+ |--------------------------------------------------------------------------
5
+ |
6
+ | The configure hook is called when someone runs "node ace configure <package>"
7
+ | command. You are free to perform any operations inside this function to
8
+ | configure the package.
9
+ |
10
+ | To make things easier, you have access to the underlying "Configure"
11
+ | instance and you can use codemods to modify the source files.
12
+ |
13
+ */
14
+ import { readFile, writeFile } from 'node:fs/promises';
15
+ import { fileURLToPath } from 'node:url';
16
+ import { stubsRoot } from './stubs/main.js';
17
+ export async function configure(command) {
18
+ const pkgPath = command.app.makePath('package.json');
19
+ const pkg = JSON.parse(await readFile(pkgPath, 'utf8'));
20
+ for (const dependency of ['@adonisjs/lucid', '@adonisjs/auth', '@adonisjs/session', '@adonisjs/shield', 'pg']) {
21
+ if (!pkg.dependencies?.[dependency])
22
+ throw new Error(`Install and configure ${dependency} before @adula/kit`);
23
+ }
24
+ const aliases = { '#modules/*': './app/modules/*.js', '#tests/*': './tests/*.js' };
25
+ for (const [key, target] of Object.entries(aliases)) {
26
+ if (pkg.imports?.[key] && pkg.imports[key] !== target)
27
+ throw new Error(`Conflicting package import ${key}`);
28
+ }
29
+ const dbPath = command.app.configPath('database.ts');
30
+ const databaseSource = await readFile(dbPath, 'utf8');
31
+ if (!/client:\s*['"]pg['"]/.test(databaseSource.replace(/\/\/[^\n]*/g, '')))
32
+ throw new Error('Configure PostgreSQL with node ace configure @adonisjs/lucid --db=postgres before @adula/kit');
33
+ const codemods = await command.createCodemods();
34
+ const project = await codemods.getTsMorphProject();
35
+ if (!project)
36
+ throw new Error('The host must have @adonisjs/assembler installed to configure kit');
37
+ const dbFile = project.addSourceFileAtPathIfExists(dbPath);
38
+ const dbExport = dbFile.getExportAssignments()[0];
39
+ if (!dbExport)
40
+ throw new Error('config/database.ts must have a default export');
41
+ if (!dbExport.getExpression().getText().startsWith('withKitDatabase(')) {
42
+ const kitImport = dbFile.getImportDeclaration('@adula/kit');
43
+ if (kitImport)
44
+ kitImport.addNamedImport('withKitDatabase');
45
+ else
46
+ dbFile.addImportDeclaration({ moduleSpecifier: '@adula/kit', namedImports: ['withKitDatabase'] });
47
+ const urlImport = dbFile.getImportDeclaration('node:url');
48
+ if (!urlImport?.getNamedImports().some((entry) => entry.getName() === 'fileURLToPath')) {
49
+ if (urlImport)
50
+ urlImport.addNamedImport('fileURLToPath');
51
+ else
52
+ dbFile.addImportDeclaration({ moduleSpecifier: 'node:url', namedImports: ['fileURLToPath'] });
53
+ }
54
+ dbExport.setExpression(`withKitDatabase(${dbExport.getExpression().getText()}, fileURLToPath(new URL('../', import.meta.url)))`);
55
+ await dbFile.save();
56
+ }
57
+ pkg.imports = { ...pkg.imports, ...aliases };
58
+ await writeFile(pkgPath, `${JSON.stringify(pkg, null, 2)}\n`);
59
+ codemods.overwriteExisting = false;
60
+ for (const stub of ['modules', 'service', 'controller', 'routes', 'resource_contract'])
61
+ await codemods.makeUsingStub(stubsRoot, `${stub}.stub`, {}, stub === 'resource_contract'
62
+ ? { contentsFromFile: fileURLToPath(new URL('./stubs/resource_contract.txt', import.meta.url)) } : undefined);
63
+ await codemods.updateRcFile((rc) => {
64
+ rc.addProvider('@adula/kit/provider').addCommand('@adula/kit/commands').addPreloadFile('#start/kit_routes');
65
+ });
66
+ if (!pkg.devDependencies?.['@japa/api-client'] && !pkg.dependencies?.['@japa/api-client']) {
67
+ const installed = await codemods.installPackages([{ name: '@japa/api-client@3.2.1', isDevDependency: true }]);
68
+ if (!installed)
69
+ throw new Error('Install @japa/api-client@3.2.1, then rerun configure');
70
+ }
71
+ for (const [name, path, args] of [
72
+ ['apiClient', '@japa/api-client', ''],
73
+ ['sessionApiClient', '@adonisjs/session/plugins/api_client', 'app'],
74
+ ['authApiClient', '@adonisjs/auth/plugins/api_client', 'app'],
75
+ ['shieldApiClient', '@adonisjs/shield/plugins/api_client', ''],
76
+ ])
77
+ await codemods.registerJapaPlugin(`${name}(${args})`, [{ module: path, isNamed: true, identifier: name }]);
78
+ command.logger.success('Kit configured. Run migration:run, create your user using the official auth flow, then ADULA_ADMIN_EMAIL=<email> node ace adula:install.');
79
+ }
@@ -0,0 +1,5 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ export default class KitCore extends BaseSchema {
3
+ up(): Promise<void>;
4
+ down(): Promise<void>;
5
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ import { createCoreSchema } from '../../src/database/schema.js';
3
+ export default class KitCore extends BaseSchema {
4
+ async up() {
5
+ await createCoreSchema(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,5 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ export default class KitAttachments extends BaseSchema {
3
+ up(): Promise<void>;
4
+ down(): Promise<void>;
5
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ import { createAttachmentsSchema } from '../../src/database/schema.js';
3
+ export default class KitAttachments extends BaseSchema {
4
+ async up() {
5
+ await createAttachmentsSchema(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,5 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ export default class KitSavedViews extends BaseSchema {
3
+ up(): Promise<void>;
4
+ down(): Promise<void>;
5
+ }
@@ -0,0 +1,10 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ import { createSavedViewsSchema } from '../../src/database/schema.js';
3
+ export default class KitSavedViews extends BaseSchema {
4
+ async up() {
5
+ await createSavedViewsSchema(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,5 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ export default class extends BaseSchema {
3
+ up(): Promise<void>;
4
+ down(): Promise<void>;
5
+ }
@@ -0,0 +1,18 @@
1
+ import { BaseSchema } from '@adonisjs/lucid/schema';
2
+ export default class extends BaseSchema {
3
+ async up() {
4
+ this.schema.createTable('user_invitations', (table) => {
5
+ table.increments('id');
6
+ table.string('email', 254).notNullable().unique();
7
+ table.string('full_name', 120).notNullable();
8
+ table.string('token_hash', 64).notNullable().unique();
9
+ table.integer('invited_by').unsigned().references('id').inTable('users').onDelete('RESTRICT');
10
+ table.timestamp('expires_at', { useTz: true }).notNullable();
11
+ table.timestamp('accepted_at', { useTz: true }).nullable();
12
+ table.timestamp('created_at', { useTz: true }).notNullable().defaultTo(this.now());
13
+ });
14
+ }
15
+ async down() {
16
+ throw new Error('Kit migrations are additive. Restore a tested backup instead of rolling back.');
17
+ }
18
+ }
@@ -0,0 +1,51 @@
1
+ export { defineResource, columnName } from './src/resource/define_resource.js';
2
+ export { configure } from './configure.js';
3
+ export { withKitDatabase } from './src/database/configure.js';
4
+ export { createResourceController } from './src/admin/controller.js';
5
+ export type { ResourceRuntime, ResourceList, ResourceEditor, ResourceShow, ResourceChildren, ResourceLookups, ResourceActivity, } from './src/admin/controller.js';
6
+ export type * from './src/admin/presentation.js';
7
+ export { ResourceRegistry } from './src/resource/registry.js';
8
+ export type * from './src/resource/types.js';
9
+ export { buildAbility, canRecord, inOrgScope } from './src/auth/ability.js';
10
+ export { packedResourceRules } from './src/auth/packed_rules.js';
11
+ export type { Actor, Rule, KitAbility } from './src/auth/ability.js';
12
+ export { ActorStore } from './src/auth/actor_store.js';
13
+ export { accessibleBy, authorizationSql, conditionSql } from './src/auth/sql.js';
14
+ export { ResourceService } from './src/admin/resource_service.js';
15
+ export { serialize, writableInput, selectedFields } from './src/admin/contracts.js';
16
+ export { KitError } from './src/admin/errors.js';
17
+ export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, } from './src/database/schema.js';
18
+ export { registerUpload, findAttachment, loadAttachments, claimAttachment, releaseAttachment, summarizeAttachment, attachmentUrl, isAttachmentId, isRelativeDiskPath, } from './src/attachments/attachment_service.js';
19
+ export type { AttachmentRecord, AttachmentSummary, UploadInput, ClaimInput, } from './src/attachments/attachment_service.js';
20
+ export { migrateStorage } from './src/attachments/storage_migrate.js';
21
+ export type { StorageDisk, StorageMigrationOptions, StorageMigrationResult, } from './src/attachments/storage_migrate.js';
22
+ export { diagnoseAttachments } from './src/attachments/doctor.js';
23
+ export { Settings, sequence, notify } from './src/services/settings.js';
24
+ export { uiPreferences, validateUiPreferences, UI_PREFERENCES_KEY, DEFAULT_UI_PREFERENCES, } from './src/core/ui_preferences.js';
25
+ export type { UiPreferences, CalendarSystem, CalendarPreference, } from './src/core/ui_preferences.js';
26
+ export { moveOrgUnit } from './src/org/org_service.js';
27
+ export { publishOutbox, consumeEvent } from './src/events/outbox.js';
28
+ export type { Jobs, DomainEvent, Listener } from './src/events/outbox.js';
29
+ export { AdonisJobs } from './src/events/adonis_jobs.js';
30
+ export { recordMutation } from './src/events/record_mutation.js';
31
+ export { assessBackup, verifyBackup } from './src/services/backup.js';
32
+ export type { BackupObject, BackupStatus } from './src/services/backup.js';
33
+ export { ActivityAdmin, logActivity } from './src/core/activity.js';
34
+ export type { ActivityEntry, ActivityFilters, ActivityPage, ActivityRow, } from './src/core/activity.js';
35
+ export { RolesAdmin, ALL_SUBJECT_LABEL } from './src/core/roles.js';
36
+ export type { RoleSummary, RoleDetail, RoleRule, RuleInput, RoleMatrix, MatrixSubject, MatrixField, } from './src/core/roles.js';
37
+ export { UsersAdmin } from './src/core/users.js';
38
+ export { UserInvitations, type InvitationDelivery } from './src/core/user_invitations.js';
39
+ export type { UserSummary, UserPage, UserRoleAssignment, UserOrgUnit } from './src/core/users.js';
40
+ export { OrgUnitsAdmin } from './src/core/org_units.js';
41
+ export type { OrgUnitNode } from './src/core/org_units.js';
42
+ export { SavedViews } from './src/core/saved_views.js';
43
+ export type { SavedView, SavedViewQuery } from './src/core/saved_views.js';
44
+ export { NotificationsAdmin } from './src/core/notifications.js';
45
+ export type { Notification, NotificationPage } from './src/core/notifications.js';
46
+ export { SettingsAdmin, isProtectedSetting, parseSettingValue, SETTING_SCOPES, PROTECTED_SETTING_KEYS, } from './src/core/settings.js';
47
+ export type { SettingScope, SettingRow, SettingInput } from './src/core/settings.js';
48
+ export { runtimeHealth, isBackupStale, backupStale, heartbeat, HEARTBEAT_MAX_AGE_MS, BACKUP_MAX_AGE_MS, } from './src/core/health.js';
49
+ export type { RuntimeHealth, HeartbeatStatus, QueueSnapshot, QueueCounts, FailedJob, } from './src/core/health.js';
50
+ export { MailDeliveryTest, MAIL_TEST_KEY, type MailTestState } from './src/core/mail_test.js';
51
+ export { InitialSetup, type SetupCheck } from './src/core/setup.js';
package/build/index.js ADDED
@@ -0,0 +1,34 @@
1
+ export { defineResource, columnName } from './src/resource/define_resource.js';
2
+ export { configure } from './configure.js';
3
+ export { withKitDatabase } from './src/database/configure.js';
4
+ export { createResourceController } from './src/admin/controller.js';
5
+ export { ResourceRegistry } from './src/resource/registry.js';
6
+ export { buildAbility, canRecord, inOrgScope } from './src/auth/ability.js';
7
+ export { packedResourceRules } from './src/auth/packed_rules.js';
8
+ export { ActorStore } from './src/auth/actor_store.js';
9
+ export { accessibleBy, authorizationSql, conditionSql } from './src/auth/sql.js';
10
+ export { ResourceService } from './src/admin/resource_service.js';
11
+ export { serialize, writableInput, selectedFields } from './src/admin/contracts.js';
12
+ export { KitError } from './src/admin/errors.js';
13
+ export { createCoreSchema, createResourceTable, createAttachmentsSchema, createSavedViewsSchema, } from './src/database/schema.js';
14
+ export { registerUpload, findAttachment, loadAttachments, claimAttachment, releaseAttachment, summarizeAttachment, attachmentUrl, isAttachmentId, isRelativeDiskPath, } from './src/attachments/attachment_service.js';
15
+ export { migrateStorage } from './src/attachments/storage_migrate.js';
16
+ export { diagnoseAttachments } from './src/attachments/doctor.js';
17
+ export { Settings, sequence, notify } from './src/services/settings.js';
18
+ export { uiPreferences, validateUiPreferences, UI_PREFERENCES_KEY, DEFAULT_UI_PREFERENCES, } from './src/core/ui_preferences.js';
19
+ export { moveOrgUnit } from './src/org/org_service.js';
20
+ export { publishOutbox, consumeEvent } from './src/events/outbox.js';
21
+ export { AdonisJobs } from './src/events/adonis_jobs.js';
22
+ export { recordMutation } from './src/events/record_mutation.js';
23
+ export { assessBackup, verifyBackup } from './src/services/backup.js';
24
+ export { ActivityAdmin, logActivity } from './src/core/activity.js';
25
+ export { RolesAdmin, ALL_SUBJECT_LABEL } from './src/core/roles.js';
26
+ export { UsersAdmin } from './src/core/users.js';
27
+ export { UserInvitations } from './src/core/user_invitations.js';
28
+ export { OrgUnitsAdmin } from './src/core/org_units.js';
29
+ export { SavedViews } from './src/core/saved_views.js';
30
+ export { NotificationsAdmin } from './src/core/notifications.js';
31
+ export { SettingsAdmin, isProtectedSetting, parseSettingValue, SETTING_SCOPES, PROTECTED_SETTING_KEYS, } from './src/core/settings.js';
32
+ export { runtimeHealth, isBackupStale, backupStale, heartbeat, HEARTBEAT_MAX_AGE_MS, BACKUP_MAX_AGE_MS, } from './src/core/health.js';
33
+ export { MailDeliveryTest, MAIL_TEST_KEY } from './src/core/mail_test.js';
34
+ export { InitialSetup } from './src/core/setup.js';
@@ -0,0 +1,6 @@
1
+ import type { ApplicationService } from '@adonisjs/core/types';
2
+ export default class KitProvider {
3
+ protected app: ApplicationService;
4
+ constructor(app: ApplicationService);
5
+ register(): void;
6
+ }
@@ -0,0 +1,10 @@
1
+ import { ResourceRegistry } from '../src/resource/registry.js';
2
+ export default class KitProvider {
3
+ app;
4
+ constructor(app) {
5
+ this.app = app;
6
+ }
7
+ register() {
8
+ this.app.container.singleton(ResourceRegistry, () => new ResourceRegistry());
9
+ }
10
+ }
@@ -0,0 +1,12 @@
1
+ import type { KitAbility, Actor } from '../auth/ability.js';
2
+ import type { RecordData, Resource, JsonValue, SerializedRecord } from '../resource/types.js';
3
+ export declare function selectedFields(resource: Resource, ability: KitAbility, options?: {
4
+ write?: boolean;
5
+ extra?: string[];
6
+ }): string[];
7
+ export declare function fromRow(row: RecordData, resource: Resource): RecordData;
8
+ export declare function jsonValue(value: unknown): JsonValue;
9
+ export declare function serialize(resource: Resource, record: RecordData, ability: KitAbility, actor: Actor): SerializedRecord;
10
+ export declare function writableInput(resource: Resource, input: RecordData): {
11
+ [k: string]: unknown;
12
+ };