@solongate/proxy 0.82.87 → 0.82.89
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/dist/api-client/client.d.ts +14 -0
- package/dist/commands/index.js +33 -0
- package/dist/index.js +52 -5
- package/dist/tui/index.js +24 -4
- package/dist/tui/local-log.d.ts +7 -1
- package/package.json +1 -1
|
@@ -18,6 +18,16 @@ export declare function saveAccount(acc: SavedAccount): void;
|
|
|
18
18
|
/** Remove a saved account from this device (does NOT revoke the cloud key). */
|
|
19
19
|
export declare function removeAccount(apiKey: string): void;
|
|
20
20
|
export declare function setViewCredentials(creds: Credentials | null): void;
|
|
21
|
+
/** The unroutable address a guest ("Skip for now") account is stored under. */
|
|
22
|
+
export declare const GUEST_EMAIL_SUFFIX = "@anonymous.solongate.invalid";
|
|
23
|
+
/**
|
|
24
|
+
* True when the account this device is enforcing with is a guest one.
|
|
25
|
+
*
|
|
26
|
+
* A guest has no dashboard rights beyond reading, and the CLI is the same
|
|
27
|
+
* account reached a different way, so the management commands answer the same
|
|
28
|
+
* way the dashboard does rather than half-working here.
|
|
29
|
+
*/
|
|
30
|
+
export declare function isGuestAccount(): boolean;
|
|
21
31
|
/** True when the given key is the ACTIVE one the guard hooks use. */
|
|
22
32
|
export declare function isActiveAccount(apiKey: string): boolean;
|
|
23
33
|
/**
|
|
@@ -44,6 +54,10 @@ export declare class ApiError extends Error {
|
|
|
44
54
|
readonly code: string;
|
|
45
55
|
constructor(status: number, code: string, message: string);
|
|
46
56
|
}
|
|
57
|
+
/** Raised when a guest account tries to change something. */
|
|
58
|
+
export declare class GuestReadOnlyError extends Error {
|
|
59
|
+
constructor();
|
|
60
|
+
}
|
|
47
61
|
/** Raised when no API key can be found — tells the user to run `solongate` and pair. */
|
|
48
62
|
export declare class NotAuthenticatedError extends Error {
|
|
49
63
|
constructor();
|
package/dist/commands/index.js
CHANGED
|
@@ -125,7 +125,31 @@ function codexHooksStatus() {
|
|
|
125
125
|
|
|
126
126
|
// src/api-client/client.ts
|
|
127
127
|
var DEFAULT_API_URL = "https://api.solongate.com";
|
|
128
|
+
var accountsFile = () => join2(homedir2(), ".solongate", "accounts.json");
|
|
129
|
+
function listAccounts() {
|
|
130
|
+
let list5 = [];
|
|
131
|
+
try {
|
|
132
|
+
const raw = JSON.parse(readFileSync2(accountsFile(), "utf-8"));
|
|
133
|
+
if (Array.isArray(raw)) list5 = raw.filter((a) => a && typeof a.apiKey === "string");
|
|
134
|
+
} catch {
|
|
135
|
+
}
|
|
136
|
+
const active2 = loginCredentialFile();
|
|
137
|
+
if (active2.apiKey && !list5.some((a) => a.apiKey === active2.apiKey)) {
|
|
138
|
+
list5.unshift({ apiKey: active2.apiKey, apiUrl: active2.apiUrl || DEFAULT_API_URL });
|
|
139
|
+
}
|
|
140
|
+
return list5;
|
|
141
|
+
}
|
|
128
142
|
var viewOverride = null;
|
|
143
|
+
var GUEST_EMAIL_SUFFIX = "@anonymous.solongate.invalid";
|
|
144
|
+
function isGuestAccount() {
|
|
145
|
+
try {
|
|
146
|
+
const active2 = loginCredentialFile().apiKey;
|
|
147
|
+
if (!active2) return false;
|
|
148
|
+
return listAccounts().some((a) => a.apiKey === active2 && (a.email ?? "").endsWith(GUEST_EMAIL_SUFFIX));
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
129
153
|
var ApiError = class extends Error {
|
|
130
154
|
status;
|
|
131
155
|
code;
|
|
@@ -136,6 +160,12 @@ var ApiError = class extends Error {
|
|
|
136
160
|
this.code = code;
|
|
137
161
|
}
|
|
138
162
|
};
|
|
163
|
+
var GuestReadOnlyError = class extends Error {
|
|
164
|
+
constructor() {
|
|
165
|
+
super("Guest account: sign up at auth.solongate.com to change anything. Your project, its policy and everything recorded carry over.");
|
|
166
|
+
this.name = "GuestReadOnlyError";
|
|
167
|
+
}
|
|
168
|
+
};
|
|
139
169
|
var NotAuthenticatedError = class extends Error {
|
|
140
170
|
constructor() {
|
|
141
171
|
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
@@ -200,6 +230,9 @@ function buildUrl(base, path, query) {
|
|
|
200
230
|
return url.toString();
|
|
201
231
|
}
|
|
202
232
|
async function request(method, path, opts = {}) {
|
|
233
|
+
if (method !== "GET" && isGuestAccount()) {
|
|
234
|
+
throw new GuestReadOnlyError();
|
|
235
|
+
}
|
|
203
236
|
const creds = resolveCredentials(opts.apiUrl);
|
|
204
237
|
const url = buildUrl(creds.apiUrl, path, opts.query);
|
|
205
238
|
const headers = {
|
package/dist/index.js
CHANGED
|
@@ -7518,6 +7518,25 @@ var init_local_log = __esm({
|
|
|
7518
7518
|
});
|
|
7519
7519
|
|
|
7520
7520
|
// src/api-client/client.ts
|
|
7521
|
+
var client_exports = {};
|
|
7522
|
+
__export(client_exports, {
|
|
7523
|
+
ApiError: () => ApiError,
|
|
7524
|
+
DEFAULT_API_URL: () => DEFAULT_API_URL2,
|
|
7525
|
+
GUEST_EMAIL_SUFFIX: () => GUEST_EMAIL_SUFFIX,
|
|
7526
|
+
GuestReadOnlyError: () => GuestReadOnlyError,
|
|
7527
|
+
NotAuthenticatedError: () => NotAuthenticatedError,
|
|
7528
|
+
clearActiveCredential: () => clearActiveCredential,
|
|
7529
|
+
isActiveAccount: () => isActiveAccount,
|
|
7530
|
+
isAuthenticated: () => isAuthenticated,
|
|
7531
|
+
isGuestAccount: () => isGuestAccount,
|
|
7532
|
+
listAccounts: () => listAccounts,
|
|
7533
|
+
removeAccount: () => removeAccount,
|
|
7534
|
+
request: () => request,
|
|
7535
|
+
resolveCredentials: () => resolveCredentials,
|
|
7536
|
+
saveAccount: () => saveAccount,
|
|
7537
|
+
setActiveAccount: () => setActiveAccount,
|
|
7538
|
+
setViewCredentials: () => setViewCredentials
|
|
7539
|
+
});
|
|
7521
7540
|
import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync5 } from "fs";
|
|
7522
7541
|
import { resolve as resolve4, join as join9 } from "path";
|
|
7523
7542
|
import { homedir as homedir7 } from "os";
|
|
@@ -7569,6 +7588,15 @@ function setViewCredentials(creds) {
|
|
|
7569
7588
|
viewOverride = creds;
|
|
7570
7589
|
cached2 = null;
|
|
7571
7590
|
}
|
|
7591
|
+
function isGuestAccount() {
|
|
7592
|
+
try {
|
|
7593
|
+
const active2 = loginCredentialFile().apiKey;
|
|
7594
|
+
if (!active2) return false;
|
|
7595
|
+
return listAccounts().some((a) => a.apiKey === active2 && (a.email ?? "").endsWith(GUEST_EMAIL_SUFFIX));
|
|
7596
|
+
} catch {
|
|
7597
|
+
return false;
|
|
7598
|
+
}
|
|
7599
|
+
}
|
|
7572
7600
|
function isActiveAccount(apiKey) {
|
|
7573
7601
|
return loginCredentialFile().apiKey === apiKey;
|
|
7574
7602
|
}
|
|
@@ -7668,6 +7696,9 @@ function buildUrl(base, path, query) {
|
|
|
7668
7696
|
return url.toString();
|
|
7669
7697
|
}
|
|
7670
7698
|
async function request(method, path, opts = {}) {
|
|
7699
|
+
if (method !== "GET" && isGuestAccount()) {
|
|
7700
|
+
throw new GuestReadOnlyError();
|
|
7701
|
+
}
|
|
7671
7702
|
const creds = resolveCredentials(opts.apiUrl);
|
|
7672
7703
|
const url = buildUrl(creds.apiUrl, path, opts.query);
|
|
7673
7704
|
const headers = {
|
|
@@ -7723,7 +7754,7 @@ async function request(method, path, opts = {}) {
|
|
|
7723
7754
|
}
|
|
7724
7755
|
return json;
|
|
7725
7756
|
}
|
|
7726
|
-
var DEFAULT_API_URL2, accountsFile, viewOverride, ApiError, NotAuthenticatedError, cached2;
|
|
7757
|
+
var DEFAULT_API_URL2, accountsFile, viewOverride, GUEST_EMAIL_SUFFIX, ApiError, GuestReadOnlyError, NotAuthenticatedError, cached2;
|
|
7727
7758
|
var init_client = __esm({
|
|
7728
7759
|
"src/api-client/client.ts"() {
|
|
7729
7760
|
"use strict";
|
|
@@ -7731,6 +7762,7 @@ var init_client = __esm({
|
|
|
7731
7762
|
DEFAULT_API_URL2 = "https://api.solongate.com";
|
|
7732
7763
|
accountsFile = () => join9(homedir7(), ".solongate", "accounts.json");
|
|
7733
7764
|
viewOverride = null;
|
|
7765
|
+
GUEST_EMAIL_SUFFIX = "@anonymous.solongate.invalid";
|
|
7734
7766
|
ApiError = class extends Error {
|
|
7735
7767
|
status;
|
|
7736
7768
|
code;
|
|
@@ -7741,6 +7773,12 @@ var init_client = __esm({
|
|
|
7741
7773
|
this.code = code;
|
|
7742
7774
|
}
|
|
7743
7775
|
};
|
|
7776
|
+
GuestReadOnlyError = class extends Error {
|
|
7777
|
+
constructor() {
|
|
7778
|
+
super("Guest account: sign up at auth.solongate.com to change anything. Your project, its policy and everything recorded carry over.");
|
|
7779
|
+
this.name = "GuestReadOnlyError";
|
|
7780
|
+
}
|
|
7781
|
+
};
|
|
7744
7782
|
NotAuthenticatedError = class extends Error {
|
|
7745
7783
|
constructor() {
|
|
7746
7784
|
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
@@ -11713,6 +11751,7 @@ function SettingsPanel({
|
|
|
11713
11751
|
else if (inp === "m") {
|
|
11714
11752
|
if (cur.kind === "acct") {
|
|
11715
11753
|
const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
|
|
11754
|
+
if (ok) clearLocalLog();
|
|
11716
11755
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
11717
11756
|
refreshAccounts();
|
|
11718
11757
|
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
@@ -11732,6 +11771,7 @@ function SettingsPanel({
|
|
|
11732
11771
|
}
|
|
11733
11772
|
setConfirmDel(null);
|
|
11734
11773
|
removeAccount(target.apiKey);
|
|
11774
|
+
clearLocalLog();
|
|
11735
11775
|
let extra = " from this device";
|
|
11736
11776
|
if (wasActive) {
|
|
11737
11777
|
if (others.length) {
|
|
@@ -12079,6 +12119,7 @@ var init_Settings = __esm({
|
|
|
12079
12119
|
init_components();
|
|
12080
12120
|
init_hooks();
|
|
12081
12121
|
init_theme();
|
|
12122
|
+
init_local_log();
|
|
12082
12123
|
EVENTS = ["denials", "allowed", "all"];
|
|
12083
12124
|
SPIN2 = ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
|
|
12084
12125
|
SIGNALS2 = ["any", "deny", "dlp", "ratelimit"];
|
|
@@ -12161,9 +12202,8 @@ function App() {
|
|
|
12161
12202
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
12162
12203
|
const cur = accounts[acctIdx];
|
|
12163
12204
|
const rawEmail = cur?.email ?? "";
|
|
12164
|
-
const
|
|
12165
|
-
const
|
|
12166
|
-
const acctLabel2 = !cur ? "not logged in" : !hasKey ? "signed out" : isGuestAccount ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
|
|
12205
|
+
const isGuestAccount2 = rawEmail.endsWith("@anonymous.solongate.invalid");
|
|
12206
|
+
const acctLabel2 = !cur ? "not logged in" : isGuestAccount2 ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
|
|
12167
12207
|
useEffect8(() => {
|
|
12168
12208
|
if (!cur || cur.email) return;
|
|
12169
12209
|
let alive = true;
|
|
@@ -12198,7 +12238,7 @@ function App() {
|
|
|
12198
12238
|
setViewKey(next?.apiKey);
|
|
12199
12239
|
setViewNonce((n) => n + 1);
|
|
12200
12240
|
};
|
|
12201
|
-
const locked = accounts.length === 0
|
|
12241
|
+
const locked = accounts.length === 0;
|
|
12202
12242
|
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
12203
12243
|
useInput8((input, key) => {
|
|
12204
12244
|
if (help) {
|
|
@@ -17003,6 +17043,13 @@ async function main() {
|
|
|
17003
17043
|
}
|
|
17004
17044
|
const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
|
|
17005
17045
|
if (MGMT_COMMANDS.has(subcommand ?? "")) {
|
|
17046
|
+
const { isGuestAccount: isGuestAccount2 } = await Promise.resolve().then(() => (init_client(), client_exports));
|
|
17047
|
+
if (subcommand !== "doctor" && isGuestAccount2()) {
|
|
17048
|
+
process.stderr.write(
|
|
17049
|
+
"\n This is a guest account, which can look but not change.\n Create an account to use the management commands:\n https://auth.solongate.com\n\n Your project, its policy and everything already recorded carry over,\n and this device keeps working without being paired again.\n\n"
|
|
17050
|
+
);
|
|
17051
|
+
process.exit(1);
|
|
17052
|
+
}
|
|
17006
17053
|
const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
|
|
17007
17054
|
const code = await runCommand2(subcommand, process.argv.slice(3));
|
|
17008
17055
|
process.exit(code);
|
package/dist/tui/index.js
CHANGED
|
@@ -904,6 +904,16 @@ function setViewCredentials(creds) {
|
|
|
904
904
|
viewOverride = creds;
|
|
905
905
|
cached2 = null;
|
|
906
906
|
}
|
|
907
|
+
var GUEST_EMAIL_SUFFIX = "@anonymous.solongate.invalid";
|
|
908
|
+
function isGuestAccount() {
|
|
909
|
+
try {
|
|
910
|
+
const active2 = loginCredentialFile().apiKey;
|
|
911
|
+
if (!active2) return false;
|
|
912
|
+
return listAccounts().some((a) => a.apiKey === active2 && (a.email ?? "").endsWith(GUEST_EMAIL_SUFFIX));
|
|
913
|
+
} catch {
|
|
914
|
+
return false;
|
|
915
|
+
}
|
|
916
|
+
}
|
|
907
917
|
function isActiveAccount(apiKey) {
|
|
908
918
|
return loginCredentialFile().apiKey === apiKey;
|
|
909
919
|
}
|
|
@@ -956,6 +966,12 @@ var ApiError = class extends Error {
|
|
|
956
966
|
this.code = code;
|
|
957
967
|
}
|
|
958
968
|
};
|
|
969
|
+
var GuestReadOnlyError = class extends Error {
|
|
970
|
+
constructor() {
|
|
971
|
+
super("Guest account: sign up at auth.solongate.com to change anything. Your project, its policy and everything recorded carry over.");
|
|
972
|
+
this.name = "GuestReadOnlyError";
|
|
973
|
+
}
|
|
974
|
+
};
|
|
959
975
|
var NotAuthenticatedError = class extends Error {
|
|
960
976
|
constructor() {
|
|
961
977
|
super("Not logged in. Run `solongate` and log in from the Accounts panel.");
|
|
@@ -1020,6 +1036,9 @@ function buildUrl(base, path, query) {
|
|
|
1020
1036
|
return url.toString();
|
|
1021
1037
|
}
|
|
1022
1038
|
async function request(method, path, opts = {}) {
|
|
1039
|
+
if (method !== "GET" && isGuestAccount()) {
|
|
1040
|
+
throw new GuestReadOnlyError();
|
|
1041
|
+
}
|
|
1023
1042
|
const creds = resolveCredentials(opts.apiUrl);
|
|
1024
1043
|
const url = buildUrl(creds.apiUrl, path, opts.query);
|
|
1025
1044
|
const headers = {
|
|
@@ -4929,6 +4948,7 @@ function SettingsPanel({
|
|
|
4929
4948
|
else if (inp === "m") {
|
|
4930
4949
|
if (cur.kind === "acct") {
|
|
4931
4950
|
const ok = setActiveAccount({ apiKey: cur.acc.apiKey, apiUrl: cur.acc.apiUrl });
|
|
4951
|
+
if (ok) clearLocalLog();
|
|
4932
4952
|
setMsg(ok ? { text: `\u2713 ${acctLabel(cur.acc)} is now the ACTIVE key (guard + logging)`, level: "ok" } : { text: "\u2717 could not set active", level: "bad" });
|
|
4933
4953
|
refreshAccounts();
|
|
4934
4954
|
} else if (cur.kind === "wh" || cur.kind === "alert" || cur.kind === "self" || cur.kind === "ll-enabled" || cur.kind === "ll-server") {
|
|
@@ -4948,6 +4968,7 @@ function SettingsPanel({
|
|
|
4948
4968
|
}
|
|
4949
4969
|
setConfirmDel(null);
|
|
4950
4970
|
removeAccount(target.apiKey);
|
|
4971
|
+
clearLocalLog();
|
|
4951
4972
|
let extra = " from this device";
|
|
4952
4973
|
if (wasActive) {
|
|
4953
4974
|
if (others.length) {
|
|
@@ -5354,9 +5375,8 @@ function App() {
|
|
|
5354
5375
|
const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
|
|
5355
5376
|
const cur = accounts[acctIdx];
|
|
5356
5377
|
const rawEmail = cur?.email ?? "";
|
|
5357
|
-
const
|
|
5358
|
-
const
|
|
5359
|
-
const acctLabel2 = !cur ? "not logged in" : !hasKey ? "signed out" : isGuestAccount ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
|
|
5378
|
+
const isGuestAccount2 = rawEmail.endsWith("@anonymous.solongate.invalid");
|
|
5379
|
+
const acctLabel2 = !cur ? "not logged in" : isGuestAccount2 ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
|
|
5360
5380
|
useEffect8(() => {
|
|
5361
5381
|
if (!cur || cur.email) return;
|
|
5362
5382
|
let alive = true;
|
|
@@ -5391,7 +5411,7 @@ function App() {
|
|
|
5391
5411
|
setViewKey(next?.apiKey);
|
|
5392
5412
|
setViewNonce((n) => n + 1);
|
|
5393
5413
|
};
|
|
5394
|
-
const locked = accounts.length === 0
|
|
5414
|
+
const locked = accounts.length === 0;
|
|
5395
5415
|
const effectiveSection = locked ? SETTINGS_SECTION : section;
|
|
5396
5416
|
useInput8((input, key) => {
|
|
5397
5417
|
if (help) {
|
package/dist/tui/local-log.d.ts
CHANGED
|
@@ -44,7 +44,13 @@ export interface LocalLogLine {
|
|
|
44
44
|
}
|
|
45
45
|
/** Delete ONE matching line (ts + tool [+ session]) from the local log file. */
|
|
46
46
|
export declare function deleteLocalEntry(at: number, tool: string, session?: string | null): number;
|
|
47
|
-
/**
|
|
47
|
+
/**
|
|
48
|
+
* Empty the local log file. Returns how many lines were removed.
|
|
49
|
+
*
|
|
50
|
+
* The file is one per machine, not one per account, and nothing in an entry
|
|
51
|
+
* says which account produced it — so when the account changes, the honest move
|
|
52
|
+
* is to start it over rather than keep showing another account's calls in Live.
|
|
53
|
+
*/
|
|
48
54
|
export declare function clearLocalLog(): number;
|
|
49
55
|
/** DLP pattern name + rate-limit-burst flag derived from a decision's reason. */
|
|
50
56
|
export declare function reasonSignals(reason: string | null | undefined): {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@solongate/proxy",
|
|
3
|
-
"version": "0.82.
|
|
3
|
+
"version": "0.82.89",
|
|
4
4
|
"description": "AI tool security proxy: protect any AI tool server with customizable policies, path/command constraints, rate limiting, and audit logging. No code changes required.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|