@solongate/proxy 0.82.86 → 0.82.88

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.
@@ -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
  /**
package/dist/index.js CHANGED
@@ -7518,6 +7518,24 @@ 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
+ NotAuthenticatedError: () => NotAuthenticatedError,
7527
+ clearActiveCredential: () => clearActiveCredential,
7528
+ isActiveAccount: () => isActiveAccount,
7529
+ isAuthenticated: () => isAuthenticated,
7530
+ isGuestAccount: () => isGuestAccount,
7531
+ listAccounts: () => listAccounts,
7532
+ removeAccount: () => removeAccount,
7533
+ request: () => request,
7534
+ resolveCredentials: () => resolveCredentials,
7535
+ saveAccount: () => saveAccount,
7536
+ setActiveAccount: () => setActiveAccount,
7537
+ setViewCredentials: () => setViewCredentials
7538
+ });
7521
7539
  import { readFileSync as readFileSync9, writeFileSync as writeFileSync7, mkdirSync as mkdirSync6, existsSync as existsSync5 } from "fs";
7522
7540
  import { resolve as resolve4, join as join9 } from "path";
7523
7541
  import { homedir as homedir7 } from "os";
@@ -7569,6 +7587,15 @@ function setViewCredentials(creds) {
7569
7587
  viewOverride = creds;
7570
7588
  cached2 = null;
7571
7589
  }
7590
+ function isGuestAccount() {
7591
+ try {
7592
+ const active2 = loginCredentialFile().apiKey;
7593
+ if (!active2) return false;
7594
+ return listAccounts().some((a) => a.apiKey === active2 && (a.email ?? "").endsWith(GUEST_EMAIL_SUFFIX));
7595
+ } catch {
7596
+ return false;
7597
+ }
7598
+ }
7572
7599
  function isActiveAccount(apiKey) {
7573
7600
  return loginCredentialFile().apiKey === apiKey;
7574
7601
  }
@@ -7723,7 +7750,7 @@ async function request(method, path, opts = {}) {
7723
7750
  }
7724
7751
  return json;
7725
7752
  }
7726
- var DEFAULT_API_URL2, accountsFile, viewOverride, ApiError, NotAuthenticatedError, cached2;
7753
+ var DEFAULT_API_URL2, accountsFile, viewOverride, GUEST_EMAIL_SUFFIX, ApiError, NotAuthenticatedError, cached2;
7727
7754
  var init_client = __esm({
7728
7755
  "src/api-client/client.ts"() {
7729
7756
  "use strict";
@@ -7731,6 +7758,7 @@ var init_client = __esm({
7731
7758
  DEFAULT_API_URL2 = "https://api.solongate.com";
7732
7759
  accountsFile = () => join9(homedir7(), ".solongate", "accounts.json");
7733
7760
  viewOverride = null;
7761
+ GUEST_EMAIL_SUFFIX = "@anonymous.solongate.invalid";
7734
7762
  ApiError = class extends Error {
7735
7763
  status;
7736
7764
  code;
@@ -11857,7 +11885,8 @@ function SettingsPanel({
11857
11885
  }
11858
11886
  const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
11859
11887
  const rawError = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
11860
- const authError = rawError && /invalid api key|authentication|401|unauthor/i.test(rawError) ? rawError : null;
11888
+ const authError = rawError && /invalid api key|authentication|401|unauthor|not logged in/i.test(rawError) ? rawError : null;
11889
+ const noKey = !!authError && /not logged in/i.test(authError);
11861
11890
  const error = authError ? null : rawError;
11862
11891
  const onOff = (on) => on ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "off" });
11863
11892
  const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
@@ -12053,7 +12082,10 @@ function SettingsPanel({
12053
12082
  const moreBelow = Math.max(0, lineEls.length - (startL + budget));
12054
12083
  return /* @__PURE__ */ jsx8(DataView, { loading, error, children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
12055
12084
  /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.dim, children: focused ? `\u2191\u2193 move \xB7 enter act \xB7 m toggle \xB7 t test \xB7 e edit \xB7 x remove \xB7 d delete \xB7 n add${moreAbove ? ` \xB7 \u25B2${moreAbove}` : ""}${moreBelow ? ` \xB7 \u25BC${moreBelow}` : ""}` : "press \u2192 to configure" }),
12056
- authError ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.bad, children: truncate2("\u2717 this device's key is invalid or was revoked \u2014 press x on the account below to remove it, then + add account to pair again", cols) }) : null,
12085
+ authError ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.bad, children: truncate2(
12086
+ noKey ? "\u2717 this device is not paired yet \u2014 press + add account below to sign in and pair it" : "\u2717 this device's key is invalid or was revoked \u2014 press x on the account below to remove it, then + add account to pair again",
12087
+ cols
12088
+ ) }) : null,
12057
12089
  editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
12058
12090
  /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
12059
12091
  /* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
@@ -12157,8 +12189,9 @@ function App() {
12157
12189
  const acctIdx = Math.max(0, accounts.findIndex((a) => a.apiKey === viewKey));
12158
12190
  const cur = accounts[acctIdx];
12159
12191
  const rawEmail = cur?.email ?? "";
12160
- const isGuestAccount = rawEmail.endsWith("@anonymous.solongate.invalid");
12161
- const acctLabel2 = cur ? isGuestAccount ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
12192
+ const isGuestAccount2 = rawEmail.endsWith("@anonymous.solongate.invalid");
12193
+ const hasKey = isAuthenticated();
12194
+ const acctLabel2 = !cur ? "not logged in" : !hasKey ? "signed out" : isGuestAccount2 ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
12162
12195
  useEffect8(() => {
12163
12196
  if (!cur || cur.email) return;
12164
12197
  let alive = true;
@@ -12193,7 +12226,7 @@ function App() {
12193
12226
  setViewKey(next?.apiKey);
12194
12227
  setViewNonce((n) => n + 1);
12195
12228
  };
12196
- const locked = accounts.length === 0 || !isAuthenticated();
12229
+ const locked = accounts.length === 0 || !hasKey;
12197
12230
  const effectiveSection = locked ? SETTINGS_SECTION : section;
12198
12231
  useInput8((input, key) => {
12199
12232
  if (help) {
@@ -16998,6 +17031,13 @@ async function main() {
16998
17031
  }
16999
17032
  const MGMT_COMMANDS = /* @__PURE__ */ new Set(["policy", "ratelimit", "dlp", "stats", "audit", "sessions", "session", "doctor", "watch", "alerts", "webhooks"]);
