anhedral 0.10.1 → 0.11.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 +77 -38
- package/assets/{anhedral-cli-init-technical.svg → anhedral-stack-technical.svg} +6 -6
- package/assets/{anhedral-cli-init.svg → anhedral-stack.svg} +7 -7
- package/dist/bin.js +271 -154
- package/dist/capabilities.d.ts +3 -3
- package/dist/capability-contract.d.ts +47 -0
- package/dist/capability-contract.js +136 -0
- package/dist/cli-arguments.d.ts +16 -0
- package/dist/cli-arguments.js +115 -0
- package/dist/cli-output.d.ts +8 -0
- package/dist/cli-output.js +211 -0
- package/dist/cloudflare.d.ts +7 -2
- package/dist/cloudflare.js +166 -36
- package/dist/command-schema.d.ts +21 -0
- package/dist/command-schema.js +374 -0
- package/dist/delivery.d.ts +2 -2
- package/dist/delivery.js +21 -4
- package/dist/index.d.ts +23 -1
- package/dist/index.js +15 -1
- package/dist/inspector-model.d.ts +115 -0
- package/dist/inspector-model.js +1 -0
- package/dist/lifecycle-model.d.ts +15 -0
- package/dist/lifecycle-model.js +20 -0
- package/dist/lifecycle.d.ts +12 -0
- package/dist/lifecycle.js +92 -0
- package/dist/mobile-delivery.d.ts +100 -0
- package/dist/mobile-delivery.js +319 -0
- package/dist/platforms/mobile.js +8 -5
- package/dist/project-inspector.d.ts +4 -0
- package/dist/project-inspector.js +646 -0
- package/dist/project-state.d.ts +17 -0
- package/dist/project-state.js +239 -11
- package/dist/provider-auth.d.ts +41 -0
- package/dist/provider-auth.js +210 -0
- package/dist/providers/adapters.d.ts +17 -0
- package/dist/providers/adapters.js +269 -0
- package/dist/providers/api.d.ts +28 -0
- package/dist/providers/api.js +252 -0
- package/dist/providers/config.d.ts +15 -0
- package/dist/providers/config.js +184 -0
- package/dist/providers/definitions.d.ts +318 -0
- package/dist/providers/definitions.js +127 -0
- package/dist/providers/provision.d.ts +24 -0
- package/dist/providers/provision.js +76 -0
- package/dist/providers/receipts.d.ts +20 -0
- package/dist/providers/receipts.js +66 -0
- package/dist/providers/recovery-verification.d.ts +7 -0
- package/dist/providers/recovery-verification.js +112 -0
- package/dist/providers/recovery.d.ts +30 -0
- package/dist/providers/recovery.js +34 -0
- package/dist/providers/runtime.d.ts +10 -0
- package/dist/providers/runtime.js +231 -0
- package/dist/providers/schema.d.ts +28 -0
- package/dist/providers/schema.js +49 -0
- package/dist/providers/state.d.ts +56 -0
- package/dist/providers/state.js +329 -0
- package/dist/provision.d.ts +1 -1
- package/dist/provision.js +61 -3
- package/dist/registry/add.d.ts +6 -0
- package/dist/registry/add.js +29 -1
- package/dist/registry/commands.d.ts +3 -2
- package/dist/registry/commands.js +53 -14
- package/dist/registry/options.js +3 -2
- package/dist/registry/preview.d.ts +11 -0
- package/dist/registry/preview.js +91 -0
- package/dist/registry/usage.d.ts +10 -0
- package/dist/registry/usage.js +22 -37
- package/dist/scaffold/auth.js +3 -19
- package/dist/scaffold/workspace.js +11 -0
- package/dist/ship.d.ts +320 -0
- package/dist/ship.js +211 -0
- package/dist/stack-registry.d.ts +2 -2
- package/dist/stack-registry.js +7 -1
- package/dist/standard.d.ts +2 -1
- package/dist/standard.js +11 -11
- package/dist/vercel.d.ts +3 -3
- package/dist/vercel.js +27 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/docs/application-stack-standard.md +51 -80
- package/docs/cli-design.md +67 -0
- package/docs/delivery-workflow.md +29 -15
- package/docs/plugin-ui.md +61 -0
- package/docs/provider-configuration.md +117 -0
- package/package.json +16 -12
- package/dist/managed-hosting.d.ts +0 -49
- package/dist/managed-hosting.js +0 -373
- package/docs/managed-hosting-architecture.md +0 -87
- package/docs/sponsorships.md +0 -25
|
@@ -1,16 +1,28 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
+
import { CAPABILITY_CONTRACT, formatCapabilityContract } from '../capability-contract.js';
|
|
2
3
|
import { addStackItems } from './add.js';
|
|
3
|
-
import { STACK_REGISTRY, getStackItem } from '../stack-registry.js';
|
|
4
|
-
|
|
4
|
+
import { STACK_REGISTRY, STANDARD_PRODUCTS, getStackItem } from '../stack-registry.js';
|
|
5
|
+
import { printResult } from '../cli-output.js';
|
|
6
|
+
import { commandHelp } from './usage.js';
|
|
7
|
+
import { CliArgumentError, suggest } from '../cli-arguments.js';
|
|
8
|
+
export async function runRegistry(args, json, output = { json }) {
|
|
5
9
|
const positional = args.filter((arg) => arg !== '--json');
|
|
6
10
|
if (positional.includes('--help') || positional.includes('-h')) {
|
|
7
|
-
console.log('
|
|
11
|
+
console.log(commandHelp('registry'));
|
|
8
12
|
return;
|
|
9
13
|
}
|
|
10
14
|
if (positional.some((arg) => arg.startsWith('-')))
|
|
11
15
|
throw new Error('Unknown registry option.');
|
|
12
16
|
const [action = 'list', name, ...extra] = positional;
|
|
17
|
+
if (action === 'capabilities' && !name && !extra.length) {
|
|
18
|
+
if (output.quiet && !json)
|
|
19
|
+
return;
|
|
20
|
+
console.log(json ? JSON.stringify(CAPABILITY_CONTRACT, null, 2) : formatCapabilityContract());
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
13
23
|
if (action === 'list' && !name && !extra.length) {
|
|
24
|
+
if (output.quiet && !json)
|
|
25
|
+
return;
|
|
14
26
|
console.log(json
|
|
15
27
|
? JSON.stringify(STACK_REGISTRY, null, 2)
|
|
16
28
|
: STACK_REGISTRY.items
|
|
@@ -19,30 +31,57 @@ export async function runRegistry(args, json) {
|
|
|
19
31
|
return;
|
|
20
32
|
}
|
|
21
33
|
if (action === 'view' && name && !extra.length) {
|
|
22
|
-
|
|
34
|
+
if (!STACK_REGISTRY.items.some((item) => item.name === name)) {
|
|
35
|
+
const correction = suggest(name, STACK_REGISTRY.items.map((item) => item.name));
|
|
36
|
+
throw new CliArgumentError(`Unknown bundled registry item.${correction ? ` Did you mean ${correction}?` : ''}`, 'Run anhedral registry list.');
|
|
37
|
+
}
|
|
38
|
+
printResult('registry', getStackItem(name), { ...output, json });
|
|
23
39
|
return;
|
|
24
40
|
}
|
|
25
|
-
throw new Error('Use registry list
|
|
41
|
+
throw new Error('Use registry list, registry view <item>, or registry capabilities.');
|
|
26
42
|
}
|
|
27
|
-
export async function runAdd(args) {
|
|
43
|
+
export async function runAdd(args, output = {}) {
|
|
28
44
|
if (args.includes('--help') || args.includes('-h')) {
|
|
29
|
-
console.log('
|
|
45
|
+
console.log(commandHelp('add'));
|
|
30
46
|
return;
|
|
31
47
|
}
|
|
32
48
|
const positional = [];
|
|
33
|
-
|
|
49
|
+
let preview;
|
|
50
|
+
for (let index = 0; index < args.length; index++) {
|
|
51
|
+
const arg = args[index];
|
|
52
|
+
if (arg === '--diff' || arg === '--view') {
|
|
53
|
+
if (preview)
|
|
54
|
+
throw new Error('Select one source preview: --diff or --view.');
|
|
55
|
+
preview = { mode: arg === '--diff' ? 'diff' : 'view' };
|
|
56
|
+
const next = args[index + 1];
|
|
57
|
+
if (next &&
|
|
58
|
+
!next.startsWith('-') &&
|
|
59
|
+
!STANDARD_PRODUCTS.includes(next)) {
|
|
60
|
+
preview.path = next;
|
|
61
|
+
index++;
|
|
62
|
+
}
|
|
63
|
+
continue;
|
|
64
|
+
}
|
|
34
65
|
if (['--dry-run', '--skip-install', '--json'].includes(arg))
|
|
35
66
|
continue;
|
|
36
67
|
if (arg.startsWith('-'))
|
|
37
68
|
throw new Error(`Unknown add option: ${arg}.`);
|
|
38
69
|
positional.push(arg);
|
|
39
70
|
}
|
|
40
|
-
const [
|
|
41
|
-
if (
|
|
42
|
-
|
|
43
|
-
|
|
71
|
+
const hasDirectory = positional[0] && !STANDARD_PRODUCTS.includes(positional[0]);
|
|
72
|
+
if (hasDirectory && positional.length === 1) {
|
|
73
|
+
const correction = suggest(positional[0], STANDARD_PRODUCTS);
|
|
74
|
+
if (correction)
|
|
75
|
+
throw new CliArgumentError(`Unknown stack part. Did you mean ${correction}?`, 'Run anhedral registry list.');
|
|
76
|
+
}
|
|
77
|
+
const directory = hasDirectory ? positional.shift() : process.cwd();
|
|
78
|
+
const items = positional;
|
|
79
|
+
if (!items.length)
|
|
80
|
+
throw new Error('Select bundled parts: anhedral add <items...> [--cwd <directory>].');
|
|
81
|
+
printResult('add', await addStackItems(path.resolve(directory), {
|
|
44
82
|
items,
|
|
45
|
-
dryRun: args.includes('--dry-run'),
|
|
83
|
+
dryRun: args.includes('--dry-run') || Boolean(preview),
|
|
46
84
|
skipInstall: args.includes('--skip-install'),
|
|
47
|
-
|
|
85
|
+
...(preview ? { preview } : {}),
|
|
86
|
+
}), { ...output, json: args.includes('--json') });
|
|
48
87
|
}
|
package/dist/registry/options.js
CHANGED
|
@@ -46,7 +46,8 @@ function parseStandardFlags(remaining) {
|
|
|
46
46
|
}
|
|
47
47
|
export function parseStandardOptions(command, args) {
|
|
48
48
|
const remaining = [...args];
|
|
49
|
-
const
|
|
49
|
+
const hasDirectory = remaining[0] && !remaining[0].startsWith('-');
|
|
50
|
+
const directory = command === 'new' || hasDirectory ? remaining.shift() : process.cwd();
|
|
50
51
|
if (!directory || directory.startsWith('-'))
|
|
51
52
|
throw new Error('new requires a destination directory.');
|
|
52
53
|
const root = path.resolve(directory);
|
|
@@ -60,6 +61,6 @@ export function parseStandardOptions(command, args) {
|
|
|
60
61
|
skipInstall: remaining.includes('--skip-install'),
|
|
61
62
|
dryRun: remaining.includes('--dry-run'),
|
|
62
63
|
json: remaining.includes('--json'),
|
|
63
|
-
initializeGit: gitSpecified ?? command === 'new',
|
|
64
|
+
initializeGit: gitSpecified ?? (command === 'new' || Boolean(hasDirectory)),
|
|
64
65
|
};
|
|
65
66
|
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export declare const MAX_PREVIEW_TOTAL_BYTES: number;
|
|
2
|
+
export interface SourcePreview {
|
|
3
|
+
path: string;
|
|
4
|
+
content?: string;
|
|
5
|
+
diff?: string;
|
|
6
|
+
unavailable?: string;
|
|
7
|
+
}
|
|
8
|
+
export declare function validatePreviewPath(file: string): void;
|
|
9
|
+
/** A single contextual hunk is linear in file size and remains an applicable unified patch. */
|
|
10
|
+
export declare function sourceDiff(file: string, before: string | undefined, after: string): string;
|
|
11
|
+
export declare function sourcePreview(root: string, stage: string, file: string, mode: 'diff' | 'view'): SourcePreview;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { readBoundedFile } from '../bounded-file.js';
|
|
4
|
+
const MAX_PREVIEW_FILE_BYTES = 256 * 1024;
|
|
5
|
+
export const MAX_PREVIEW_TOTAL_BYTES = 1024 * 1024;
|
|
6
|
+
export function validatePreviewPath(file) {
|
|
7
|
+
if (!file ||
|
|
8
|
+
path.posix.isAbsolute(file) ||
|
|
9
|
+
file.includes('\\') ||
|
|
10
|
+
/[\x00-\x1f\x7f]/.test(file) ||
|
|
11
|
+
file
|
|
12
|
+
.split('/')
|
|
13
|
+
.some((part) => !part ||
|
|
14
|
+
['.', '..', '.anhedral'].includes(part) ||
|
|
15
|
+
(/^(?:\.env|\.dev\.vars)(?:\.|$)/.test(part) && !part.endsWith('.example'))))
|
|
16
|
+
throw new Error('Select a relative generated source path; private environment and state files cannot be previewed.');
|
|
17
|
+
}
|
|
18
|
+
/** A single contextual hunk is linear in file size and remains an applicable unified patch. */
|
|
19
|
+
export function sourceDiff(file, before, after) {
|
|
20
|
+
const lines = (content) => content === '' ? [] : content.split('\n').slice(0, content.endsWith('\n') ? -1 : undefined);
|
|
21
|
+
const oldLines = lines(before ?? '');
|
|
22
|
+
const newLines = lines(after);
|
|
23
|
+
if (before === after)
|
|
24
|
+
return '';
|
|
25
|
+
let prefix = 0;
|
|
26
|
+
while (prefix < oldLines.length &&
|
|
27
|
+
prefix < newLines.length &&
|
|
28
|
+
oldLines[prefix] === newLines[prefix])
|
|
29
|
+
prefix++;
|
|
30
|
+
// Newline-only changes must still include the final line in the patch.
|
|
31
|
+
if (prefix && oldLines.length === newLines.length && prefix === oldLines.length)
|
|
32
|
+
prefix--;
|
|
33
|
+
let suffix = 0;
|
|
34
|
+
while ((before ?? '').endsWith('\n') === after.endsWith('\n') &&
|
|
35
|
+
suffix < oldLines.length - prefix &&
|
|
36
|
+
suffix < newLines.length - prefix &&
|
|
37
|
+
oldLines.at(-suffix - 1) === newLines.at(-suffix - 1))
|
|
38
|
+
suffix++;
|
|
39
|
+
const start = Math.max(0, prefix - 3);
|
|
40
|
+
const oldEnd = Math.min(oldLines.length, oldLines.length - suffix + 3);
|
|
41
|
+
const newEnd = Math.min(newLines.length, newLines.length - suffix + 3);
|
|
42
|
+
const output = [
|
|
43
|
+
`diff --git a/${file} b/${file}`,
|
|
44
|
+
...(before === undefined ? ['new file mode 100644'] : []),
|
|
45
|
+
`--- ${before === undefined ? '/dev/null' : `a/${file}`}`,
|
|
46
|
+
`+++ b/${file}`,
|
|
47
|
+
`@@ -${oldEnd - start ? start + 1 : start},${oldEnd - start} +${newEnd - start ? start + 1 : start},${newEnd - start} @@`,
|
|
48
|
+
];
|
|
49
|
+
if (before === undefined && !after)
|
|
50
|
+
return output.slice(0, 2).join('\n') + '\n';
|
|
51
|
+
const append = (prefix, line, last, content) => {
|
|
52
|
+
output.push(`${prefix}${line}`);
|
|
53
|
+
if (last && !content.endsWith('\n'))
|
|
54
|
+
output.push('\');
|
|
55
|
+
};
|
|
56
|
+
for (let index = start; index < prefix; index++)
|
|
57
|
+
output.push(` ${oldLines[index]}`);
|
|
58
|
+
for (let index = prefix; index < oldLines.length - suffix; index++)
|
|
59
|
+
append('-', oldLines[index], index === oldLines.length - 1, before ?? '');
|
|
60
|
+
for (let index = prefix; index < newLines.length - suffix; index++)
|
|
61
|
+
append('+', newLines[index], index === newLines.length - 1, after);
|
|
62
|
+
for (let index = oldLines.length - suffix; index < oldEnd; index++)
|
|
63
|
+
append(' ', oldLines[index], index === oldLines.length - 1, after);
|
|
64
|
+
return output.join('\n') + '\n';
|
|
65
|
+
}
|
|
66
|
+
export function sourcePreview(root, stage, file, mode) {
|
|
67
|
+
validatePreviewPath(file);
|
|
68
|
+
const decode = (directory) => new TextDecoder('utf-8', { fatal: true }).decode(readBoundedFile(path.join(directory, file), MAX_PREVIEW_FILE_BYTES));
|
|
69
|
+
let after;
|
|
70
|
+
let before;
|
|
71
|
+
try {
|
|
72
|
+
after = decode(stage);
|
|
73
|
+
if (after.includes('\x00'))
|
|
74
|
+
throw new Error('Binary file');
|
|
75
|
+
if (mode === 'diff' && existsSync(path.join(root, file))) {
|
|
76
|
+
before = decode(root);
|
|
77
|
+
if (before.includes('\x00'))
|
|
78
|
+
throw new Error('Binary file');
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
return {
|
|
83
|
+
path: file,
|
|
84
|
+
unavailable: 'Binary, nonregular or oversized file; source preview is unavailable (256 KiB limit).',
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
path: file,
|
|
89
|
+
...(mode === 'view' ? { content: after } : { diff: sourceDiff(file, before, after) }),
|
|
90
|
+
};
|
|
91
|
+
}
|
package/dist/registry/usage.d.ts
CHANGED
|
@@ -1 +1,11 @@
|
|
|
1
|
+
export declare const COMMAND_HELP: {
|
|
2
|
+
[k: string]: {
|
|
3
|
+
options: string[];
|
|
4
|
+
description: string;
|
|
5
|
+
usage: string;
|
|
6
|
+
examples: readonly string[];
|
|
7
|
+
note?: string;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
10
|
+
export declare function commandHelp(command: string): string | undefined;
|
|
1
11
|
export declare const STANDARD_USAGE: string;
|
package/dist/registry/usage.js
CHANGED
|
@@ -1,37 +1,22 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
anhedral
|
|
23
|
-
anhedral connect [directory] --provider cloudflare [--account <id>] --audience public|private [--allow-email <email>]
|
|
24
|
-
anhedral provision [directory] [--dry-run] [--json]
|
|
25
|
-
anhedral ship [directory] [--dry-run] [--json]
|
|
26
|
-
anhedral adopt [directory] --provider vercel [--json]
|
|
27
|
-
anhedral recover [directory] [--provider vercel|cloudflare] [--json]
|
|
28
|
-
anhedral status [directory] [--refresh] [--json]
|
|
29
|
-
anhedral manage [directory] [--local] [--json]
|
|
30
|
-
anhedral verify [directory] [--json]
|
|
31
|
-
anhedral rollback [directory] --release <id> --data-compatible [--json]
|
|
32
|
-
|
|
33
|
-
--skip-install skips the final workspace install; the official shadcn bootstrap
|
|
34
|
-
still requires network access and may install its own dependencies.
|
|
35
|
-
--all is intentionally unsupported: select only required capabilities.
|
|
36
|
-
Vercel Hobby is personal/non-commercial with limits; commercial apps need a suitable existing plan.
|
|
37
|
-
`;
|
|
1
|
+
import { COMMANDS, GLOBAL_OPTIONS, optionHelp } from '../command-schema.js';
|
|
2
|
+
// Preserve the presentation API for consumers; all option text comes from typed definitions.
|
|
3
|
+
export const COMMAND_HELP = Object.fromEntries(Object.entries(COMMANDS).map(([name, entry]) => [
|
|
4
|
+
name,
|
|
5
|
+
{ ...entry, options: entry.options.filter((option) => !option.hidden).map(optionHelp) },
|
|
6
|
+
]));
|
|
7
|
+
const primary = ['init', 'auth', 'ship', 'add', 'registry', 'inspect', 'doctor', 'connect'];
|
|
8
|
+
const common = GLOBAL_OPTIONS.map(optionHelp);
|
|
9
|
+
export function commandHelp(command) {
|
|
10
|
+
if (command === 'new')
|
|
11
|
+
return commandHelp('init')
|
|
12
|
+
?.replace('Usage: anhedral init', 'Usage: anhedral new')
|
|
13
|
+
.concat('\nCompatibility alias: new requires a destination directory.\n');
|
|
14
|
+
const entry = COMMAND_HELP[command];
|
|
15
|
+
if (!entry)
|
|
16
|
+
return undefined;
|
|
17
|
+
return `${entry.description}\n\nUsage: anhedral ${entry.usage}\n\nOptions:\n${[...entry.options, ...common].map((option) => ` ${option}`).join('\n')}\n\nExamples:\n${entry.examples.map((example) => ` anhedral ${example}`).join('\n')}${entry.note ? `\n\n${entry.note}` : ''}\n`;
|
|
18
|
+
}
|
|
19
|
+
export const STANDARD_USAGE = `Anhedral\nScaffold source, authenticate your providers, and ship your selected stack.\n\nUsage: anhedral <command> [options]\n\nStart here:\n${primary.map((name) => ` ${name.padEnd(12)}${COMMAND_HELP[name].description}`).join('\n')}\n\nDelivery tools:\n${Object.entries(COMMAND_HELP)
|
|
20
|
+
.filter(([name]) => !primary.includes(name))
|
|
21
|
+
.map(([name, entry]) => ` ${name.padEnd(12)}${entry.description}`)
|
|
22
|
+
.join('\n')}\n\nDefault: Vinext on Cloudflare Workers, from the official shadcn pnpm/Turborepo monorepo.\nExamples:\n anhedral init client-app\n anhedral auth client-app\n anhedral ship client-app --dry-run\n\nUse anhedral <command> --help for options and examples.\nUse anhedral help <command> for the same focused help.\nGlobal options:\n${common.map((option) => ` ${option}`).join('\n')}\n -v, --version Show the CLI version.\n\nnew remains a compatibility alias for init with an explicit destination.\n`;
|
package/dist/scaffold/auth.js
CHANGED
|
@@ -3,7 +3,7 @@ import { STACK_DEPENDENCIES } from '../dependencies.js';
|
|
|
3
3
|
import { existsSync, readFileSync } from 'node:fs';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { writeBetterAuthSchema } from '../auth-schema.js';
|
|
6
|
-
import {
|
|
6
|
+
import { put, patchPackage, sharedPackage } from './files.js';
|
|
7
7
|
export function scaffoldBetterAuth({ root, options, runtimeApp, has }) {
|
|
8
8
|
writeBetterAuthSchema(root, has('neon'));
|
|
9
9
|
sharedPackage(root, 'auth', `import { betterAuth } from 'better-auth';
|
|
@@ -30,14 +30,6 @@ export function createAuth(db: ReturnType<typeof createDatabase>, secret: string
|
|
|
30
30
|
const source = readFileSync(path.join(root, 'apps/api/src/index.ts'), 'utf8');
|
|
31
31
|
put(root, 'apps/api/src/index.ts', `import { createAuth } from '@workspace/auth';\nimport { createDatabase } from '@workspace/db';\n` +
|
|
32
32
|
source.replace('export default app;', `app.on(['GET', 'POST'], '/api/auth/*', async (c) => {\n const env = c.env;\n const database = ${connection};\n return await createAuth(database, env.BETTER_AUTH_SECRET, env.BETTER_AUTH_URL).handler(c.req.raw);\n});\nexport default app;`));
|
|
33
|
-
const config = readJson(root, 'apps/api/wrangler.jsonc');
|
|
34
|
-
json(root, 'apps/api/wrangler.jsonc', {
|
|
35
|
-
...config,
|
|
36
|
-
vars: {
|
|
37
|
-
BETTER_AUTH_URL: 'http://localhost:8787',
|
|
38
|
-
...(config.vars ?? {}),
|
|
39
|
-
},
|
|
40
|
-
});
|
|
41
33
|
}
|
|
42
34
|
else {
|
|
43
35
|
put(root, 'apps/web/app/api/auth/[...all]/route.ts', `${has('vinext') ? "import { env } from 'cloudflare:workers';" : options.hosting === 'cloudflare' ? "import { getCloudflareContext } from '@opennextjs/cloudflare';" : ''}
|
|
@@ -53,15 +45,7 @@ export { handler as GET, handler as POST };
|
|
|
53
45
|
if (options.hosting === 'cloudflare' && !has('vinext'))
|
|
54
46
|
put(root, 'apps/web/cloudflare-env.d.ts', `interface CloudflareEnv { BETTER_AUTH_SECRET: string; BETTER_AUTH_URL: string; ${has('neon') ? 'DATABASE_URL: string;' : "DB: Parameters<typeof import('drizzle-orm/d1').drizzle>[0];"} }\n`);
|
|
55
47
|
if (has('vinext')) {
|
|
56
|
-
put(root, 'apps/web/secrets.d.ts', 'declare namespace Cloudflare { interface Env { BETTER_AUTH_SECRET: string } }\n');
|
|
57
|
-
const config = readJson(root, 'apps/web/wrangler.jsonc');
|
|
58
|
-
json(root, 'apps/web/wrangler.jsonc', {
|
|
59
|
-
...config,
|
|
60
|
-
vars: {
|
|
61
|
-
BETTER_AUTH_URL: 'http://localhost:3000',
|
|
62
|
-
...(config.vars ?? {}),
|
|
63
|
-
},
|
|
64
|
-
});
|
|
48
|
+
put(root, 'apps/web/secrets.d.ts', 'declare namespace Cloudflare { interface Env { BETTER_AUTH_SECRET: string; BETTER_AUTH_URL: string } }\n');
|
|
65
49
|
}
|
|
66
50
|
patchPackage(root, 'apps/web/package.json', {
|
|
67
51
|
dependencies: { 'drizzle-orm': STACK_DEPENDENCIES['drizzle-orm'] },
|
|
@@ -73,7 +57,7 @@ export { handler as GET, handler as POST };
|
|
|
73
57
|
BETTER_AUTH_URL: `http://localhost:${runtimeApp === 'web' ? '3000' : '8787'}`,
|
|
74
58
|
});
|
|
75
59
|
if (has('hono'))
|
|
76
|
-
put(root, 'apps/api/src/secrets.d.ts', 'interface Env { BETTER_AUTH_SECRET: string }\n');
|
|
60
|
+
put(root, 'apps/api/src/secrets.d.ts', 'interface Env { BETTER_AUTH_SECRET: string; BETTER_AUTH_URL: string }\n');
|
|
77
61
|
}
|
|
78
62
|
export function scaffoldClerk({ root, has }) {
|
|
79
63
|
if (has('next') || has('vinext')) {
|
|
@@ -9,6 +9,9 @@ import { json, put, readJson, patchPackage, } from './files.js';
|
|
|
9
9
|
import { writeSetupDocumentation, workerBuildSuffix } from './documentation.js';
|
|
10
10
|
import { writeStackDocumentation } from './stack-documentation.js';
|
|
11
11
|
import { writeEnvironmentExample } from './environment.js';
|
|
12
|
+
import { providerConfigurationTemplate } from '../providers/config.js';
|
|
13
|
+
import { existsSync } from 'node:fs';
|
|
14
|
+
import path from 'node:path';
|
|
12
15
|
function securityOverrides(options) {
|
|
13
16
|
const has = (value) => options.products.includes(value);
|
|
14
17
|
return {
|
|
@@ -161,6 +164,14 @@ process.exitCode = result.status ?? 1;
|
|
|
161
164
|
resourcesProvisioned: false,
|
|
162
165
|
});
|
|
163
166
|
json(root, 'anhedral.setup.json', createSetupPlan({ ...options, dryRun: false }, registry));
|
|
167
|
+
const providers = providerConfigurationTemplate(options.products, options.name);
|
|
168
|
+
const prior = updating && existsSync(path.join(root, 'anhedral.providers.json'))
|
|
169
|
+
? readJson(root, 'anhedral.providers.json')
|
|
170
|
+
: undefined;
|
|
171
|
+
json(root, 'anhedral.providers.json', {
|
|
172
|
+
...providers,
|
|
173
|
+
providers: { ...providers.providers, ...prior?.providers },
|
|
174
|
+
});
|
|
164
175
|
if (!updating)
|
|
165
176
|
writeSetupDocumentation(root, options);
|
|
166
177
|
}
|