relic 0.4.0 → 0.4.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.
@@ -1,45 +0,0 @@
1
- import { validateSession } from "@repo/auth";
2
- import { trackEvent } from "@repo/logger";
3
- import ora from "ora";
4
- import pc from "picocolors";
5
- import { getApi } from "../lib/api";
6
-
7
- export default async function whoami() {
8
- const spinner = ora("Fetching user info...").start();
9
-
10
- try {
11
- const sessionValidation = await validateSession();
12
- if (!sessionValidation.isValid || sessionValidation.isExpired) {
13
- spinner.stop();
14
- console.log(pc.yellow("Not logged in"));
15
- console.log(pc.dim("Run `relic login` to authenticate"));
16
- return;
17
- }
18
-
19
- const api = getApi();
20
- const user = await api.getCurrentUser();
21
-
22
- trackEvent("cli_command_executed", { command: "whoami" });
23
- spinner.stop();
24
- console.log(pc.bold("Logged in as:"));
25
- console.log();
26
- console.log(`${pc.dim("Name:")} ${user.name}`);
27
- console.log(`${pc.dim("Email:")} ${user.email}`);
28
- console.log(`${pc.dim("Plan:")} ${user.hasPro ? pc.green("Pro") : "Free"}`);
29
- } catch (err) {
30
- const message = err instanceof Error ? err.message : "Failed to fetch user";
31
- // Handle auth-related errors more gracefully
32
- if (
33
- message.includes("Not authenticated") ||
34
- message.includes("JWT") ||
35
- message.includes("token")
36
- ) {
37
- spinner.stop();
38
- console.log(pc.yellow("Not logged in"));
39
- console.log(pc.dim("Run `relic login` to authenticate"));
40
- return;
41
- }
42
- spinner.fail(pc.red(`Error: ${message}`));
43
- process.exit(1);
44
- }
45
- }
package/ffi/bridge.ts DELETED
@@ -1,36 +0,0 @@
1
- import type { Pointer } from "bun:ffi";
2
- import { getLibrary } from "./helper";
3
-
4
- type LibraryType = Awaited<ReturnType<typeof getLibrary>>;
5
-
6
- export class RunnerBridge {
7
- private lib: LibraryType;
8
- private static instance: RunnerBridge | null = null;
9
- private static instancePromise: Promise<RunnerBridge> | null = null;
10
-
11
- private constructor(lib: LibraryType) {
12
- this.lib = lib;
13
- }
14
-
15
- static async getInstance(): Promise<RunnerBridge> {
16
- if (RunnerBridge.instance) {
17
- return RunnerBridge.instance;
18
- }
19
-
20
- if (RunnerBridge.instancePromise) {
21
- return RunnerBridge.instancePromise;
22
- }
23
-
24
- RunnerBridge.instancePromise = (async () => {
25
- const lib = await getLibrary();
26
- RunnerBridge.instance = new RunnerBridge(lib);
27
- return RunnerBridge.instance;
28
- })();
29
-
30
- return RunnerBridge.instancePromise;
31
- }
32
-
33
- runWithSecrets(command: Pointer, secrets: Pointer): number {
34
- return this.lib.symbols.run_with_secrets(command, secrets);
35
- }
36
- }
package/ffi/constants.ts DELETED
@@ -1,3 +0,0 @@
1
- export const REPO_URL = "https://github.com/heycupola/relic";
2
- export const ISSUES_URL = `${REPO_URL}/issues`;
3
- export const RELEASES_URL = `${REPO_URL}/releases`;
package/ffi/helper.ts DELETED
@@ -1,134 +0,0 @@
1
- import { dlopen, FFIType, suffix } from "bun:ffi";
2
- import { ISSUES_URL, RELEASES_URL } from "./constants";
3
-
4
- type Environment = "development" | "production";
5
-
6
- const PLATFORM_MAP: Record<string, string> = {
7
- "darwin-arm64": "darwin-arm64",
8
- "darwin-x64": "darwin-x64",
9
- "linux-x64": "linux-x64",
10
- "win32-x64": "win32-x64",
11
- };
12
-
13
- async function detectEnvironment(): Promise<Environment> {
14
- if (process.env.DEV === "true") {
15
- return "development";
16
- }
17
-
18
- const prebuildsPath = `${import.meta.dir}/../prebuilds`;
19
- if (await Bun.file(prebuildsPath).exists()) {
20
- return "production";
21
- }
22
-
23
- const turboJsonPath = `${import.meta.dir}/../../../turbo.json`;
24
- if (await Bun.file(turboJsonPath).exists()) {
25
- return "development";
26
- }
27
-
28
- return "production";
29
- }
30
-
31
- function getRunnerPath(): string {
32
- return `${import.meta.dir}/../../../packages/runner`;
33
- }
34
-
35
- function getLibraryName(): string {
36
- return process.platform === "win32" ? "relic_runner.dll" : `librelic_runner.${suffix}`;
37
- }
38
-
39
- function getProductionError(platform: string): Error {
40
- return new Error(
41
- `Rust library not found for ${platform}.\n\n` +
42
- `This appears to be a packaging issue. Please try reinstalling:\n` +
43
- ` - If installed via package manager: uninstall and reinstall relic\n` +
44
- ` - If using binaries: re-download from ${RELEASES_URL}\n\n` +
45
- `If the problem persists, report at: ${ISSUES_URL}`,
46
- );
47
- }
48
-
49
- function getDevelopmentError(platform: string): Error {
50
- return new Error(
51
- `Rust library not found for ${platform}.\n\n` +
52
- `Build the runner first:\n` +
53
- ` cd packages/runner && cargo build --release`,
54
- );
55
- }
56
-
57
- async function findLibraryInProduction(
58
- targetPlatform: string,
59
- libName: string,
60
- ): Promise<string | null> {
61
- const searchPaths = [
62
- `${import.meta.dir}/${libName}`,
63
- `${import.meta.dir}/../lib/${libName}`,
64
- `${import.meta.dir}/../prebuilds/${targetPlatform}/${libName}`,
65
- ];
66
-
67
- for (const candidate of searchPaths) {
68
- if (await Bun.file(candidate).exists()) {
69
- return candidate;
70
- }
71
- }
72
-
73
- return null;
74
- }
75
-
76
- async function findLibraryInDevelopment(
77
- targetPlatform: string,
78
- libName: string,
79
- ): Promise<string | null> {
80
- const runnerPath = getRunnerPath();
81
-
82
- const paths = [
83
- `${runnerPath}/target/release/${libName}`,
84
- `${runnerPath}/target/debug/${libName}`,
85
- `${runnerPath}/prebuilt/${targetPlatform}/${libName}`,
86
- ];
87
-
88
- for (const path of paths) {
89
- if (await Bun.file(path).exists()) {
90
- return path;
91
- }
92
- }
93
-
94
- return null;
95
- }
96
-
97
- export async function getPlatformLibrary(): Promise<string> {
98
- const platformKey = `${process.platform}-${process.arch}`;
99
- const targetPlatform = PLATFORM_MAP[platformKey];
100
-
101
- if (!targetPlatform) {
102
- throw new Error(
103
- `Unsupported platform: ${platformKey}. Supported platforms: ${Object.keys(PLATFORM_MAP).join(", ")}`,
104
- );
105
- }
106
-
107
- const libName = getLibraryName();
108
- const env = await detectEnvironment();
109
-
110
- if (env === "production") {
111
- const libraryPath = await findLibraryInProduction(targetPlatform, libName);
112
- if (libraryPath) {
113
- return libraryPath;
114
- }
115
- throw getProductionError(platformKey);
116
- }
117
-
118
- const libraryPath = await findLibraryInDevelopment(targetPlatform, libName);
119
- if (libraryPath) {
120
- return libraryPath;
121
- }
122
- throw getDevelopmentError(platformKey);
123
- }
124
-
125
- export async function getLibrary() {
126
- const lib = dlopen(await getPlatformLibrary(), {
127
- run_with_secrets: {
128
- args: [FFIType.cstring, FFIType.cstring],
129
- returns: FFIType.i32,
130
- },
131
- });
132
-
133
- return lib;
134
- }
package/index.ts DELETED
@@ -1,116 +0,0 @@
1
- import { initLogger, isFirstRun, saveTelemetryPreference } from "@repo/logger";
2
- import { Command, CommanderError } from "commander";
3
- import type { SecretScope } from "lib/types";
4
- import pc from "picocolors";
5
- import init from "./commands/init";
6
- import login from "./commands/login";
7
- import logout from "./commands/logout";
8
- import projects from "./commands/projects";
9
- import run from "./commands/run";
10
- import { telemetryDisable, telemetryEnable, telemetryStatus } from "./commands/telemetry";
11
- import whoami from "./commands/whoami";
12
- import pkg from "./package.json";
13
-
14
- await initLogger();
15
-
16
- if (isFirstRun()) {
17
- console.log(
18
- pc.dim(
19
- "Relic collects anonymous usage data to improve the product. Run `relic telemetry disable` to opt out.",
20
- ),
21
- );
22
- saveTelemetryPreference(true);
23
- }
24
-
25
- function printAvailableCommands() {
26
- console.error(pc.dim(" Available commands:\n"));
27
- for (const cmd of program.commands) {
28
- console.error(` ${pc.cyan(cmd.name().padEnd(14))} ${pc.dim(cmd.description())}`);
29
- }
30
- }
31
-
32
- function printHelpHint() {
33
- console.error(`\n ${pc.dim(`Run ${pc.white("relic --help")} for more information.`)}\n`);
34
- }
35
-
36
- const program = new Command()
37
- .name("relic")
38
- .description("Zero-knowledge secret layer for your projects")
39
- .version(pkg.version)
40
- .exitOverride()
41
- .configureOutput({
42
- outputError: () => {
43
- /* suppressed */
44
- },
45
- })
46
- .action(async () => {
47
- process.env._RELIC_FROM_CLI = "true";
48
- await import("@repo/tui");
49
- });
50
-
51
- program.command("login").description("Authenticate with Relic").action(login);
52
- program.command("logout").description("Clear authentication").action(logout);
53
- program.command("whoami").description("Show current user").action(whoami);
54
- program.command("projects").description("List all projects").action(projects);
55
- program.command("init").description("Initialize Relic for the current project").action(init);
56
-
57
- const telemetryCmd = program
58
- .command("telemetry")
59
- .description("Manage anonymous usage data collection");
60
- telemetryCmd.command("status").description("Show telemetry status").action(telemetryStatus);
61
- telemetryCmd.command("enable").description("Enable telemetry").action(telemetryEnable);
62
- telemetryCmd.command("disable").description("Disable telemetry").action(telemetryDisable);
63
-
64
- program
65
- .command("run")
66
- .description("Run a command with secrets injected as environment variables")
67
- .requiredOption("-e, --environment <name>", "Environment name (required)")
68
- .option("-f, --folder <name>", "Folder name (optional)")
69
- .option("-s, --scope <scope>", "Scope filter: client, server, or shared (optional)")
70
- .option("-p, --project <id>", "Project ID (optional, defaults to relic.toml or RELIC_PROJECT_ID)")
71
- .argument("<command...>", "Command to run")
72
- .action(
73
- (
74
- command: string[],
75
- options: { environment: string; folder?: string; scope?: SecretScope; project?: string },
76
- ) => {
77
- run(command, options);
78
- },
79
- );
80
-
81
- try {
82
- program.parse();
83
- } catch (err) {
84
- if (err instanceof CommanderError) {
85
- if (err.code === "commander.helpDisplayed" || err.code === "commander.version") {
86
- process.exit(0);
87
- }
88
-
89
- const cleanMessage = err.message.replace(/^error:\s*/i, "");
90
- console.error();
91
-
92
- if (err.code === "commander.unknownCommand" || err.code === "commander.excessArguments") {
93
- const unknown =
94
- err.message.match(/'(.+?)'/)?.[1] ??
95
- process.argv.find(
96
- (arg) => !arg.startsWith("-") && arg !== process.argv[0] && arg !== process.argv[1],
97
- );
98
- console.error(` ${pc.red(pc.bold("Unknown command:"))} ${pc.white(unknown ?? "unknown")}`);
99
- console.error();
100
- printAvailableCommands();
101
- } else if (err.code === "commander.missingArgument") {
102
- console.error(` ${pc.red(pc.bold("Missing argument:"))} ${pc.dim(cleanMessage)}`);
103
- } else if (err.code === "commander.missingMandatoryOptionValue") {
104
- console.error(` ${pc.red(pc.bold("Missing required option:"))} ${pc.dim(cleanMessage)}`);
105
- } else if (err.code === "commander.optionMissingArgument") {
106
- console.error(` ${pc.red(pc.bold("Option missing argument:"))} ${pc.dim(cleanMessage)}`);
107
- } else {
108
- console.error(` ${pc.red(pc.bold("Error:"))} ${pc.dim(cleanMessage)}`);
109
- }
110
-
111
- printHelpHint();
112
- process.exit(1);
113
- }
114
-
115
- throw err;
116
- }