17000
17033
  if (MGMT_COMMANDS.has(subcommand ?? "")) {
17034
+ const { isGuestAccount: isGuestAccount2 } = await Promise.resolve().then(() => (init_client(), client_exports));
17035
+ if (subcommand !== "doctor" && isGuestAccount2()) {
17036
+ process.stderr.write(
17037
+ "\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"
17038
+ );
17039
+ process.exit(1);
17040
+ }
17001
17041
  const { runCommand: runCommand2 } = await Promise.resolve().then(() => (init_commands(), commands_exports));
17002
17042
  const code = await runCommand2(subcommand, process.argv.slice(3));
17003
17043
  process.exit(code);
package/dist/tui/index.js CHANGED
@@ -5073,7 +5073,8 @@ function SettingsPanel({
5073
5073
  }
5074
5074
  const loading = !locked && (localQ.loading && !localQ.data || whQ.loading && !whQ.data || alertQ.loading && !alertQ.data || guardQ.loading && !guardQ.data || selfQ.loading && !selfQ.data);
5075
5075
  const rawError = locked ? null : localQ.error ?? whQ.error ?? alertQ.error ?? guardQ.error ?? selfQ.error;
5076
- const authError = rawError && /invalid api key|authentication|401|unauthor/i.test(rawError) ? rawError : null;
5076
+ const authError = rawError && /invalid api key|authentication|401|unauthor|not logged in/i.test(rawError) ? rawError : null;
5077
+ const noKey = !!authError && /not logged in/i.test(authError);
5077
5078
  const error = authError ? null : rawError;
5078
5079
  const onOff = (on) => on ? /* @__PURE__ */ jsx8(Text8, { color: theme.ok, children: "on " }) : /* @__PURE__ */ jsx8(Text8, { color: theme.dim, children: "off" });
5079
5080
  const chanOf = (rule) => [...rule.emails ?? [], ...(rule.telegram ?? []).map((t) => "tg " + t)].join(", ") || "\u2014";
@@ -5269,7 +5270,10 @@ function SettingsPanel({
5269
5270
  const moreBelow = Math.max(0, lineEls.length - (startL + budget));
5270
5271
  return /* @__PURE__ */ jsx8(DataView, { loading, error, children: /* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
5271
5272
  /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.dim, children: focused ? `\u2191\u2193 move \xB7 enter act \xB7 m toggle \xB7 t test \xB7 e edit \xB7 x remove \xB7 d delete \xB7 n add${moreAbove ? ` \xB7 \u25B2${moreAbove}` : ""}${moreBelow ? ` \xB7 \u25BC${moreBelow}` : ""}` : "press \u2192 to configure" }),
5272
- authError ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.bad, children: truncate("\u2717 this device's key is invalid or was revoked \u2014 press x on the account below to remove it, then + add account to pair again", cols) }) : null,
5273
+ authError ? /* @__PURE__ */ jsx8(Text8, { wrap: "truncate", color: theme.bad, children: truncate(
5274
+ noKey ? "\u2717 this device is not paired yet \u2014 press + add account below to sign in and pair it" : "\u2717 this device's key is invalid or was revoked \u2014 press x on the account below to remove it, then + add account to pair again",
5275
+ cols
5276
+ ) }) : null,
5273
5277
  editing ? /* @__PURE__ */ jsxs8(Box8, { children: [
5274
5278
  /* @__PURE__ */ jsx8(Text8, { color: theme.warn, children: editing === "path" ? "local log path: " : "webhook url: " }),
5275
5279
  /* @__PURE__ */ jsx8(TextInput6, { value: input, onChange: setInput, onSubmit: submitInput })
@@ -5351,7 +5355,8 @@ function App() {
5351
5355
  const cur = accounts[acctIdx];
5352
5356
  const rawEmail = cur?.email ?? "";
5353
5357
  const isGuestAccount = rawEmail.endsWith("@anonymous.solongate.invalid");
5354
- const acctLabel2 = cur ? isGuestAccount ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}` : "not logged in";
5358
+ const hasKey = isAuthenticated();
5359
+ const acctLabel2 = !cur ? "not logged in" : !hasKey ? "signed out" : isGuestAccount ? "Anonymous" : rawEmail || cur.user || cur.project || `account \u2026${cur.apiKey.slice(-4)}`;
5355
5360
  useEffect8(() => {
5356
5361
  if (!cur || cur.email) return;
5357
5362
  let alive = true;
@@ -5386,7 +5391,7 @@ function App() {
5386
5391
  setViewKey(next?.apiKey);
5387
5392
  setViewNonce((n) => n + 1);
5388
5393
  };
5389
- const locked = accounts.length === 0 || !isAuthenticated();
5394
+ const locked = accounts.length === 0 || !hasKey;
5390
5395
  const effectiveSection = locked ? SETTINGS_SECTION : section;
5391
5396
  useInput8((input, key) => {
5392
5397
  if (help) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@solongate/proxy",
3
- "version": "0.82.86",
3
+ "version": "0.82.88",
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": {