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.
Files changed (140) hide show
  1. package/README.md +64 -0
  2. package/build/adonis_peers.d.ts +14 -0
  3. package/build/adonis_peers.js +56 -0
  4. package/build/cli.d.ts +2 -0
  5. package/build/cli.js +111 -0
  6. package/build/commands/add.d.ts +18 -0
  7. package/build/commands/add.js +246 -0
  8. package/build/commands/check.d.ts +4 -0
  9. package/build/commands/check.js +159 -0
  10. package/build/commands/diff.d.ts +2 -0
  11. package/build/commands/diff.js +74 -0
  12. package/build/commands/init.d.ts +6 -0
  13. package/build/commands/init.js +124 -0
  14. package/build/commands/list.d.ts +2 -0
  15. package/build/commands/list.js +34 -0
  16. package/build/config_merge.d.ts +10 -0
  17. package/build/config_merge.js +71 -0
  18. package/build/constants_merge.d.ts +4 -0
  19. package/build/constants_merge.js +85 -0
  20. package/build/copy.d.ts +8 -0
  21. package/build/copy.js +33 -0
  22. package/build/host.d.ts +15 -0
  23. package/build/host.js +85 -0
  24. package/build/registry/index.d.ts +26 -0
  25. package/build/registry/index.js +116 -0
  26. package/build/registry/plan.d.ts +53 -0
  27. package/build/registry/plan.js +159 -0
  28. package/build/schema.d.ts +136 -0
  29. package/build/schema.js +58 -0
  30. package/build/types.d.ts +21 -0
  31. package/build/types.js +1 -0
  32. package/build/wire.d.ts +16 -0
  33. package/build/wire.js +162 -0
  34. package/package.json +51 -0
  35. package/registry/README.md +86 -0
  36. package/registry/account/contracts/avatar_storage.ts +7 -0
  37. package/registry/account/contracts/index.ts +7 -0
  38. package/registry/account/contracts/types.ts +23 -0
  39. package/registry/account/events.ts +14 -0
  40. package/registry/account/module.json +31 -0
  41. package/registry/account/options.ts +11 -0
  42. package/registry/account/service.ts +155 -0
  43. package/registry/account/stubs/adapters/account.ts +21 -0
  44. package/registry/account/stubs/adapters/drive_avatar_storage.ts +15 -0
  45. package/registry/account/stubs/controllers/account_controller.ts +190 -0
  46. package/registry/account/stubs/routes/account.ts +53 -0
  47. package/registry/account/stubs/validators/account.ts +37 -0
  48. package/registry/account/tests/account_service.spec.ts +132 -0
  49. package/registry/account/tests/fakes/memory_avatar_storage.ts +12 -0
  50. package/registry/api/envelope.ts +66 -0
  51. package/registry/api/exception.ts +38 -0
  52. package/registry/api/exception_handler.ts +54 -0
  53. package/registry/api/module.json +27 -0
  54. package/registry/api/provider.ts +129 -0
  55. package/registry/api/service.ts +88 -0
  56. package/registry/api/tests/emit_safe.spec.ts +107 -0
  57. package/registry/api/tests/respond.spec.ts +40 -0
  58. package/registry/auth/contracts/index.ts +18 -0
  59. package/registry/auth/contracts/password_reset_store.ts +21 -0
  60. package/registry/auth/contracts/session_manager.ts +19 -0
  61. package/registry/auth/contracts/types.ts +32 -0
  62. package/registry/auth/events.ts +21 -0
  63. package/registry/auth/module.json +45 -0
  64. package/registry/auth/options.ts +23 -0
  65. package/registry/auth/service.ts +150 -0
  66. package/registry/auth/stubs/adapters/auth.ts +21 -0
  67. package/registry/auth/stubs/adapters/lucid_access_token_session.ts +33 -0
  68. package/registry/auth/stubs/adapters/lucid_password_reset_store.ts +68 -0
  69. package/registry/auth/stubs/adapters/lucid_user_store.ts +86 -0
  70. package/registry/auth/stubs/adapters/map_user.ts +19 -0
  71. package/registry/auth/stubs/controllers/auth_controller.ts +126 -0
  72. package/registry/auth/stubs/migrations/add_pending_email_to_users_table.ts +17 -0
  73. package/registry/auth/stubs/migrations/create_password_resets_table.ts +27 -0
  74. package/registry/auth/stubs/migrations/create_users_table.ts +31 -0
  75. package/registry/auth/stubs/models/password_reset.ts +29 -0
  76. package/registry/auth/stubs/models/user.ts +99 -0
  77. package/registry/auth/stubs/providers/vine_provider.ts +43 -0
  78. package/registry/auth/stubs/routes/auth.ts +36 -0
  79. package/registry/auth/stubs/start/limiter.ts +17 -0
  80. package/registry/auth/stubs/validators/auth.ts +48 -0
  81. package/registry/auth/stubs/validators/rules/exists.ts +21 -0
  82. package/registry/auth/stubs/validators/rules/unique.ts +21 -0
  83. package/registry/auth/stubs/validators/rules/valid_password.ts +20 -0
  84. package/registry/auth/stubs/validators/rules/valid_token.ts +27 -0
  85. package/registry/auth/stubs/validators/vine.d.ts +10 -0
  86. package/registry/auth/tests/auth_service.spec.ts +145 -0
  87. package/registry/auth/tests/auth_update_password.spec.ts +99 -0
  88. package/registry/auth/tests/fakes/index.ts +3 -0
  89. package/registry/auth/tests/fakes/memory_password_reset_store.ts +71 -0
  90. package/registry/auth/tests/fakes/memory_session_manager.ts +23 -0
  91. package/registry/auth/tests/fakes/memory_user_store.ts +89 -0
  92. package/registry/constants/exceptions.ts +64 -0
  93. package/registry/constants/index.ts +12 -0
  94. package/registry/constants/responseCodes.ts +87 -0
  95. package/registry/contracts/index.ts +5 -0
  96. package/registry/contracts/user.ts +78 -0
  97. package/registry/creem/contracts/creem_client.ts +34 -0
  98. package/registry/creem/contracts/index.ts +8 -0
  99. package/registry/creem/contracts/types.ts +30 -0
  100. package/registry/creem/events.ts +9 -0
  101. package/registry/creem/module.json +28 -0
  102. package/registry/creem/service.ts +87 -0
  103. package/registry/creem/stubs/adapters/creem.ts +23 -0
  104. package/registry/creem/stubs/adapters/creem_io_client.ts +70 -0
  105. package/registry/creem/tests/fakes/fake_creem_client.ts +68 -0
  106. package/registry/notification/contracts/app_notification_store.ts +8 -0
  107. package/registry/notification/contracts/index.ts +9 -0
  108. package/registry/notification/contracts/mail_transport.ts +7 -0
  109. package/registry/notification/contracts/types.ts +32 -0
  110. package/registry/notification/module.json +23 -0
  111. package/registry/notification/options.ts +11 -0
  112. package/registry/notification/service.ts +103 -0
  113. package/registry/notification/stubs/adapters/adonis_mail_transport.ts +15 -0
  114. package/registry/notification/stubs/adapters/lucid_app_notification_store.ts +21 -0
  115. package/registry/notification/stubs/adapters/notification.ts +36 -0
  116. package/registry/notification/stubs/migrations/create_notifications_table.ts +23 -0
  117. package/registry/notification/stubs/models/app_notification.ts +45 -0
  118. package/registry/notification/tests/fakes/memory_app_notification_store.ts +19 -0
  119. package/registry/notification/tests/fakes/memory_mail_transport.ts +16 -0
  120. package/registry/notification/tests/notification_service.spec.ts +63 -0
  121. package/registry/registry.json +4 -0
  122. package/registry/subscription/contracts/index.ts +9 -0
  123. package/registry/subscription/contracts/subscription_store.ts +15 -0
  124. package/registry/subscription/contracts/types.ts +39 -0
  125. package/registry/subscription/events.ts +13 -0
  126. package/registry/subscription/module.json +31 -0
  127. package/registry/subscription/options.ts +14 -0
  128. package/registry/subscription/service.ts +140 -0
  129. package/registry/subscription/stubs/adapters/lucid_subscription_store.ts +69 -0
  130. package/registry/subscription/stubs/adapters/subscription.ts +21 -0
  131. package/registry/subscription/stubs/migrations/create_subscriptions_table.ts +26 -0
  132. package/registry/subscription/stubs/migrations/subscriptions_user_creem_unique.ts +19 -0
  133. package/registry/subscription/stubs/models/subscription.ts +45 -0
  134. package/registry/subscription/tests/billing_service.spec.ts +189 -0
  135. package/registry/subscription/tests/fakes/memory_subscription_store.ts +63 -0
  136. package/registry/types/api.ts +41 -0
  137. package/registry/types/constants.ts +7 -0
  138. package/registry/types/index.ts +6 -0
  139. package/registry/types/models.ts +32 -0
  140. package/schema/adonia.schema.json +39 -0
