cleargate 0.1.0-alpha.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.
- package/README.md +3 -0
- package/dist/admin-api/index.cjs +359 -0
- package/dist/admin-api/index.cjs.map +1 -0
- package/dist/admin-api/index.d.cts +135 -0
- package/dist/admin-api/index.d.ts +135 -0
- package/dist/admin-api/index.js +313 -0
- package/dist/admin-api/index.js.map +1 -0
- package/dist/auth/factory.cjs +198 -0
- package/dist/auth/factory.cjs.map +1 -0
- package/dist/auth/factory.d.cts +10 -0
- package/dist/auth/factory.d.ts +10 -0
- package/dist/auth/factory.js +8 -0
- package/dist/auth/factory.js.map +1 -0
- package/dist/auth/require-token.cjs +40 -0
- package/dist/auth/require-token.cjs.map +1 -0
- package/dist/auth/require-token.d.cts +11 -0
- package/dist/auth/require-token.d.ts +11 -0
- package/dist/auth/require-token.js +16 -0
- package/dist/auth/require-token.js.map +1 -0
- package/dist/auth/token-store.cjs +20 -0
- package/dist/auth/token-store.cjs.map +1 -0
- package/dist/auth/token-store.d.cts +26 -0
- package/dist/auth/token-store.d.ts +26 -0
- package/dist/auth/token-store.js +2 -0
- package/dist/auth/token-store.js.map +1 -0
- package/dist/chunk-4V4QABOJ.js +165 -0
- package/dist/chunk-4V4QABOJ.js.map +1 -0
- package/dist/cli.cjs +459 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/cli.d.cts +2 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +280 -0
- package/dist/cli.js.map +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TokenStore } from './token-store.js';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Asserts a refresh token is present for the given profile.
|
|
5
|
+
* Throws a user-friendly error if the token is missing.
|
|
6
|
+
*
|
|
7
|
+
* Mirrors requireMcpUrl from config.ts — single throw site for "missing token".
|
|
8
|
+
*/
|
|
9
|
+
declare function requireToken(profile: string, store: TokenStore): Promise<string>;
|
|
10
|
+
|
|
11
|
+
export { requireToken };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/auth/require-token.ts
|
|
4
|
+
async function requireToken(profile, store) {
|
|
5
|
+
const token = await store.load(profile);
|
|
6
|
+
if (token === null) {
|
|
7
|
+
throw new Error(
|
|
8
|
+
`No refresh token for profile "${profile}". Run \`cleargate join <invite-url>\` first.`
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
return token;
|
|
12
|
+
}
|
|
13
|
+
export {
|
|
14
|
+
requireToken
|
|
15
|
+
};
|
|
16
|
+
//# sourceMappingURL=require-token.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auth/require-token.ts"],"sourcesContent":["import type { TokenStore } from './token-store.js';\n\n/**\n * Asserts a refresh token is present for the given profile.\n * Throws a user-friendly error if the token is missing.\n *\n * Mirrors requireMcpUrl from config.ts — single throw site for \"missing token\".\n */\nexport async function requireToken(\n profile: string,\n store: TokenStore,\n): Promise<string> {\n const token = await store.load(profile);\n if (token === null) {\n throw new Error(\n `No refresh token for profile \"${profile}\". Run \\`cleargate join <invite-url>\\` first.`,\n );\n }\n return token;\n}\n"],"mappings":";;;AAQA,eAAsB,aACpB,SACA,OACiB;AACjB,QAAM,QAAQ,MAAM,MAAM,KAAK,OAAO;AACtC,MAAI,UAAU,MAAM;AAClB,UAAM,IAAI;AAAA,MACR,iCAAiC,OAAO;AAAA,IAC1C;AAAA,EACF;AACA,SAAO;AACT;","names":[]}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
var __copyProps = (to, from, except, desc) => {
|
|
8
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
9
|
+
for (let key of __getOwnPropNames(from))
|
|
10
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
11
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
12
|
+
}
|
|
13
|
+
return to;
|
|
14
|
+
};
|
|
15
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
16
|
+
|
|
17
|
+
// src/auth/token-store.ts
|
|
18
|
+
var token_store_exports = {};
|
|
19
|
+
module.exports = __toCommonJS(token_store_exports);
|
|
20
|
+
//# sourceMappingURL=token-store.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/auth/token-store.ts"],"sourcesContent":["/**\n * TokenStore — interface + factory options types only.\n * Zero runtime imports (consumers can import types cheaply).\n */\n\nexport interface TokenStore {\n /** Persist a refresh token for the named profile. Overwrites any existing value. */\n save(profile: string, token: string): Promise<void>;\n /** Return the stored refresh token for the profile, or null if none. */\n load(profile: string): Promise<string | null>;\n /** Remove the stored token for the profile. Idempotent — no error if absent. */\n remove(profile: string): Promise<void>;\n /** Backend identifier for diagnostics. */\n readonly backend: 'keychain' | 'file';\n}\n\nexport interface TokenStoreFactoryOptions {\n /** Override file path for FileTokenStore (test seam). Default: ~/.cleargate/auth.json */\n filePath?: string;\n /** Override keychain service name (test seam). Default: \"cleargate\". */\n keychainService?: string;\n /** Force a backend, bypassing detection. Used by tests. */\n forceBackend?: 'keychain' | 'file';\n /** stderr writer for the \"keychain unavailable\" warning. Default: process.stderr.write. */\n warn?: (msg: string) => void;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAAA;AAAA;","names":[]}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenStore — interface + factory options types only.
|
|
3
|
+
* Zero runtime imports (consumers can import types cheaply).
|
|
4
|
+
*/
|
|
5
|
+
interface TokenStore {
|
|
6
|
+
/** Persist a refresh token for the named profile. Overwrites any existing value. */
|
|
7
|
+
save(profile: string, token: string): Promise<void>;
|
|
8
|
+
/** Return the stored refresh token for the profile, or null if none. */
|
|
9
|
+
load(profile: string): Promise<string | null>;
|
|
10
|
+
/** Remove the stored token for the profile. Idempotent — no error if absent. */
|
|
11
|
+
remove(profile: string): Promise<void>;
|
|
12
|
+
/** Backend identifier for diagnostics. */
|
|
13
|
+
readonly backend: 'keychain' | 'file';
|
|
14
|
+
}
|
|
15
|
+
interface TokenStoreFactoryOptions {
|
|
16
|
+
/** Override file path for FileTokenStore (test seam). Default: ~/.cleargate/auth.json */
|
|
17
|
+
filePath?: string;
|
|
18
|
+
/** Override keychain service name (test seam). Default: "cleargate". */
|
|
19
|
+
keychainService?: string;
|
|
20
|
+
/** Force a backend, bypassing detection. Used by tests. */
|
|
21
|
+
forceBackend?: 'keychain' | 'file';
|
|
22
|
+
/** stderr writer for the "keychain unavailable" warning. Default: process.stderr.write. */
|
|
23
|
+
warn?: (msg: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type { TokenStore, TokenStoreFactoryOptions };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TokenStore — interface + factory options types only.
|
|
3
|
+
* Zero runtime imports (consumers can import types cheaply).
|
|
4
|
+
*/
|
|
5
|
+
interface TokenStore {
|
|
6
|
+
/** Persist a refresh token for the named profile. Overwrites any existing value. */
|
|
7
|
+
save(profile: string, token: string): Promise<void>;
|
|
8
|
+
/** Return the stored refresh token for the profile, or null if none. */
|
|
9
|
+
load(profile: string): Promise<string | null>;
|
|
10
|
+
/** Remove the stored token for the profile. Idempotent — no error if absent. */
|
|
11
|
+
remove(profile: string): Promise<void>;
|
|
12
|
+
/** Backend identifier for diagnostics. */
|
|
13
|
+
readonly backend: 'keychain' | 'file';
|
|
14
|
+
}
|
|
15
|
+
interface TokenStoreFactoryOptions {
|
|
16
|
+
/** Override file path for FileTokenStore (test seam). Default: ~/.cleargate/auth.json */
|
|
17
|
+
filePath?: string;
|
|
18
|
+
/** Override keychain service name (test seam). Default: "cleargate". */
|
|
19
|
+
keychainService?: string;
|
|
20
|
+
/** Force a backend, bypassing detection. Used by tests. */
|
|
21
|
+
forceBackend?: 'keychain' | 'file';
|
|
22
|
+
/** stderr writer for the "keychain unavailable" warning. Default: process.stderr.write. */
|
|
23
|
+
warn?: (msg: string) => void;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type { TokenStore, TokenStoreFactoryOptions };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/auth/factory.ts
|
|
4
|
+
import * as os from "os";
|
|
5
|
+
import * as path2 from "path";
|
|
6
|
+
|
|
7
|
+
// src/auth/keychain-store.ts
|
|
8
|
+
import { Entry } from "@napi-rs/keyring";
|
|
9
|
+
var KeychainTokenStore = class {
|
|
10
|
+
constructor(service) {
|
|
11
|
+
this.service = service;
|
|
12
|
+
}
|
|
13
|
+
service;
|
|
14
|
+
backend = "keychain";
|
|
15
|
+
async save(profile, token) {
|
|
16
|
+
new Entry(this.service, profile).setPassword(token);
|
|
17
|
+
}
|
|
18
|
+
async load(profile) {
|
|
19
|
+
try {
|
|
20
|
+
const result = new Entry(this.service, profile).getPassword();
|
|
21
|
+
return result ?? null;
|
|
22
|
+
} catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async remove(profile) {
|
|
27
|
+
try {
|
|
28
|
+
new Entry(this.service, profile).deletePassword();
|
|
29
|
+
} catch {
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
// src/auth/file-store.ts
|
|
35
|
+
import * as fs from "fs/promises";
|
|
36
|
+
import * as path from "path";
|
|
37
|
+
import { z } from "zod";
|
|
38
|
+
var ProfileEntrySchema = z.object({ refreshToken: z.string().min(1) }).strict();
|
|
39
|
+
var AuthFileSchema = z.object({
|
|
40
|
+
version: z.literal(1),
|
|
41
|
+
profiles: z.record(z.string().min(1), ProfileEntrySchema)
|
|
42
|
+
}).strict();
|
|
43
|
+
var EMPTY_AUTH_FILE = { version: 1, profiles: {} };
|
|
44
|
+
var FileTokenStore = class {
|
|
45
|
+
constructor(filePath) {
|
|
46
|
+
this.filePath = filePath;
|
|
47
|
+
}
|
|
48
|
+
filePath;
|
|
49
|
+
backend = "file";
|
|
50
|
+
async save(profile, token) {
|
|
51
|
+
const current = await this.readFile();
|
|
52
|
+
const updated = {
|
|
53
|
+
...current,
|
|
54
|
+
profiles: {
|
|
55
|
+
...current.profiles,
|
|
56
|
+
[profile]: { refreshToken: token }
|
|
57
|
+
}
|
|
58
|
+
};
|
|
59
|
+
await this.writeFile(updated);
|
|
60
|
+
}
|
|
61
|
+
async load(profile) {
|
|
62
|
+
const data = await this.readFile();
|
|
63
|
+
return data.profiles[profile]?.refreshToken ?? null;
|
|
64
|
+
}
|
|
65
|
+
async remove(profile) {
|
|
66
|
+
let current;
|
|
67
|
+
try {
|
|
68
|
+
current = await this.readFile();
|
|
69
|
+
} catch {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
if (!(profile in current.profiles)) {
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const { [profile]: _removed, ...rest } = current.profiles;
|
|
76
|
+
const updated = { ...current, profiles: rest };
|
|
77
|
+
await this.writeFile(updated);
|
|
78
|
+
}
|
|
79
|
+
async readFile() {
|
|
80
|
+
let raw;
|
|
81
|
+
try {
|
|
82
|
+
raw = await fs.readFile(this.filePath, "utf8");
|
|
83
|
+
} catch (err) {
|
|
84
|
+
if (err.code === "ENOENT") {
|
|
85
|
+
return EMPTY_AUTH_FILE;
|
|
86
|
+
}
|
|
87
|
+
throw err;
|
|
88
|
+
}
|
|
89
|
+
let parsed;
|
|
90
|
+
try {
|
|
91
|
+
parsed = JSON.parse(raw);
|
|
92
|
+
} catch {
|
|
93
|
+
throw new Error(
|
|
94
|
+
`Failed to parse auth file at ${this.filePath}: invalid JSON`
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
const result = AuthFileSchema.safeParse(parsed);
|
|
98
|
+
if (!result.success) {
|
|
99
|
+
const versionCheck = parsed?.["version"];
|
|
100
|
+
if (versionCheck !== 1) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`Invalid auth file at ${this.filePath}: unsupported version ${String(versionCheck)}. Please upgrade \`cleargate\` to read this file.`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
throw new Error(
|
|
106
|
+
`Invalid auth file at ${this.filePath}: ${result.error.message}`
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
return result.data;
|
|
110
|
+
}
|
|
111
|
+
async writeFile(data) {
|
|
112
|
+
const dir = path.dirname(this.filePath);
|
|
113
|
+
await fs.mkdir(dir, { recursive: true, mode: 448 });
|
|
114
|
+
await fs.chmod(dir, 448).catch(() => {
|
|
115
|
+
});
|
|
116
|
+
const json = JSON.stringify(data, null, 2);
|
|
117
|
+
const tmpPath = path.join(dir, ".auth.json.tmp");
|
|
118
|
+
await fs.writeFile(tmpPath, json, { mode: 384 });
|
|
119
|
+
await fs.chmod(tmpPath, 384);
|
|
120
|
+
await fs.rename(tmpPath, this.filePath);
|
|
121
|
+
await fs.chmod(this.filePath, 384);
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
// src/auth/factory.ts
|
|
126
|
+
var DEFAULT_KEYCHAIN_SERVICE = "cleargate";
|
|
127
|
+
function resolveFilePath(opts) {
|
|
128
|
+
if (opts.filePath) return opts.filePath;
|
|
129
|
+
const home = os.homedir();
|
|
130
|
+
if (!home) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
"Cannot determine home directory. Set opts.filePath explicitly or ensure os.homedir() returns a non-empty string."
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return path2.join(home, ".cleargate", "auth.json");
|
|
136
|
+
}
|
|
137
|
+
function defaultWarn(msg) {
|
|
138
|
+
process.stderr.write(msg + "\n");
|
|
139
|
+
}
|
|
140
|
+
async function createTokenStore(opts = {}) {
|
|
141
|
+
const filePath = resolveFilePath(opts);
|
|
142
|
+
const service = opts.keychainService ?? DEFAULT_KEYCHAIN_SERVICE;
|
|
143
|
+
const warn = opts.warn ?? defaultWarn;
|
|
144
|
+
if (opts.forceBackend === "file") {
|
|
145
|
+
return new FileTokenStore(filePath);
|
|
146
|
+
}
|
|
147
|
+
if (opts.forceBackend === "keychain") {
|
|
148
|
+
return new KeychainTokenStore(service);
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
const { Entry: Entry2 } = await import("@napi-rs/keyring");
|
|
152
|
+
new Entry2(service, "__cleargate_probe__").getPassword();
|
|
153
|
+
return new KeychainTokenStore(service);
|
|
154
|
+
} catch {
|
|
155
|
+
warn(
|
|
156
|
+
`cleargate: OS keychain unavailable, falling back to file storage at ${filePath}. Run with --log-level=debug for details.`
|
|
157
|
+
);
|
|
158
|
+
return new FileTokenStore(filePath);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export {
|
|
163
|
+
createTokenStore
|
|
164
|
+
};
|
|
165
|
+
//# sourceMappingURL=chunk-4V4QABOJ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/auth/factory.ts","../src/auth/keychain-store.ts","../src/auth/file-store.ts"],"sourcesContent":["import * as os from 'node:os';\nimport * as path from 'node:path';\nimport { KeychainTokenStore } from './keychain-store.js';\nimport { FileTokenStore } from './file-store.js';\nimport type { TokenStore, TokenStoreFactoryOptions } from './token-store.js';\n\nconst DEFAULT_KEYCHAIN_SERVICE = 'cleargate';\n\nfunction resolveFilePath(opts: TokenStoreFactoryOptions): string {\n if (opts.filePath) return opts.filePath;\n const home = os.homedir();\n if (!home) {\n throw new Error(\n 'Cannot determine home directory. Set opts.filePath explicitly or ensure os.homedir() returns a non-empty string.',\n );\n }\n return path.join(home, '.cleargate', 'auth.json');\n}\n\nfunction defaultWarn(msg: string): void {\n process.stderr.write(msg + '\\n');\n}\n\n/**\n * Creates a TokenStore, selecting the keychain backend when available and\n * falling back to file storage with a stderr warning when the OS keychain\n * cannot be accessed.\n */\nexport async function createTokenStore(\n opts: TokenStoreFactoryOptions = {},\n): Promise<TokenStore> {\n const filePath = resolveFilePath(opts);\n const service = opts.keychainService ?? DEFAULT_KEYCHAIN_SERVICE;\n const warn = opts.warn ?? defaultWarn;\n\n // Short-circuit if backend is forced (test seam, skips probe)\n if (opts.forceBackend === 'file') {\n return new FileTokenStore(filePath);\n }\n if (opts.forceBackend === 'keychain') {\n return new KeychainTokenStore(service);\n }\n\n // Probe the keychain to determine availability\n try {\n const { Entry } = await import('@napi-rs/keyring');\n new Entry(service, '__cleargate_probe__').getPassword();\n // Probe succeeded (returned string | null cleanly) — use keychain\n return new KeychainTokenStore(service);\n } catch {\n // Constructor threw (native module load failed, libsecret missing on Linux)\n // OR getPassword() threw (dbus not running, prompt cancelled)\n // Either way, keychain is unavailable for this CLI invocation\n warn(\n `cleargate: OS keychain unavailable, falling back to file storage at ${filePath}. Run with --log-level=debug for details.`,\n );\n return new FileTokenStore(filePath);\n }\n}\n","import { Entry } from '@napi-rs/keyring';\nimport type { TokenStore } from './token-store.js';\n\nexport class KeychainTokenStore implements TokenStore {\n readonly backend = 'keychain' as const;\n\n constructor(private readonly service: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n new Entry(this.service, profile).setPassword(token);\n }\n\n async load(profile: string): Promise<string | null> {\n try {\n const result = new Entry(this.service, profile).getPassword();\n // getPassword() returns string | null per @napi-rs/keyring@1.2.0 index.d.ts:124\n // Despite the docstring claiming it throws NoEntry, the return type wins.\n // Handle both: null return AND potential thrown NoEntry (platform-specific).\n return result ?? null;\n } catch {\n // NoEntry or other keychain error — treat as absent\n return null;\n }\n }\n\n async remove(profile: string): Promise<void> {\n try {\n new Entry(this.service, profile).deletePassword();\n } catch {\n // Entry didn't exist or other keychain error — idempotent, swallow\n }\n }\n}\n","import * as fs from 'node:fs/promises';\nimport * as path from 'node:path';\nimport { z } from 'zod';\nimport type { TokenStore } from './token-store.js';\n\nconst ProfileEntrySchema = z.object({ refreshToken: z.string().min(1) }).strict();\n\nexport const AuthFileSchema = z\n .object({\n version: z.literal(1),\n profiles: z.record(z.string().min(1), ProfileEntrySchema),\n })\n .strict();\n\ntype AuthFile = z.infer<typeof AuthFileSchema>;\n\nconst EMPTY_AUTH_FILE: AuthFile = { version: 1, profiles: {} };\n\nexport class FileTokenStore implements TokenStore {\n readonly backend = 'file' as const;\n\n constructor(private readonly filePath: string) {}\n\n async save(profile: string, token: string): Promise<void> {\n const current = await this.readFile();\n const updated: AuthFile = {\n ...current,\n profiles: {\n ...current.profiles,\n [profile]: { refreshToken: token },\n },\n };\n await this.writeFile(updated);\n }\n\n async load(profile: string): Promise<string | null> {\n const data = await this.readFile();\n return data.profiles[profile]?.refreshToken ?? null;\n }\n\n async remove(profile: string): Promise<void> {\n let current: AuthFile;\n try {\n current = await this.readFile();\n } catch {\n // File doesn't exist or unreadable — no-op since there's nothing to remove\n return;\n }\n if (!(profile in current.profiles)) {\n return; // Profile doesn't exist — idempotent\n }\n const { [profile]: _removed, ...rest } = current.profiles;\n const updated: AuthFile = { ...current, profiles: rest };\n await this.writeFile(updated);\n }\n\n private async readFile(): Promise<AuthFile> {\n let raw: string;\n try {\n raw = await fs.readFile(this.filePath, 'utf8');\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === 'ENOENT') {\n return EMPTY_AUTH_FILE;\n }\n throw err;\n }\n\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n throw new Error(\n `Failed to parse auth file at ${this.filePath}: invalid JSON`,\n );\n }\n\n const result = AuthFileSchema.safeParse(parsed);\n if (!result.success) {\n // Check for version mismatch specifically\n const versionCheck = (parsed as Record<string, unknown>)?.['version'];\n if (versionCheck !== 1) {\n throw new Error(\n `Invalid auth file at ${this.filePath}: unsupported version ${String(versionCheck)}. Please upgrade \\`cleargate\\` to read this file.`,\n );\n }\n throw new Error(\n `Invalid auth file at ${this.filePath}: ${result.error.message}`,\n );\n }\n\n return result.data;\n }\n\n private async writeFile(data: AuthFile): Promise<void> {\n const dir = path.dirname(this.filePath);\n await fs.mkdir(dir, { recursive: true, mode: 0o700 });\n // Explicit chmod after mkdir — mkdir only sets mode on newly created dirs\n await fs.chmod(dir, 0o700).catch(() => {\n // If chmod fails on existing dir, that's acceptable — we don't want to\n // surprise users who have set custom modes on ~/.cleargate/\n });\n\n const json = JSON.stringify(data, null, 2);\n const tmpPath = path.join(dir, '.auth.json.tmp');\n\n // Atomic write: write to tmp then rename to avoid partial-write corruption\n await fs.writeFile(tmpPath, json, { mode: 0o600 });\n // Explicit chmod after writeFile — writeFile only sets mode on file creation\n await fs.chmod(tmpPath, 0o600);\n await fs.rename(tmpPath, this.filePath);\n // After rename, chmod the final path to ensure it stays 0600\n await fs.chmod(this.filePath, 0o600);\n }\n}\n"],"mappings":"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","names":["path","Entry"]}
|