Flatten the repo: move everything out of app/ to the root
Now that the CLI and the Next.js app are one package, nesting it inside app/ served no purpose - the repo root itself becomes the published npm package. Merges app/.gitignore and app/README.md into the root versions, drops the now-duplicate app/LICENSE, and updates path references (README, docs/ARCHITECTURE.md, docs/CONFIG_REFERENCE.md, package.json's repository.directory) that assumed the app/ nesting. Also fixes a real bug this surfaced: the in-app docs viewer resolved docs/ relative to process.cwd(), which only worked by accident when the CLI happened to be invoked from app/'s parent directory. A first attempt at fixing it with import.meta.dirname broke instead, for the same cross-module-graph reason config-path resolution already documented - Next compiles Route Handlers through a separate module graph that doesn't preserve source-relative import.meta paths. Fixed by exposing the app root via TRIGGERSHELL_APP_ROOT (set once in server.ts, where import.meta *does* resolve correctly), the same pattern already used for TRIGGERSHELL_CONFIG_PATH. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,73 @@
|
||||
import crypto from "node:crypto";
|
||||
import path from "node:path";
|
||||
import { password as promptPassword } from "@inquirer/prompts";
|
||||
import { stringify } from "yaml";
|
||||
import { hashPassword } from "../../lib/auth/password";
|
||||
import { upsertEnvVar } from "../lib/env-file";
|
||||
import { resolveConfigPath } from "../lib/paths";
|
||||
import { slug } from "../lib/slug";
|
||||
|
||||
export interface UsersOptions {
|
||||
config?: string;
|
||||
inline?: boolean;
|
||||
}
|
||||
|
||||
function printSnippet(heading: string, entry: Record<string, unknown>): void {
|
||||
console.log(`\n${heading}\n`);
|
||||
console.log(stringify([entry]));
|
||||
}
|
||||
|
||||
async function promptNewPassword(): Promise<string> {
|
||||
for (;;) {
|
||||
const first = await promptPassword({ message: "Password", mask: true });
|
||||
const second = await promptPassword({ message: "Confirm password", mask: true });
|
||||
if (first === second) return first;
|
||||
console.error("Passwords did not match, try again.\n");
|
||||
}
|
||||
}
|
||||
|
||||
export async function usersAddCommand(username: string, opts: UsersOptions): Promise<void> {
|
||||
const password = await promptNewPassword();
|
||||
const passwordHash = await hashPassword(password);
|
||||
|
||||
if (opts.inline) {
|
||||
printSnippet("Add this under `auth.users:` in your config file:", { username, passwordHash });
|
||||
return;
|
||||
}
|
||||
|
||||
const configPath = resolveConfigPath(opts.config);
|
||||
const envPath = path.join(path.dirname(configPath), ".env");
|
||||
const varName = `TRIGGERSHELL_USER_${slug(username)}_PASSWORD_HASH`;
|
||||
upsertEnvVar(envPath, varName, passwordHash);
|
||||
|
||||
console.log(`Stored ${varName} in ${envPath}`);
|
||||
printSnippet("Add this under `auth.users:` in your config file:", {
|
||||
username,
|
||||
passwordHash: `\${${varName}}`,
|
||||
});
|
||||
}
|
||||
|
||||
export async function usersAddTokenCommand(name: string, opts: UsersOptions): Promise<void> {
|
||||
const token = crypto.randomBytes(32).toString("hex");
|
||||
const tokenHash = `sha256:${crypto.createHash("sha256").update(token).digest("hex")}`;
|
||||
|
||||
console.log("\nSave this token now - it will not be shown again:");
|
||||
console.log(` ${token}`);
|
||||
console.log(`Use it as: Authorization: Bearer ${token}`);
|
||||
|
||||
if (opts.inline) {
|
||||
printSnippet("Add this under `auth.tokens:` in your config file:", { name, tokenHash });
|
||||
return;
|
||||
}
|
||||
|
||||
const configPath = resolveConfigPath(opts.config);
|
||||
const envPath = path.join(path.dirname(configPath), ".env");
|
||||
const varName = `TRIGGERSHELL_TOKEN_${slug(name)}_HASH`;
|
||||
upsertEnvVar(envPath, varName, tokenHash);
|
||||
|
||||
console.log(`Stored ${varName} in ${envPath}`);
|
||||
printSnippet("Add this under `auth.tokens:` in your config file:", {
|
||||
name,
|
||||
tokenHash: `\${${varName}}`,
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user