adonia 0.1.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 +64 -0
- package/build/adonis_peers.d.ts +14 -0
- package/build/adonis_peers.js +56 -0
- package/build/cli.d.ts +2 -0
- package/build/cli.js +111 -0
- package/build/commands/add.d.ts +18 -0
- package/build/commands/add.js +246 -0
- package/build/commands/check.d.ts +4 -0
- package/build/commands/check.js +159 -0
- package/build/commands/diff.d.ts +2 -0
- package/build/commands/diff.js +74 -0
- package/build/commands/init.d.ts +6 -0
- package/build/commands/init.js +124 -0
- package/build/commands/list.d.ts +2 -0
- package/build/commands/list.js +34 -0
- package/build/config_merge.d.ts +10 -0
- package/build/config_merge.js +71 -0
- package/build/constants_merge.d.ts +4 -0
- package/build/constants_merge.js +85 -0
- package/build/copy.d.ts +8 -0
- package/build/copy.js +33 -0
- package/build/host.d.ts +15 -0
- package/build/host.js +85 -0
- package/build/registry/index.d.ts +26 -0
- package/build/registry/index.js +116 -0
- package/build/registry/plan.d.ts +53 -0
- package/build/registry/plan.js +159 -0
- package/build/schema.d.ts +136 -0
- package/build/schema.js +58 -0
- package/build/types.d.ts +21 -0
- package/build/types.js +1 -0
- package/build/wire.d.ts +16 -0
- package/build/wire.js +162 -0
- package/package.json +51 -0
- package/registry/README.md +86 -0
- package/registry/account/contracts/avatar_storage.ts +7 -0
- package/registry/account/contracts/index.ts +7 -0
- package/registry/account/contracts/types.ts +23 -0
- package/registry/account/events.ts +14 -0
- package/registry/account/module.json +31 -0
- package/registry/account/options.ts +11 -0
- package/registry/account/service.ts +155 -0
- package/registry/account/stubs/adapters/account.ts +21 -0
- package/registry/account/stubs/adapters/drive_avatar_storage.ts +15 -0
- package/registry/account/stubs/controllers/account_controller.ts +190 -0
- package/registry/account/stubs/routes/account.ts +53 -0
- package/registry/account/stubs/validators/account.ts +37 -0
- package/registry/account/tests/account_service.spec.ts +132 -0
- package/registry/account/tests/fakes/memory_avatar_storage.ts +12 -0
- package/registry/api/envelope.ts +66 -0
- package/registry/api/exception.ts +38 -0
- package/registry/api/exception_handler.ts +54 -0
- package/registry/api/module.json +27 -0
- package/registry/api/provider.ts +129 -0
- package/registry/api/service.ts +88 -0
- package/registry/api/tests/emit_safe.spec.ts +107 -0
- package/registry/api/tests/respond.spec.ts +40 -0
- package/registry/auth/contracts/index.ts +18 -0
- package/registry/auth/contracts/password_reset_store.ts +21 -0
- package/registry/auth/contracts/session_manager.ts +19 -0
- package/registry/auth/contracts/types.ts +32 -0
- package/registry/auth/events.ts +21 -0
- package/registry/auth/module.json +45 -0
- package/registry/auth/options.ts +23 -0
- package/registry/auth/service.ts +150 -0
- package/registry/auth/stubs/adapters/auth.ts +21 -0
- package/registry/auth/stubs/adapters/lucid_access_token_session.ts +33 -0
- package/registry/auth/stubs/adapters/lucid_password_reset_store.ts +68 -0
- package/registry/auth/stubs/adapters/lucid_user_store.ts +86 -0
- package/registry/auth/stubs/adapters/map_user.ts +19 -0
- package/registry/auth/stubs/controllers/auth_controller.ts +126 -0
- package/registry/auth/stubs/migrations/add_pending_email_to_users_table.ts +17 -0
- package/registry/auth/stubs/migrations/create_password_resets_table.ts +27 -0
- package/registry/auth/stubs/migrations/create_users_table.ts +31 -0
- package/registry/auth/stubs/models/password_reset.ts +29 -0
- package/registry/auth/stubs/models/user.ts +99 -0
- package/registry/auth/stubs/providers/vine_provider.ts +43 -0
- package/registry/auth/stubs/routes/auth.ts +36 -0
- package/registry/auth/stubs/start/limiter.ts +17 -0
- package/registry/auth/stubs/validators/auth.ts +48 -0
- package/registry/auth/stubs/validators/rules/exists.ts +21 -0
- package/registry/auth/stubs/validators/rules/unique.ts +21 -0
- package/registry/auth/stubs/validators/rules/valid_password.ts +20 -0
- package/registry/auth/stubs/validators/rules/valid_token.ts +27 -0
- package/registry/auth/stubs/validators/vine.d.ts +10 -0
- package/registry/auth/tests/auth_service.spec.ts +145 -0
- package/registry/auth/tests/auth_update_password.spec.ts +99 -0
- package/registry/auth/tests/fakes/index.ts +3 -0
- package/registry/auth/tests/fakes/memory_password_reset_store.ts +71 -0
- package/registry/auth/tests/fakes/memory_session_manager.ts +23 -0
- package/registry/auth/tests/fakes/memory_user_store.ts +89 -0
- package/registry/constants/exceptions.ts +64 -0
- package/registry/constants/index.ts +12 -0
- package/registry/constants/responseCodes.ts +87 -0
- package/registry/contracts/index.ts +5 -0
- package/registry/contracts/user.ts +78 -0
- package/registry/creem/contracts/creem_client.ts +34 -0
- package/registry/creem/contracts/index.ts +8 -0
- package/registry/creem/contracts/types.ts +30 -0
- package/registry/creem/events.ts +9 -0
- package/registry/creem/module.json +28 -0
- package/registry/creem/service.ts +87 -0
- package/registry/creem/stubs/adapters/creem.ts +23 -0
- package/registry/creem/stubs/adapters/creem_io_client.ts +70 -0
- package/registry/creem/tests/fakes/fake_creem_client.ts +68 -0
- package/registry/notification/contracts/app_notification_store.ts +8 -0
- package/registry/notification/contracts/index.ts +9 -0
- package/registry/notification/contracts/mail_transport.ts +7 -0
- package/registry/notification/contracts/types.ts +32 -0
- package/registry/notification/module.json +23 -0
- package/registry/notification/options.ts +11 -0
- package/registry/notification/service.ts +103 -0
- package/registry/notification/stubs/adapters/adonis_mail_transport.ts +15 -0
- package/registry/notification/stubs/adapters/lucid_app_notification_store.ts +21 -0
- package/registry/notification/stubs/adapters/notification.ts +36 -0
- package/registry/notification/stubs/migrations/create_notifications_table.ts +23 -0
- package/registry/notification/stubs/models/app_notification.ts +45 -0
- package/registry/notification/tests/fakes/memory_app_notification_store.ts +19 -0
- package/registry/notification/tests/fakes/memory_mail_transport.ts +16 -0
- package/registry/notification/tests/notification_service.spec.ts +63 -0
- package/registry/registry.json +4 -0
- package/registry/subscription/contracts/index.ts +9 -0
- package/registry/subscription/contracts/subscription_store.ts +15 -0
- package/registry/subscription/contracts/types.ts +39 -0
- package/registry/subscription/events.ts +13 -0
- package/registry/subscription/module.json +31 -0
- package/registry/subscription/options.ts +14 -0
- package/registry/subscription/service.ts +140 -0
- package/registry/subscription/stubs/adapters/lucid_subscription_store.ts +69 -0
- package/registry/subscription/stubs/adapters/subscription.ts +21 -0
- package/registry/subscription/stubs/migrations/create_subscriptions_table.ts +26 -0
- package/registry/subscription/stubs/migrations/subscriptions_user_creem_unique.ts +19 -0
- package/registry/subscription/stubs/models/subscription.ts +45 -0
- package/registry/subscription/tests/billing_service.spec.ts +189 -0
- package/registry/subscription/tests/fakes/memory_subscription_store.ts +63 -0
- package/registry/types/api.ts +41 -0
- package/registry/types/constants.ts +7 -0
- package/registry/types/index.ts +6 -0
- package/registry/types/models.ts +32 -0
- package/schema/adonia.schema.json +39 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { CORE_PACKAGES, impliedCoreManifest, moduleManifestSchema, registryIndexSchema, } from '../schema.js';
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
export function bundledRegistryPath() {
|
|
7
|
+
// build/registry/index.js → ../../registry
|
|
8
|
+
return resolve(__dirname, '../../registry');
|
|
9
|
+
}
|
|
10
|
+
export function loadRegistryIndex(root) {
|
|
11
|
+
const path = join(root, 'registry.json');
|
|
12
|
+
if (!existsSync(path)) {
|
|
13
|
+
const names = readdirSync(root).filter((n) => {
|
|
14
|
+
try {
|
|
15
|
+
return statSync(join(root, n)).isDirectory();
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return false;
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
const core = ['api', ...CORE_PACKAGES].filter((n) => names.includes(n));
|
|
22
|
+
const modules = names.filter((n) => !core.includes(n) && existsSync(join(root, n, 'module.json')));
|
|
23
|
+
return registryIndexSchema.parse({ core, modules });
|
|
24
|
+
}
|
|
25
|
+
return registryIndexSchema.parse(JSON.parse(readFileSync(path, 'utf8')));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolution order:
|
|
29
|
+
* 1. --registry <dir>
|
|
30
|
+
* 2. bundled (adonia.json "bundled" or empty)
|
|
31
|
+
* 3. local path in adonia.json
|
|
32
|
+
* github:… is rejected until remote materialization lands.
|
|
33
|
+
*/
|
|
34
|
+
export async function resolveRegistry(options) {
|
|
35
|
+
if (options.registryFlag) {
|
|
36
|
+
const root = resolve(options.cwd, options.registryFlag);
|
|
37
|
+
if (!existsSync(root)) {
|
|
38
|
+
throw new Error(`Registry path not found: ${root}`);
|
|
39
|
+
}
|
|
40
|
+
return { root, index: loadRegistryIndex(root), source: 'flag' };
|
|
41
|
+
}
|
|
42
|
+
const hostReg = options.hostRegistry ?? 'bundled';
|
|
43
|
+
if (hostReg === 'bundled' || hostReg === '') {
|
|
44
|
+
return loadBundled();
|
|
45
|
+
}
|
|
46
|
+
if (hostReg.startsWith('github:')) {
|
|
47
|
+
throw new Error('GitHub registries (github:…) are not supported in adonia@0.1.x.\n' +
|
|
48
|
+
'Use "registry": "bundled", a local path in adonia.json, or\n' +
|
|
49
|
+
'--registry <dir>.');
|
|
50
|
+
}
|
|
51
|
+
// Treat other strings as local paths relative to cwd
|
|
52
|
+
const asPath = resolve(options.cwd, hostReg);
|
|
53
|
+
if (existsSync(asPath)) {
|
|
54
|
+
return { root: asPath, index: loadRegistryIndex(asPath), source: 'flag' };
|
|
55
|
+
}
|
|
56
|
+
console.warn(`Unknown registry "${hostReg}"; using bundled.`);
|
|
57
|
+
return loadBundled();
|
|
58
|
+
}
|
|
59
|
+
function loadBundled() {
|
|
60
|
+
const bundled = bundledRegistryPath();
|
|
61
|
+
if (!existsSync(bundled)) {
|
|
62
|
+
throw new Error(`Bundled registry missing at ${bundled}. Reinstall adonia or pass --registry <dir>.`);
|
|
63
|
+
}
|
|
64
|
+
return { root: bundled, index: loadRegistryIndex(bundled), source: 'bundled' };
|
|
65
|
+
}
|
|
66
|
+
export function loadManifest(registry, name) {
|
|
67
|
+
if (CORE_PACKAGES.includes(name)) {
|
|
68
|
+
return impliedCoreManifest(name);
|
|
69
|
+
}
|
|
70
|
+
const path = join(registry.root, name, 'module.json');
|
|
71
|
+
if (!existsSync(path)) {
|
|
72
|
+
throw new Error(`Unknown module "${name}". Run \`npx adonia list\` to see available modules.`);
|
|
73
|
+
}
|
|
74
|
+
return moduleManifestSchema.parse(JSON.parse(readFileSync(path, 'utf8')));
|
|
75
|
+
}
|
|
76
|
+
export function expandDependencies(registry, names, installed, overwrite) {
|
|
77
|
+
const ordered = [];
|
|
78
|
+
const visiting = new Set();
|
|
79
|
+
const visited = new Set();
|
|
80
|
+
function visit(name) {
|
|
81
|
+
if (visited.has(name))
|
|
82
|
+
return;
|
|
83
|
+
if (visiting.has(name)) {
|
|
84
|
+
throw new Error(`Cycle in registryDependencies involving "${name}"`);
|
|
85
|
+
}
|
|
86
|
+
visiting.add(name);
|
|
87
|
+
const manifest = loadManifest(registry, name);
|
|
88
|
+
for (const dep of manifest.registryDependencies) {
|
|
89
|
+
visit(dep);
|
|
90
|
+
}
|
|
91
|
+
if (name === 'api') {
|
|
92
|
+
for (const core of CORE_PACKAGES) {
|
|
93
|
+
visit(core);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
visiting.delete(name);
|
|
97
|
+
visited.add(name);
|
|
98
|
+
if (!installed.has(name) || overwrite) {
|
|
99
|
+
if (!ordered.includes(name))
|
|
100
|
+
ordered.push(name);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
for (const name of names) {
|
|
104
|
+
visit(name);
|
|
105
|
+
}
|
|
106
|
+
return ordered;
|
|
107
|
+
}
|
|
108
|
+
export function listAllModuleNames(registry) {
|
|
109
|
+
return [...registry.index.core, ...registry.index.modules];
|
|
110
|
+
}
|
|
111
|
+
export function moduleDir(registry, name) {
|
|
112
|
+
return join(registry.root, name);
|
|
113
|
+
}
|
|
114
|
+
export function relativeFromRegistry(registry, absPath) {
|
|
115
|
+
return relative(registry.root, absPath);
|
|
116
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { type CopyOptions, type CopyResult } from '../copy.js';
|
|
2
|
+
import type { HostModulesConfig, ModuleManifest } from '../schema.js';
|
|
3
|
+
import type { Registry } from './index.js';
|
|
4
|
+
export interface PlannedCopy {
|
|
5
|
+
src: string;
|
|
6
|
+
dest: string;
|
|
7
|
+
kind: 'file' | 'stub' | 'test';
|
|
8
|
+
}
|
|
9
|
+
/** App stub folders selected by CLI flags. Routes are never included in `--with-stubs`. */
|
|
10
|
+
export type StubFolder = 'models' | 'migrations' | 'controllers' | 'validators' | 'routes' | 'providers' | 'start' | 'adapters';
|
|
11
|
+
export interface StubSelect {
|
|
12
|
+
models: boolean;
|
|
13
|
+
migrations: boolean;
|
|
14
|
+
controllers: boolean;
|
|
15
|
+
validators: boolean;
|
|
16
|
+
routes: boolean;
|
|
17
|
+
/** Vine macros; selected with `--with-validators` or `--with-stubs`. */
|
|
18
|
+
providers: boolean;
|
|
19
|
+
/** Host start files (limiter); selected with `--with-routes` or `--with-stubs`. */
|
|
20
|
+
start: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Lucid / SDK host I/O. Selected with `--with-adapters`, `--with-stubs`,
|
|
23
|
+
* or `--with-controllers`.
|
|
24
|
+
*/
|
|
25
|
+
adapters: boolean;
|
|
26
|
+
}
|
|
27
|
+
export declare const DEFAULT_ROUTES_DIR = "start/routes";
|
|
28
|
+
export declare const DEFAULT_PROVIDERS_DIR = "providers";
|
|
29
|
+
export declare const DEFAULT_START_DIR = "start";
|
|
30
|
+
export declare const DEFAULT_ADAPTERS_DIR = "app/adapters";
|
|
31
|
+
export declare function resolveStubSelect(flags: {
|
|
32
|
+
withStubs?: boolean;
|
|
33
|
+
withModels?: boolean;
|
|
34
|
+
withMigrations?: boolean;
|
|
35
|
+
withControllers?: boolean;
|
|
36
|
+
withValidators?: boolean;
|
|
37
|
+
withRoutes?: boolean;
|
|
38
|
+
withAdapters?: boolean;
|
|
39
|
+
}): StubSelect | null;
|
|
40
|
+
export declare function anyAppStubsSelected(select: StubSelect | null): boolean;
|
|
41
|
+
export declare function planModuleFiles(registry: Registry, name: string, manifest: ModuleManifest, host: HostModulesConfig, cwd: string): PlannedCopy[];
|
|
42
|
+
export declare function planStubs(registry: Registry, name: string, manifest: ModuleManifest, host: HostModulesConfig, cwd: string, warnings: string[], select: StubSelect): PlannedCopy[];
|
|
43
|
+
export declare function manifestHasRouteStubs(manifest: ModuleManifest): boolean;
|
|
44
|
+
export declare function hostRouteFile(cwd: string, moduleName: string): string;
|
|
45
|
+
export declare function planTests(registry: Registry, name: string, host: HostModulesConfig, cwd: string): PlannedCopy[];
|
|
46
|
+
export declare function executePlan(plans: PlannedCopy[], options: CopyOptions): {
|
|
47
|
+
results: {
|
|
48
|
+
plan: PlannedCopy;
|
|
49
|
+
result: CopyResult;
|
|
50
|
+
}[];
|
|
51
|
+
conflicts: PlannedCopy[];
|
|
52
|
+
};
|
|
53
|
+
export declare function describePlan(plan: PlannedCopy, cwd: string): string;
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import fg from 'fast-glob';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join, relative } from 'node:path';
|
|
4
|
+
import { copyFileWithPolicy } from '../copy.js';
|
|
5
|
+
import { moduleDir } from './index.js';
|
|
6
|
+
const APP_STUB_FOLDERS = ['models', 'migrations', 'controllers', 'validators'];
|
|
7
|
+
const STUB_FOLDER_TO_PATH_KEY = {
|
|
8
|
+
models: 'models',
|
|
9
|
+
migrations: 'migrations',
|
|
10
|
+
controllers: 'controllers',
|
|
11
|
+
validators: 'validators',
|
|
12
|
+
};
|
|
13
|
+
export const DEFAULT_ROUTES_DIR = 'start/routes';
|
|
14
|
+
export const DEFAULT_PROVIDERS_DIR = 'providers';
|
|
15
|
+
export const DEFAULT_START_DIR = 'start';
|
|
16
|
+
export const DEFAULT_ADAPTERS_DIR = 'app/adapters';
|
|
17
|
+
export function resolveStubSelect(flags) {
|
|
18
|
+
const withStubs = Boolean(flags.withStubs);
|
|
19
|
+
const withValidators = withStubs || Boolean(flags.withValidators);
|
|
20
|
+
const withControllers = withStubs || Boolean(flags.withControllers);
|
|
21
|
+
const withRoutes = Boolean(flags.withRoutes);
|
|
22
|
+
const select = {
|
|
23
|
+
models: withStubs || Boolean(flags.withModels),
|
|
24
|
+
migrations: withStubs || Boolean(flags.withMigrations),
|
|
25
|
+
controllers: withControllers,
|
|
26
|
+
validators: withValidators,
|
|
27
|
+
routes: withRoutes,
|
|
28
|
+
providers: withValidators,
|
|
29
|
+
start: withStubs || withRoutes,
|
|
30
|
+
adapters: withStubs || withControllers || Boolean(flags.withAdapters),
|
|
31
|
+
};
|
|
32
|
+
if (!APP_STUB_FOLDERS.some((f) => select[f]) &&
|
|
33
|
+
!select.routes &&
|
|
34
|
+
!select.providers &&
|
|
35
|
+
!select.start &&
|
|
36
|
+
!select.adapters) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
return select;
|
|
40
|
+
}
|
|
41
|
+
export function anyAppStubsSelected(select) {
|
|
42
|
+
if (!select)
|
|
43
|
+
return false;
|
|
44
|
+
return (APP_STUB_FOLDERS.some((f) => select[f]) ||
|
|
45
|
+
select.providers ||
|
|
46
|
+
select.start ||
|
|
47
|
+
select.adapters);
|
|
48
|
+
}
|
|
49
|
+
export function planModuleFiles(registry, name, manifest, host, cwd) {
|
|
50
|
+
const root = moduleDir(registry, name);
|
|
51
|
+
const destRoot = join(cwd, host.paths.modules, name);
|
|
52
|
+
const files = fg.sync(manifest.files.length ? manifest.files : ['**/*'], {
|
|
53
|
+
cwd: root,
|
|
54
|
+
onlyFiles: true,
|
|
55
|
+
dot: false,
|
|
56
|
+
ignore: ['stubs/**', 'tests/**', 'node_modules/**'],
|
|
57
|
+
});
|
|
58
|
+
return files.map((rel) => ({
|
|
59
|
+
src: join(root, rel),
|
|
60
|
+
dest: join(destRoot, rel),
|
|
61
|
+
kind: 'file',
|
|
62
|
+
}));
|
|
63
|
+
}
|
|
64
|
+
export function planStubs(registry, name, manifest, host, cwd, warnings, select) {
|
|
65
|
+
const root = moduleDir(registry, name);
|
|
66
|
+
const plans = [];
|
|
67
|
+
const stubGlobs = manifest.stubs.length ? manifest.stubs : [];
|
|
68
|
+
const files = fg.sync(stubGlobs, { cwd: root, onlyFiles: true });
|
|
69
|
+
for (const rel of files) {
|
|
70
|
+
// stubs/models/foo.ts
|
|
71
|
+
const without = rel.replace(/^stubs\//, '');
|
|
72
|
+
const slash = without.indexOf('/');
|
|
73
|
+
if (slash === -1) {
|
|
74
|
+
warnings.push(`Skipping stub with no folder: ${rel}`);
|
|
75
|
+
continue;
|
|
76
|
+
}
|
|
77
|
+
const folder = without.slice(0, slash);
|
|
78
|
+
const rest = without.slice(slash + 1);
|
|
79
|
+
if (!select[folder])
|
|
80
|
+
continue;
|
|
81
|
+
if (folder === 'routes') {
|
|
82
|
+
plans.push({
|
|
83
|
+
src: join(root, rel),
|
|
84
|
+
dest: join(cwd, DEFAULT_ROUTES_DIR, rest),
|
|
85
|
+
kind: 'stub',
|
|
86
|
+
});
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
if (folder === 'providers') {
|
|
90
|
+
plans.push({
|
|
91
|
+
src: join(root, rel),
|
|
92
|
+
dest: join(cwd, DEFAULT_PROVIDERS_DIR, rest),
|
|
93
|
+
kind: 'stub',
|
|
94
|
+
});
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (folder === 'start') {
|
|
98
|
+
plans.push({
|
|
99
|
+
src: join(root, rel),
|
|
100
|
+
dest: join(cwd, DEFAULT_START_DIR, rest),
|
|
101
|
+
kind: 'stub',
|
|
102
|
+
});
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
if (folder === 'adapters') {
|
|
106
|
+
plans.push({
|
|
107
|
+
src: join(root, rel),
|
|
108
|
+
dest: join(cwd, DEFAULT_ADAPTERS_DIR, rest),
|
|
109
|
+
kind: 'stub',
|
|
110
|
+
});
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
const pathKey = STUB_FOLDER_TO_PATH_KEY[folder];
|
|
114
|
+
if (!pathKey) {
|
|
115
|
+
warnings.push(`Unknown stub folder "${folder}" (${rel}); skipped`);
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const destDir = host.paths[pathKey];
|
|
119
|
+
plans.push({
|
|
120
|
+
src: join(root, rel),
|
|
121
|
+
dest: join(cwd, destDir, rest),
|
|
122
|
+
kind: 'stub',
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
return plans;
|
|
126
|
+
}
|
|
127
|
+
export function manifestHasRouteStubs(manifest) {
|
|
128
|
+
return manifest.stubs.some((s) => /(^|\/)stubs\/routes(\/|$)/.test(s) || s.includes('stubs/routes'));
|
|
129
|
+
}
|
|
130
|
+
export function hostRouteFile(cwd, moduleName) {
|
|
131
|
+
return join(cwd, DEFAULT_ROUTES_DIR, `${moduleName}.ts`);
|
|
132
|
+
}
|
|
133
|
+
export function planTests(registry, name, host, cwd) {
|
|
134
|
+
const root = join(moduleDir(registry, name), 'tests');
|
|
135
|
+
if (!existsSync(root))
|
|
136
|
+
return [];
|
|
137
|
+
const files = fg.sync('**/*', { cwd: root, onlyFiles: true });
|
|
138
|
+
const destRoot = join(cwd, host.paths.modules, name, 'tests');
|
|
139
|
+
return files.map((rel) => ({
|
|
140
|
+
src: join(root, rel),
|
|
141
|
+
dest: join(destRoot, rel),
|
|
142
|
+
kind: 'test',
|
|
143
|
+
}));
|
|
144
|
+
}
|
|
145
|
+
export function executePlan(plans, options) {
|
|
146
|
+
const results = [];
|
|
147
|
+
const conflicts = [];
|
|
148
|
+
for (const plan of plans) {
|
|
149
|
+
const result = copyFileWithPolicy(plan.src, plan.dest, options);
|
|
150
|
+
results.push({ plan, result });
|
|
151
|
+
if (result === 'conflict' || result === 'would-conflict') {
|
|
152
|
+
conflicts.push(plan);
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return { results, conflicts };
|
|
156
|
+
}
|
|
157
|
+
export function describePlan(plan, cwd) {
|
|
158
|
+
return `${plan.kind}: ${relative(cwd, plan.dest)}`;
|
|
159
|
+
}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export declare const moduleManifestSchema: z.ZodObject<{
|
|
3
|
+
name: z.ZodString;
|
|
4
|
+
description: z.ZodDefault<z.ZodString>;
|
|
5
|
+
files: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
6
|
+
stubs: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
7
|
+
dependencies: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
8
|
+
registryDependencies: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
9
|
+
peerModels: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
10
|
+
configKeys: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
11
|
+
env: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
12
|
+
events: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
13
|
+
hostFacingExceptions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
14
|
+
hostTests: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
15
|
+
}, "strip", z.ZodTypeAny, {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
files: string[];
|
|
19
|
+
stubs: string[];
|
|
20
|
+
dependencies: Record<string, string>;
|
|
21
|
+
registryDependencies: string[];
|
|
22
|
+
peerModels: string[];
|
|
23
|
+
configKeys: string[];
|
|
24
|
+
env: string[];
|
|
25
|
+
events: string[];
|
|
26
|
+
hostFacingExceptions: string[];
|
|
27
|
+
hostTests: string[];
|
|
28
|
+
}, {
|
|
29
|
+
name: string;
|
|
30
|
+
description?: string | undefined;
|
|
31
|
+
files?: string[] | undefined;
|
|
32
|
+
stubs?: string[] | undefined;
|
|
33
|
+
dependencies?: Record<string, string> | undefined;
|
|
34
|
+
registryDependencies?: string[] | undefined;
|
|
35
|
+
peerModels?: string[] | undefined;
|
|
36
|
+
configKeys?: string[] | undefined;
|
|
37
|
+
env?: string[] | undefined;
|
|
38
|
+
events?: string[] | undefined;
|
|
39
|
+
hostFacingExceptions?: string[] | undefined;
|
|
40
|
+
hostTests?: string[] | undefined;
|
|
41
|
+
}>;
|
|
42
|
+
export type ModuleManifest = z.infer<typeof moduleManifestSchema>;
|
|
43
|
+
export declare const hostModulesSchema: z.ZodObject<{
|
|
44
|
+
$schema: z.ZodOptional<z.ZodString>;
|
|
45
|
+
registry: z.ZodString;
|
|
46
|
+
ref: z.ZodString;
|
|
47
|
+
paths: z.ZodObject<{
|
|
48
|
+
modules: z.ZodString;
|
|
49
|
+
models: z.ZodString;
|
|
50
|
+
migrations: z.ZodString;
|
|
51
|
+
controllers: z.ZodString;
|
|
52
|
+
validators: z.ZodString;
|
|
53
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
54
|
+
modules: z.ZodString;
|
|
55
|
+
models: z.ZodString;
|
|
56
|
+
migrations: z.ZodString;
|
|
57
|
+
controllers: z.ZodString;
|
|
58
|
+
validators: z.ZodString;
|
|
59
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
60
|
+
modules: z.ZodString;
|
|
61
|
+
models: z.ZodString;
|
|
62
|
+
migrations: z.ZodString;
|
|
63
|
+
controllers: z.ZodString;
|
|
64
|
+
validators: z.ZodString;
|
|
65
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
66
|
+
aliases: z.ZodObject<{
|
|
67
|
+
modules: z.ZodString;
|
|
68
|
+
constants: z.ZodString;
|
|
69
|
+
models: z.ZodString;
|
|
70
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
71
|
+
modules: z.ZodString;
|
|
72
|
+
constants: z.ZodString;
|
|
73
|
+
models: z.ZodString;
|
|
74
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
75
|
+
modules: z.ZodString;
|
|
76
|
+
constants: z.ZodString;
|
|
77
|
+
models: z.ZodString;
|
|
78
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
79
|
+
installed: z.ZodArray<z.ZodString, "many">;
|
|
80
|
+
}, "strip", z.ZodTypeAny, {
|
|
81
|
+
registry: string;
|
|
82
|
+
ref: string;
|
|
83
|
+
paths: {
|
|
84
|
+
modules: string;
|
|
85
|
+
models: string;
|
|
86
|
+
migrations: string;
|
|
87
|
+
controllers: string;
|
|
88
|
+
validators: string;
|
|
89
|
+
} & {
|
|
90
|
+
[k: string]: unknown;
|
|
91
|
+
};
|
|
92
|
+
aliases: {
|
|
93
|
+
modules: string;
|
|
94
|
+
models: string;
|
|
95
|
+
constants: string;
|
|
96
|
+
} & {
|
|
97
|
+
[k: string]: unknown;
|
|
98
|
+
};
|
|
99
|
+
installed: string[];
|
|
100
|
+
$schema?: string | undefined;
|
|
101
|
+
}, {
|
|
102
|
+
registry: string;
|
|
103
|
+
ref: string;
|
|
104
|
+
paths: {
|
|
105
|
+
modules: string;
|
|
106
|
+
models: string;
|
|
107
|
+
migrations: string;
|
|
108
|
+
controllers: string;
|
|
109
|
+
validators: string;
|
|
110
|
+
} & {
|
|
111
|
+
[k: string]: unknown;
|
|
112
|
+
};
|
|
113
|
+
aliases: {
|
|
114
|
+
modules: string;
|
|
115
|
+
models: string;
|
|
116
|
+
constants: string;
|
|
117
|
+
} & {
|
|
118
|
+
[k: string]: unknown;
|
|
119
|
+
};
|
|
120
|
+
installed: string[];
|
|
121
|
+
$schema?: string | undefined;
|
|
122
|
+
}>;
|
|
123
|
+
export type HostModulesConfig = z.infer<typeof hostModulesSchema>;
|
|
124
|
+
export declare const registryIndexSchema: z.ZodObject<{
|
|
125
|
+
core: z.ZodArray<z.ZodString, "many">;
|
|
126
|
+
modules: z.ZodArray<z.ZodString, "many">;
|
|
127
|
+
}, "strip", z.ZodTypeAny, {
|
|
128
|
+
modules: string[];
|
|
129
|
+
core: string[];
|
|
130
|
+
}, {
|
|
131
|
+
modules: string[];
|
|
132
|
+
core: string[];
|
|
133
|
+
}>;
|
|
134
|
+
export type RegistryIndex = z.infer<typeof registryIndexSchema>;
|
|
135
|
+
export declare const CORE_PACKAGES: readonly ["types", "constants", "contracts"];
|
|
136
|
+
export declare function impliedCoreManifest(name: (typeof CORE_PACKAGES)[number]): ModuleManifest;
|
package/build/schema.js
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
export const moduleManifestSchema = z.object({
|
|
3
|
+
name: z.string().min(1),
|
|
4
|
+
description: z.string().default(''),
|
|
5
|
+
files: z.array(z.string()).default([]),
|
|
6
|
+
stubs: z.array(z.string()).default([]),
|
|
7
|
+
dependencies: z.record(z.string()).default({}),
|
|
8
|
+
registryDependencies: z.array(z.string()).default([]),
|
|
9
|
+
peerModels: z.array(z.string()).default([]),
|
|
10
|
+
configKeys: z.array(z.string()).default([]),
|
|
11
|
+
env: z.array(z.string()).default([]),
|
|
12
|
+
events: z.array(z.string()).default([]),
|
|
13
|
+
hostFacingExceptions: z.array(z.string()).default([]),
|
|
14
|
+
hostTests: z.array(z.string()).default([]),
|
|
15
|
+
});
|
|
16
|
+
export const hostModulesSchema = z.object({
|
|
17
|
+
$schema: z.string().optional(),
|
|
18
|
+
registry: z.string().min(1),
|
|
19
|
+
ref: z.string().min(1),
|
|
20
|
+
paths: z
|
|
21
|
+
.object({
|
|
22
|
+
modules: z.string(),
|
|
23
|
+
models: z.string(),
|
|
24
|
+
migrations: z.string(),
|
|
25
|
+
controllers: z.string(),
|
|
26
|
+
validators: z.string(),
|
|
27
|
+
})
|
|
28
|
+
.passthrough(),
|
|
29
|
+
aliases: z
|
|
30
|
+
.object({
|
|
31
|
+
modules: z.string(),
|
|
32
|
+
constants: z.string(),
|
|
33
|
+
models: z.string(),
|
|
34
|
+
})
|
|
35
|
+
.passthrough(),
|
|
36
|
+
installed: z.array(z.string()),
|
|
37
|
+
});
|
|
38
|
+
export const registryIndexSchema = z.object({
|
|
39
|
+
core: z.array(z.string()),
|
|
40
|
+
modules: z.array(z.string()),
|
|
41
|
+
});
|
|
42
|
+
export const CORE_PACKAGES = ['types', 'constants', 'contracts'];
|
|
43
|
+
export function impliedCoreManifest(name) {
|
|
44
|
+
return moduleManifestSchema.parse({
|
|
45
|
+
name,
|
|
46
|
+
description: `Shared ${name} package`,
|
|
47
|
+
files: ['**/*'],
|
|
48
|
+
stubs: [],
|
|
49
|
+
dependencies: {},
|
|
50
|
+
registryDependencies: [],
|
|
51
|
+
peerModels: [],
|
|
52
|
+
configKeys: [],
|
|
53
|
+
env: [],
|
|
54
|
+
events: [],
|
|
55
|
+
hostFacingExceptions: [],
|
|
56
|
+
hostTests: [],
|
|
57
|
+
});
|
|
58
|
+
}
|
package/build/types.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export interface SharedFlags {
|
|
2
|
+
cwd: string;
|
|
3
|
+
yes: boolean;
|
|
4
|
+
dryRun: boolean;
|
|
5
|
+
registry?: string;
|
|
6
|
+
overwrite: boolean;
|
|
7
|
+
}
|
|
8
|
+
/** Opt-in host scaffolding for `add` / `diff` / scaffold. */
|
|
9
|
+
export interface ScaffoldFlags {
|
|
10
|
+
withModels?: boolean;
|
|
11
|
+
withMigrations?: boolean;
|
|
12
|
+
withControllers?: boolean;
|
|
13
|
+
withValidators?: boolean;
|
|
14
|
+
/** Lucid / SDK host I/O → `app/adapters/`. */
|
|
15
|
+
withAdapters?: boolean;
|
|
16
|
+
/** models + migrations + controllers + validators + adapters (not routes). */
|
|
17
|
+
withStubs?: boolean;
|
|
18
|
+
withRoutes?: boolean;
|
|
19
|
+
wireRoutes?: boolean;
|
|
20
|
+
withTests?: boolean;
|
|
21
|
+
}
|
package/build/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/build/wire.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
declare const REQUIRED_IMPORTS: Record<string, string>;
|
|
2
|
+
declare const EMPTY_MODULES_CONFIG = "const modulesConfig: Record<string, { description: string; emits: string[] }> = {}\n\nexport default modulesConfig\n";
|
|
3
|
+
export declare function printWireChecklist(): void;
|
|
4
|
+
export declare function applyWire(cwd: string, dryRun?: boolean): string[];
|
|
5
|
+
export { REQUIRED_IMPORTS, EMPTY_MODULES_CONFIG };
|
|
6
|
+
/**
|
|
7
|
+
* Append a side-effect import of `start/routes/<module>.ts` into
|
|
8
|
+
* `start/routes.ts`. Idempotent. Does not create the module route file.
|
|
9
|
+
*/
|
|
10
|
+
export declare function wireModuleRoute(cwd: string, moduleName: string, dryRun?: boolean): {
|
|
11
|
+
ok: true;
|
|
12
|
+
actions: string[];
|
|
13
|
+
} | {
|
|
14
|
+
ok: false;
|
|
15
|
+
error: string;
|
|
16
|
+
};
|