@@ -0,0 +1,74 @@
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { relative } from 'node:path';
3
+ import { loadHostConfig } from '../host.js';
4
+ import { loadManifest, resolveRegistry } from '../registry/index.js';
5
+ import { planModuleFiles, planStubs, resolveStubSelect } from '../registry/plan.js';
6
+ import { sha256 } from '../copy.js';
7
+ export async function runDiff(name, flags) {
8
+ if (!name) {
9
+ console.error('Usage: adonia diff <name>');
10
+ process.exitCode = 1;
11
+ return;
12
+ }
13
+ let config;
14
+ try {
15
+ config = loadHostConfig(flags.cwd);
16
+ }
17
+ catch (err) {
18
+ console.error(err instanceof Error ? err.message : err);
19
+ process.exitCode = 1;
20
+ return;
21
+ }
22
+ const registry = await resolveRegistry({
23
+ registryFlag: flags.registry,
24
+ hostRegistry: config.registry,
25
+ ref: config.ref,
26
+ cwd: flags.cwd,
27
+ });
28
+ const manifest = loadManifest(registry, name);
29
+ const warnings = [];
30
+ const stubSelect = resolveStubSelect(flags);
31
+ const plans = [
32
+ ...planModuleFiles(registry, name, manifest, config, flags.cwd),
33
+ ...(stubSelect
34
+ ? planStubs(registry, name, manifest, config, flags.cwd, warnings, stubSelect)
35
+ : []),
36
+ ];
37
+ let differed = false;
38
+ for (const plan of plans) {
39
+ if (!existsSync(plan.dest)) {
40
+ console.log(`--- missing: ${relative(flags.cwd, plan.dest)}`);
41
+ differed = true;
42
+ continue;
43
+ }
44
+ const a = readFileSync(plan.src);
45
+ const b = readFileSync(plan.dest);
46
+ if (sha256(a) === sha256(b))
47
+ continue;
48
+ differed = true;
49
+ console.log(unifiedDiff(relative(flags.cwd, plan.dest), a.toString('utf8'), b.toString('utf8')));
50
+ }
51
+ for (const w of warnings)
52
+ console.warn(w);
53
+ if (differed)
54
+ process.exitCode = 1;
55
+ else
56
+ console.log('No differences.');
57
+ }
58
+ function unifiedDiff(path, registry, host) {
59
+ const a = registry.split('\n');
60
+ const b = host.split('\n');
61
+ const lines = [`--- registry/${path}`, `+++ host/${path}`];
62
+ const max = Math.max(a.length, b.length);
63
+ for (let i = 0; i < max; i++) {
64
+ const left = a[i];
65
+ const right = b[i];
66
+ if (left === right)
67
+ continue;
68
+ if (left !== undefined)
69
+ lines.push(`-${left}`);
70
+ if (right !== undefined)
71
+ lines.push(`+${right}`);
72
+ }
73
+ return lines.join('\n');
74
+ }
@@ -0,0 +1,6 @@
1
+ import type { SharedFlags } from '../types.js';
2
+ export declare function runInit(flags: SharedFlags & {
3
+ wire?: boolean;
4
+ skipCore?: boolean;
5
+ scaffold?: boolean;
6
+ }): Promise<void>;
@@ -0,0 +1,124 @@
1
+ import { defaultHostConfig, isAdonisApp, loadHostConfig, writeHostConfig } from '../host.js';
2
+ import { expandDependencies, resolveRegistry } from '../registry/index.js';
3
+ import { CORE_PACKAGES } from '../schema.js';
4
+ import { applyWire, printWireChecklist } from '../wire.js';
5
+ import { installModules } from './add.js';
6
+ export async function runInit(flags) {
7
+ const cwd = flags.cwd;
8
+ const check = isAdonisApp(cwd);
9
+ if (!check.ok) {
10
+ console.error(check.reason);
11
+ process.exitCode = 1;
12
+ return;
13
+ }
14
+ let wire = Boolean(flags.wire);
15
+ if (flags.scaffold && !wire) {
16
+ console.log('Scaffold implies --wire; enabling host wiring.');
17
+ wire = true;
18
+ }
19
+ let config = defaultHostConfig();
20
+ try {
21
+ config = loadHostConfig(cwd);
22
+ console.log('adonia.json already exists; keeping current config.');
23
+ }
24
+ catch {
25
+ writeHostConfig(cwd, config, flags.dryRun);
26
+ console.log(flags.dryRun ? 'Would write adonia.json' : 'Wrote adonia.json');
27
+ }
28
+ if (wire) {
29
+ const actions = applyWire(cwd, flags.dryRun);
30
+ if (actions.length) {
31
+ console.log(`${flags.dryRun ? 'Would wire' : 'Wired'}: ${actions.join(', ')}`);
32
+ }
33
+ else {
34
+ console.log('Host wiring already up to date.');
35
+ }
36
+ }
37
+ else {
38
+ printWireChecklist();
39
+ }
40
+ let registry;
41
+ try {
42
+ registry = await resolveRegistry({
43
+ registryFlag: flags.registry,
44
+ hostRegistry: config.registry,
45
+ ref: config.ref,
46
+ cwd,
47
+ });
48
+ }
49
+ catch (err) {
50
+ console.error(err instanceof Error ? err.message : err);
51
+ process.exitCode = 1;
52
+ return;
53
+ }
54
+ if (!flags.dryRun) {
55
+ try {
56
+ config = loadHostConfig(cwd);
57
+ }
58
+ catch {
59
+ /* keep in-memory default */
60
+ }
61
+ }
62
+ if (flags.skipCore) {
63
+ console.log('Skipping core install (--skip-core).');
64
+ }
65
+ else {
66
+ if (!flags.yes && !flags.dryRun) {
67
+ console.log('Install shared API core into ./modules? (yes)');
68
+ }
69
+ const coreNames = ['api', ...CORE_PACKAGES];
70
+ const toInstall = expandDependencies(registry, coreNames, new Set(config.installed), flags.overwrite);
71
+ if (!toInstall.length) {
72
+ console.log('Core already installed.');
73
+ }
74
+ else {
75
+ const result = await installModules({
76
+ names: toInstall,
77
+ flags: { ...flags, yes: true, withTests: false, suppressNextSteps: true },
78
+ config,
79
+ registry,
80
+ });
81
+ if (result.conflicts.length || result.wireErrors.length) {
82
+ process.exitCode = 1;
83
+ }
84
+ if (!flags.dryRun) {
85
+ try {
86
+ config = loadHostConfig(cwd);
87
+ }
88
+ catch {
89
+ /* keep */
90
+ }
91
+ }
92
+ }
93
+ }
94
+ if (!flags.scaffold)
95
+ return;
96
+ const featureNames = registry.index.modules;
97
+ if (!featureNames.length) {
98
+ console.log('No feature modules in registry to scaffold.');
99
+ return;
100
+ }
101
+ console.log(`Scaffolding feature modules: ${featureNames.join(', ')}`);
102
+ const ordered = expandDependencies(registry, featureNames, new Set(config.installed), flags.overwrite);
103
+ if (!ordered.length) {
104
+ console.log('Feature modules already installed. Use --overwrite to recopy stubs/routes.');
105
+ // Still attempt route wiring for already-installed modules when route files exist
106
+ return;
107
+ }
108
+ const result = await installModules({
109
+ names: ordered,
110
+ flags: {
111
+ ...flags,
112
+ yes: true,
113
+ withStubs: true,
114
+ withRoutes: true,
115
+ wireRoutes: true,
116
+ withTests: false,
117
+ },
118
+ config,
119
+ registry,
120
+ });
121
+ if (result.conflicts.length || result.wireErrors.length) {
122
+ process.exitCode = 1;
123
+ }
124
+ }
@@ -0,0 +1,2 @@
1
+ import type { SharedFlags } from '../types.js';
2
+ export declare function runList(flags: SharedFlags): Promise<void>;
@@ -0,0 +1,34 @@
1
+ import { loadHostConfig } from '../host.js';
2
+ import { listAllModuleNames, loadManifest, resolveRegistry } from '../registry/index.js';
3
+ export async function runList(flags) {
4
+ let installed = new Set();
5
+ let hostRegistry;
6
+ let ref;
7
+ try {
8
+ const config = loadHostConfig(flags.cwd);
9
+ installed = new Set(config.installed);
10
+ hostRegistry = config.registry;
11
+ ref = config.ref;
12
+ }
13
+ catch {
14
+ console.log('(no adonia.json — showing registry only; run npx adonia init)');
15
+ }
16
+ const registry = await resolveRegistry({
17
+ registryFlag: flags.registry,
18
+ hostRegistry,
19
+ ref,
20
+ cwd: flags.cwd,
21
+ });
22
+ console.log(`Registry (${registry.source}): ${registry.root}\n`);
23
+ for (const name of listAllModuleNames(registry)) {
24
+ let description = '';
25
+ try {
26
+ description = loadManifest(registry, name).description;
27
+ }
28
+ catch {
29
+ description = '';
30
+ }
31
+ const mark = installed.has(name) ? 'installed' : 'available';
32
+ console.log(` ${name.padEnd(16)} [${mark}] ${description}`);
33
+ }
34
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Insert or replace a single module key in config/modules.ts.
3
+ * Uses a lightweight text approach so we don't need a TS parser.
4
+ */
5
+ export declare function mergeModulesConfig(path: string, name: string, description: string, events: string[], dryRun?: boolean): {
6
+ ok: true;
7
+ } | {
8
+ ok: false;
9
+ snippet: string;
10
+ };
@@ -0,0 +1,71 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ /**
3
+ * Insert or replace a single module key in config/modules.ts.
4
+ * Uses a lightweight text approach so we don't need a TS parser.
5
+ */
6
+ export function mergeModulesConfig(path, name, description, events, dryRun = false) {
7
+ const entry = buildEntry(name, description, events);
8
+ if (!existsSync(path)) {
9
+ const content = `const modulesConfig: Record<string, { description: string; emits: string[] }> = {\n${entry}\n}\n\nexport default modulesConfig\n`;
10
+ if (!dryRun)
11
+ writeFileSync(path, content);
12
+ return { ok: true };
13
+ }
14
+ const original = readFileSync(path, 'utf8');
15
+ if (!/modulesConfig\s*[:=]/.test(original) && !/export\s+default/.test(original)) {
16
+ return { ok: false, snippet: entry };
17
+ }
18
+ // Replace existing key block or insert before closing brace of the object
19
+ const keyRe = new RegExp(`(^|\\n)\\s*${escapeRegExp(name)}\\s*:\\s*\\{[\\s\\S]*?\\n\\s*\\},?`, 'm');
20
+ let next;
21
+ if (keyRe.test(original)) {
22
+ next = original.replace(keyRe, `$1${entry}`);
23
+ }
24
+ else {
25
+ // Find the modulesConfig object closing
26
+ const openMatch = original.match(/((?:const|let|var)\s+modulesConfig[^=]*=\s*\{|modulesConfig\s*[:=]\s*\{)/);
27
+ if (!openMatch || openMatch.index === undefined) {
28
+ return { ok: false, snippet: entry };
29
+ }
30
+ const start = openMatch.index + openMatch[0].length;
31
+ const close = findMatchingBrace(original, start - 1);
32
+ if (close === -1)
33
+ return { ok: false, snippet: entry };
34
+ const before = original.slice(0, close);
35
+ const after = original.slice(close);
36
+ const needsComma = /[^\s,{]$/.test(before.trimEnd()) || /emits:\s*\[[^\]]*\]\s*$/.test(before);
37
+ const trimmed = before.replace(/\s*$/, '');
38
+ const comma = trimmed.endsWith(',') || trimmed.endsWith('{') ? '' : ',';
39
+ next = `${trimmed}${comma}\n${entry}\n${after}`;
40
+ void needsComma;
41
+ }
42
+ if (!dryRun)
43
+ writeFileSync(path, next);
44
+ return { ok: true };
45
+ }
46
+ function buildEntry(name, description, events) {
47
+ const emits = events.map((e) => ` '${e}',`).join('\n');
48
+ return ` ${name}: {
49
+ description: ${JSON.stringify(description)},
50
+ emits: [
51
+ ${emits}
52
+ ],
53
+ },`;
54
+ }
55
+ function escapeRegExp(s) {
56
+ return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
57
+ }
58
+ function findMatchingBrace(source, openIndex) {
59
+ let depth = 0;
60
+ for (let i = openIndex; i < source.length; i++) {
61
+ const ch = source[i];
62
+ if (ch === '{')
63
+ depth++;
64
+ else if (ch === '}') {
65
+ depth--;
66
+ if (depth === 0)
67
+ return i;
68
+ }
69
+ }
70
+ return -1;
71
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Merge registry constant catalogs into the host copy without deleting host keys.
3
+ */
4
+ export declare function mergeConstantsCatalogs(registryConstantsDir: string, hostConstantsDir: string, dryRun?: boolean): string[];
@@ -0,0 +1,85 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { join } from 'node:path';
3
+ const CATALOG_FILES = ['exceptions.ts', 'responseCodes.ts'];
4
+ /**
5
+ * Merge registry constant catalogs into the host copy without deleting host keys.
6
+ */
7
+ export function mergeConstantsCatalogs(registryConstantsDir, hostConstantsDir, dryRun = false) {
8
+ const warnings = [];
9
+ for (const file of CATALOG_FILES) {
10
+ const src = join(registryConstantsDir, file);
11
+ const dest = join(hostConstantsDir, file);
12
+ if (!existsSync(src) || !existsSync(dest))
13
+ continue;
14
+ const result = mergeOneCatalog(src, dest, dryRun);
15
+ if (result)
16
+ warnings.push(result);
17
+ }
18
+ return warnings;
19
+ }
20
+ function mergeOneCatalog(src, dest, dryRun) {
21
+ const registryText = readFileSync(src, 'utf8');
22
+ const hostText = readFileSync(dest, 'utf8');
23
+ const regEntries = parseCatalogEntries(registryText);
24
+ const hostEntries = parseCatalogEntries(hostText);
25
+ if (!regEntries || !hostEntries) {
26
+ return `Could not parse ${dest} for constants merge; copy keys from the registry by hand.`;
27
+ }
28
+ let inserted = 0;
29
+ const conflicts = [];
30
+ const hostKeys = new Set(Object.keys(hostEntries.map));
31
+ let nextBody = hostEntries.body;
32
+ for (const [key, value] of Object.entries(regEntries.map)) {
33
+ if (!hostKeys.has(key)) {
34
+ // insert before closing brace of object
35
+ const insert = ` ${key}: ${value},\n`;
36
+ nextBody = nextBody.replace(/\n\}\s*$/, `\n${insert}}`);
37
+ inserted++;
38
+ continue;
39
+ }
40
+ if (normalizeEntry(hostEntries.map[key]) !== normalizeEntry(value)) {
41
+ conflicts.push(key);
42
+ }
43
+ }
44
+ if (inserted && !dryRun) {
45
+ writeFileSync(dest, hostText.slice(0, hostEntries.start) + nextBody + hostText.slice(hostEntries.end));
46
+ }
47
+ if (conflicts.length) {
48
+ return `Constants conflict in ${dest}: ${conflicts.join(', ')}`;
49
+ }
50
+ return null;
51
+ }
52
+ function normalizeEntry(s) {
53
+ return s.replace(/\s+/g, '');
54
+ }
55
+ function parseCatalogEntries(text) {
56
+ // Find first `= {` after export/const
57
+ const m = text.match(/=\s*\{/);
58
+ if (!m || m.index === undefined)
59
+ return null;
60
+ const open = m.index + m[0].length - 1;
61
+ let depth = 0;
62
+ let end = -1;
63
+ for (let i = open; i < text.length; i++) {
64
+ if (text[i] === '{')
65
+ depth++;
66
+ else if (text[i] === '}') {
67
+ depth--;
68
+ if (depth === 0) {
69
+ end = i + 1;
70
+ break;
71
+ }
72
+ }
73
+ }
74
+ if (end === -1)
75
+ return null;
76
+ const body = text.slice(open, end);
77
+ const map = {};
78
+ // Match KEY: { ... }, at top level
79
+ const entryRe = /(\w+)\s*:\s*(\{[^}]*\})/g;
80
+ let match;
81
+ while ((match = entryRe.exec(body))) {
82
+ map[match[1]] = match[2];
83
+ }
84
+ return { map, body, start: open, end };
85
+ }
@@ -0,0 +1,8 @@
1
+ export type CopyResult = 'copied' | 'skipped' | 'conflict' | 'would-copy' | 'would-skip' | 'would-conflict';
2
+ export interface CopyOptions {
3
+ overwrite?: boolean;
4
+ dryRun?: boolean;
5
+ }
6
+ export declare function sha256(content: Buffer | string): string;
7
+ export declare function copyFileWithPolicy(src: string, dest: string, options?: CopyOptions): CopyResult;
8
+ export declare function ensureDir(path: string, dryRun?: boolean): void;
package/build/copy.js ADDED
@@ -0,0 +1,33 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
3
+ import { dirname } from 'node:path';
4
+ export function sha256(content) {
5
+ return createHash('sha256').update(content).digest('hex');
6
+ }
7
+ export function copyFileWithPolicy(src, dest, options = {}) {
8
+ const { overwrite = false, dryRun = false } = options;
9
+ const srcBuf = readFileSync(src);
10
+ if (!existsSync(dest)) {
11
+ if (dryRun)
12
+ return 'would-copy';
13
+ mkdirSync(dirname(dest), { recursive: true });
14
+ copyFileSync(src, dest);
15
+ return 'copied';
16
+ }
17
+ const destBuf = readFileSync(dest);
18
+ if (sha256(srcBuf) === sha256(destBuf)) {
19
+ return dryRun ? 'would-skip' : 'skipped';
20
+ }
21
+ if (!overwrite) {
22
+ return dryRun ? 'would-conflict' : 'conflict';
23
+ }
24
+ if (dryRun)
25
+ return 'would-copy';
26
+ writeFileSync(dest, srcBuf);
27
+ return 'copied';
28
+ }
29
+ export function ensureDir(path, dryRun = false) {
30
+ if (dryRun)
31
+ return;
32
+ mkdirSync(path, { recursive: true });
33
+ }
@@ -0,0 +1,15 @@
1
+ import { type HostModulesConfig } from './schema.js';
2
+ export declare const ADONIA_JSON = "adonia.json";
3
+ /** @deprecated Read-only fallback for one minor after rename. */
4
+ export declare const LEGACY_MODULES_JSON = "modules.json";
5
+ export declare function packageVersion(): string;
6
+ export declare function isAdonisApp(cwd: string): {
7
+ ok: true;
8
+ } | {
9
+ ok: false;
10
+ reason: string;
11
+ };
12
+ export declare function loadHostConfig(cwd: string): HostModulesConfig;
13
+ export declare function writeHostConfig(cwd: string, config: HostModulesConfig, dryRun?: boolean): void;
14
+ export declare function defaultHostConfig(): HostModulesConfig;
15
+ export declare function detectPackageManager(cwd: string): 'npm' | 'pnpm' | 'yarn';
package/build/host.js ADDED
@@ -0,0 +1,85 @@
1
+ import { existsSync, readFileSync, writeFileSync } from 'node:fs';
2
+ import { createRequire } from 'node:module';
3
+ import { dirname, join } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+ import { hostModulesSchema } from './schema.js';
6
+ export const ADONIA_JSON = 'adonia.json';
7
+ /** @deprecated Read-only fallback for one minor after rename. */
8
+ export const LEGACY_MODULES_JSON = 'modules.json';
9
+ const require = createRequire(import.meta.url);
10
+ export function packageVersion() {
11
+ try {
12
+ const pkgPath = join(dirname(fileURLToPath(import.meta.url)), '../package.json');
13
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
14
+ return pkg.version ?? '0.0.0';
15
+ }
16
+ catch {
17
+ try {
18
+ return require('../package.json').version;
19
+ }
20
+ catch {
21
+ return '0.0.0';
22
+ }
23
+ }
24
+ }
25
+ export function isAdonisApp(cwd) {
26
+ const adonisrc = join(cwd, 'adonisrc.ts');
27
+ const pkgPath = join(cwd, 'package.json');
28
+ if (!existsSync(adonisrc)) {
29
+ return { ok: false, reason: 'adonisrc.ts not found — not an Adonis app' };
30
+ }
31
+ if (!existsSync(pkgPath)) {
32
+ return { ok: false, reason: 'package.json not found' };
33
+ }
34
+ const pkg = JSON.parse(readFileSync(pkgPath, 'utf8'));
35
+ const deps = { ...pkg.dependencies, ...pkg.devDependencies };
36
+ if (!deps['@adonisjs/core']) {
37
+ return { ok: false, reason: 'package.json does not depend on @adonisjs/core' };
38
+ }
39
+ return { ok: true };
40
+ }
41
+ function configPath(cwd) {
42
+ const primary = join(cwd, ADONIA_JSON);
43
+ if (existsSync(primary))
44
+ return primary;
45
+ const legacy = join(cwd, LEGACY_MODULES_JSON);
46
+ if (existsSync(legacy))
47
+ return legacy;
48
+ throw new Error(`Missing ${ADONIA_JSON}. Run \`npx adonia init\` first.`);
49
+ }
50
+ export function loadHostConfig(cwd) {
51
+ const path = configPath(cwd);
52
+ return hostModulesSchema.parse(JSON.parse(readFileSync(path, 'utf8')));
53
+ }
54
+ export function writeHostConfig(cwd, config, dryRun = false) {
55
+ if (dryRun)
56
+ return;
57
+ writeFileSync(join(cwd, ADONIA_JSON), `${JSON.stringify(config, null, 2)}\n`);
58
+ }
59
+ export function defaultHostConfig() {
60
+ return hostModulesSchema.parse({
61
+ $schema: './node_modules/adonia/schema/adonia.schema.json',
62
+ registry: 'bundled',
63
+ ref: packageVersion(),
64
+ paths: {
65
+ modules: 'modules',
66
+ models: 'app/models',
67
+ migrations: 'database/migrations',
68
+ controllers: 'app/controllers',
69
+ validators: 'app/validators',
70
+ },
71
+ aliases: {
72
+ modules: '#modules',
73
+ constants: '#constants',
74
+ models: '#models',
75
+ },
76
+ installed: [],
77
+ });
78
+ }
79
+ export function detectPackageManager(cwd) {
80
+ if (existsSync(join(cwd, 'pnpm-lock.yaml')))
81
+ return 'pnpm';
82
+ if (existsSync(join(cwd, 'yarn.lock')))
83
+ return 'yarn';
84
+ return 'npm';
85
+ }
@@ -0,0 +1,26 @@
1
+ import { type ModuleManifest, type RegistryIndex } from '../schema.js';
2
+ export interface Registry {
3
+ root: string;
4
+ index: RegistryIndex;
5
+ source: 'flag' | 'bundled';
6
+ }
7
+ export declare function bundledRegistryPath(): string;
8
+ export declare function loadRegistryIndex(root: string): RegistryIndex;
9
+ /**
10
+ * Resolution order:
11
+ * 1. --registry <dir>
12
+ * 2. bundled (adonia.json "bundled" or empty)
13
+ * 3. local path in adonia.json
14
+ * github:… is rejected until remote materialization lands.
15
+ */
16
+ export declare function resolveRegistry(options: {
17
+ registryFlag?: string;
18
+ hostRegistry?: string;
19
+ ref?: string;
20
+ cwd: string;
21
+ }): Promise<Registry>;
22
+ export declare function loadManifest(registry: Registry, name: string): ModuleManifest;
23
+ export declare function expandDependencies(registry: Registry, names: string[], installed: Set<string>, overwrite: boolean): string[];
24
+ export declare function listAllModuleNames(registry: Registry): string[];
25
+ export declare function moduleDir(registry: Registry, name: string): string;
26
+ export declare function relativeFromRegistry(registry: Registry, absPath: string): string;