@pgplex/pgconsole 0.0.4 → 0.1.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 +1 @@
1
- import{_ as e,a as t,c as n,d as r,f as i,g as a,h as o,i as s,l as c,m as l,n as u,o as d,p as f,r as p,s as m,t as h,u as g}from"./index-D1j7ALWF.js";export{o as ensureModuleLoaded};
1
+ import{_ as e,a as t,c as n,d as r,f as i,g as a,h as o,i as s,l as c,m as l,n as u,o as d,p as f,r as p,s as m,t as h,u as g}from"./index-CzWqr-JX.js";export{o as ensureModuleLoaded};
@@ -9,8 +9,8 @@
9
9
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
10
10
  <link href="https://fonts.googleapis.com/css2?family=Geist+Mono:wght@100..900&display=swap" rel="stylesheet" />
11
11
  <title>pgconsole</title>
12
- <script type="module" crossorigin src="/assets/index-D1j7ALWF.js"></script>
13
- <link rel="stylesheet" crossorigin href="/assets/index-DgePIECN.css">
12
+ <script type="module" crossorigin src="/assets/index-CzWqr-JX.js"></script>
13
+ <link rel="stylesheet" crossorigin href="/assets/index-C-1OZ2hX.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
package/dist/server.mjs CHANGED
@@ -41271,57 +41271,36 @@ See https://docs.pgconsole.com/configuration/config`);
41271
41271
  if (a.jwt_secret.length < 32) {
41272
41272
  throw new Error("Auth jwt_secret must be at least 32 characters");
41273
41273
  }
41274
- let providers = void 0;
41274
+ const providers = [];
41275
41275
  const rawProviders = a.providers;
41276
- if (rawProviders) {
41277
- providers = {};
41278
- for (const key of Object.keys(rawProviders)) {
41279
- const raw = rawProviders[key];
41280
- if (key === "google") {
41281
- if (!raw.client_id || typeof raw.client_id !== "string") {
41282
- throw new Error("Google provider missing required field: client_id");
41283
- }
41284
- if (!raw.client_secret || typeof raw.client_secret !== "string") {
41285
- throw new Error("Google provider missing required field: client_secret");
41286
- }
41287
- providers.google = {
41288
- client_id: raw.client_id,
41289
- client_secret: raw.client_secret
41290
- };
41291
- } else if (key === "keycloak") {
41292
- if (!raw.issuer_url || typeof raw.issuer_url !== "string") {
41293
- throw new Error("Keycloak provider missing required field: issuer_url");
41294
- }
41295
- if (!raw.client_id || typeof raw.client_id !== "string") {
41296
- throw new Error("Keycloak provider missing required field: client_id");
41297
- }
41298
- if (!raw.client_secret || typeof raw.client_secret !== "string") {
41299
- throw new Error("Keycloak provider missing required field: client_secret");
41300
- }
41301
- providers.keycloak = {
41302
- issuer_url: raw.issuer_url.replace(/\/+$/, ""),
41303
- client_id: raw.client_id,
41304
- client_secret: raw.client_secret
41305
- };
41306
- } else if (key === "okta") {
41307
- if (!raw.issuer_url || typeof raw.issuer_url !== "string") {
41308
- throw new Error("Okta provider missing required field: issuer_url");
41309
- }
41310
- if (!raw.client_id || typeof raw.client_id !== "string") {
41311
- throw new Error("Okta provider missing required field: client_id");
41312
- }
41313
- if (!raw.client_secret || typeof raw.client_secret !== "string") {
41314
- throw new Error("Okta provider missing required field: client_secret");
41315
- }
41316
- providers.okta = {
41317
- issuer_url: raw.issuer_url.replace(/\/+$/, ""),
41318
- client_id: raw.client_id,
41319
- client_secret: raw.client_secret
41320
- };
41321
- }
41276
+ const validProviderTypes = ["google", "keycloak", "okta"];
41277
+ if (rawProviders && Array.isArray(rawProviders)) {
41278
+ for (const entry of rawProviders) {
41279
+ const raw = entry;
41280
+ if (!raw.type || typeof raw.type !== "string") {
41281
+ throw new Error("Auth provider missing required field: type");
41282
+ }
41283
+ if (!validProviderTypes.includes(raw.type)) {
41284
+ throw new Error(`Auth provider has invalid type: ${raw.type}. Must be one of: ${validProviderTypes.join(", ")}`);
41285
+ }
41286
+ if (!raw.client_id || typeof raw.client_id !== "string") {
41287
+ throw new Error(`${raw.type} provider missing required field: client_id`);
41288
+ }
41289
+ if (!raw.client_secret || typeof raw.client_secret !== "string") {
41290
+ throw new Error(`${raw.type} provider missing required field: client_secret`);
41291
+ }
41292
+ if ((raw.type === "keycloak" || raw.type === "okta") && (!raw.issuer_url || typeof raw.issuer_url !== "string")) {
41293
+ throw new Error(`${raw.type} provider missing required field: issuer_url`);
41294
+ }
41295
+ providers.push({
41296
+ type: raw.type,
41297
+ client_id: raw.client_id,
41298
+ client_secret: raw.client_secret,
41299
+ issuer_url: typeof raw.issuer_url === "string" ? raw.issuer_url.replace(/\/+$/, "") : void 0
41300
+ });
41322
41301
  }
41323
41302
  }
41324
- const hasOAuthProvider = providers?.google || providers?.keycloak || providers?.okta;
41303
+ const hasOAuthProvider = providers.length > 0;
41325
41304
  if (hasOAuthProvider && !external_url) {
41326
41305
  throw new Error("[general] external_url is required when OAuth providers are enabled");
41327
41306
  }
@@ -41395,10 +41374,10 @@ See https://docs.pgconsole.com/configuration/config`);
41395
41374
  if (typeof perm !== "string") {
41396
41375
  throw new Error(`IAM rule ${ruleNum} has invalid permission: must be string`);
41397
41376
  }
41398
- if (perm === "allPermissions") {
41377
+ if (perm === "*") {
41399
41378
  permissions.push(...validPermissions);
41400
41379
  } else if (!validPermissions.includes(perm)) {
41401
- throw new Error(`IAM rule ${ruleNum} has invalid permission: ${perm}. Must be one of: ${validPermissions.join(", ")}, allPermissions`);
41380
+ throw new Error(`IAM rule ${ruleNum} has invalid permission: ${perm}. Must be one of: ${validPermissions.join(", ")}, *`);
41402
41381
  } else {
41403
41382
  permissions.push(perm);
41404
41383
  }
@@ -41412,7 +41391,7 @@ See https://docs.pgconsole.com/configuration/config`);
41412
41391
  throw new Error(`IAM rule ${ruleNum} has invalid member: must be non-empty string`);
41413
41392
  }
41414
41393
  const m2 = member.trim();
41415
- if (m2 === "allUsers") {
41394
+ if (m2 === "*") {
41416
41395
  members.push(m2);
41417
41396
  } else if (m2.startsWith("user:")) {
41418
41397
  const email = m2.slice(5);
@@ -41430,7 +41409,7 @@ See https://docs.pgconsole.com/configuration/config`);
41430
41409
  }
41431
41410
  members.push(m2);
41432
41411
  } else {
41433
- throw new Error(`IAM rule ${ruleNum} has invalid member format: ${m2}. Must be "allUsers", "user:xxx", or "group:xxx"`);
41412
+ throw new Error(`IAM rule ${ruleNum} has invalid member format: ${m2}. Must be "*", "user:xxx", or "group:xxx"`);
41434
41413
  }
41435
41414
  }
41436
41415
  iam.push({ connection, permissions, members });
@@ -41472,6 +41451,9 @@ function getConnectionById(id) {
41472
41451
  function getAuthConfig() {
41473
41452
  return loadedConfig.auth;
41474
41453
  }
41454
+ function getAuthProvider(type) {
41455
+ return loadedConfig.auth?.providers.find((p) => p.type === type);
41456
+ }
41475
41457
  function getUsers() {
41476
41458
  return loadedConfig.users;
41477
41459
  }
@@ -41634,11 +41616,24 @@ function auditSQL(actor, connection, database, sql, success, duration_ms, row_co
41634
41616
  if (error) event.error = error;
41635
41617
  emit(event);
41636
41618
  }
41619
+ function auditExport(actor, connection, database, sql, row_count, format) {
41620
+ emit({
41621
+ type: "audit",
41622
+ ts: now(),
41623
+ action: "data.export",
41624
+ actor,
41625
+ connection,
41626
+ database,
41627
+ sql,
41628
+ row_count,
41629
+ format
41630
+ });
41631
+ }
41637
41632
 
41638
41633
  // server/lib/oauth/google.ts
41639
41634
  function registerGoogleOAuth(router3, opts) {
41640
41635
  router3.get("/google", (_req, res) => {
41641
- const google = getAuthConfig()?.providers?.google;
41636
+ const google = getAuthProvider("google");
41642
41637
  if (!google) {
41643
41638
  return res.status(400).json({ error: "Google OAuth not configured" });
41644
41639
  }
@@ -41655,7 +41650,7 @@ function registerGoogleOAuth(router3, opts) {
41655
41650
  return res.redirect(`https://accounts.google.com/o/oauth2/v2/auth?${params}`);
41656
41651
  });
41657
41652
  router3.get("/google/callback", async (req, res) => {
41658
- const google = getAuthConfig()?.providers?.google;
41653
+ const google = getAuthProvider("google");
41659
41654
  const externalUrl = getExternalUrl();
41660
41655
  if (!google) {
41661
41656
  return res.redirect(`${externalUrl}/signin?error=not_configured`);
@@ -41725,7 +41720,7 @@ function registerGoogleOAuth(router3, opts) {
41725
41720
  // server/lib/oauth/keycloak.ts
41726
41721
  function registerKeycloakOAuth(router3, opts) {
41727
41722
  router3.get("/keycloak", (_req, res) => {
41728
- const keycloak = getAuthConfig()?.providers?.keycloak;
41723
+ const keycloak = getAuthProvider("keycloak");
41729
41724
  if (!keycloak) {
41730
41725
  return res.status(400).json({ error: "Keycloak not configured" });
41731
41726
  }
@@ -41742,7 +41737,7 @@ function registerKeycloakOAuth(router3, opts) {
41742
41737
  return res.redirect(`${keycloak.issuer_url}/protocol/openid-connect/auth?${params}`);
41743
41738
  });
41744
41739
  router3.get("/keycloak/callback", async (req, res) => {
41745
- const keycloak = getAuthConfig()?.providers?.keycloak;
41740
+ const keycloak = getAuthProvider("keycloak");
41746
41741
  const externalUrl = getExternalUrl();
41747
41742
  if (!keycloak) {
41748
41743
  return res.redirect(`${externalUrl}/signin?error=not_configured`);
@@ -41809,7 +41804,7 @@ function registerKeycloakOAuth(router3, opts) {
41809
41804
  // server/lib/oauth/okta.ts
41810
41805
  function registerOktaOAuth(router3, opts) {
41811
41806
  router3.get("/okta", (_req, res) => {
41812
- const okta = getAuthConfig()?.providers?.okta;
41807
+ const okta = getAuthProvider("okta");
41813
41808
  if (!okta) {
41814
41809
  return res.status(400).json({ error: "Okta not configured" });
41815
41810
  }
@@ -41826,7 +41821,7 @@ function registerOktaOAuth(router3, opts) {
41826
41821
  return res.redirect(`${okta.issuer_url}/v1/authorize?${params}`);
41827
41822
  });
41828
41823
  router3.get("/okta/callback", async (req, res) => {
41829
- const okta = getAuthConfig()?.providers?.okta;
41824
+ const okta = getAuthProvider("okta");
41830
41825
  const externalUrl = getExternalUrl();
41831
41826
  if (!okta) {
41832
41827
  return res.redirect(`${externalUrl}/signin?error=not_configured`);
@@ -42014,14 +42009,12 @@ router.get("/providers", (_req, res) => {
42014
42009
  const plan = getPlan();
42015
42010
  const providers = [];
42016
42011
  if (getUsers().some((u) => u.password)) providers.push({ name: "basic" });
42017
- if (config?.providers) {
42018
- for (const key of Object.keys(config.providers)) {
42019
- const feat = SSO_FEATURE[key];
42020
- if (feat && !feature(feat, plan)) {
42021
- providers.push({ name: key, requiredPlan: requiredPlan(feat) });
42022
- } else {
42023
- providers.push({ name: key });
42024
- }
42012
+ for (const provider of config?.providers ?? []) {
42013
+ const feat = SSO_FEATURE[provider.type];
42014
+ if (feat && !feature(feat, plan)) {
42015
+ providers.push({ name: provider.type, requiredPlan: requiredPlan(feat) });
42016
+ } else {
42017
+ providers.push({ name: provider.type });
42025
42018
  }
42026
42019
  }
42027
42020
  return res.json({ providers });
@@ -56345,6 +56338,93 @@ var TerminateSessionResponse = class _TerminateSessionResponse extends Message {
56345
56338
  return proto3.util.equals(_TerminateSessionResponse, a, b);
56346
56339
  }
56347
56340
  };
56341
+ var AuditExportRequest = class _AuditExportRequest extends Message {
56342
+ /**
56343
+ * @generated from field: string connection_id = 1;
56344
+ */
56345
+ connectionId = "";
56346
+ /**
56347
+ * @generated from field: string sql = 2;
56348
+ */
56349
+ sql = "";
56350
+ /**
56351
+ * @generated from field: int32 row_count = 3;
56352
+ */
56353
+ rowCount = 0;
56354
+ /**
56355
+ * @generated from field: string format = 4;
56356
+ */
56357
+ format = "";
56358
+ constructor(data) {
56359
+ super();
56360
+ proto3.util.initPartial(data, this);
56361
+ }
56362
+ static runtime = proto3;
56363
+ static typeName = "query.v1.AuditExportRequest";
56364
+ static fields = proto3.util.newFieldList(() => [
56365
+ {
56366
+ no: 1,
56367
+ name: "connection_id",
56368
+ kind: "scalar",
56369
+ T: 9
56370
+ /* ScalarType.STRING */
56371
+ },
56372
+ {
56373
+ no: 2,
56374
+ name: "sql",
56375
+ kind: "scalar",
56376
+ T: 9
56377
+ /* ScalarType.STRING */
56378
+ },
56379
+ {
56380
+ no: 3,
56381
+ name: "row_count",
56382
+ kind: "scalar",
56383
+ T: 5
56384
+ /* ScalarType.INT32 */
56385
+ },
56386
+ {
56387
+ no: 4,
56388
+ name: "format",
56389
+ kind: "scalar",
56390
+ T: 9
56391
+ /* ScalarType.STRING */
56392
+ }
56393
+ ]);
56394
+ static fromBinary(bytes, options) {
56395
+ return new _AuditExportRequest().fromBinary(bytes, options);
56396
+ }
56397
+ static fromJson(jsonValue, options) {
56398
+ return new _AuditExportRequest().fromJson(jsonValue, options);
56399
+ }
56400
+ static fromJsonString(jsonString, options) {
56401
+ return new _AuditExportRequest().fromJsonString(jsonString, options);
56402
+ }
56403
+ static equals(a, b) {
56404
+ return proto3.util.equals(_AuditExportRequest, a, b);
56405
+ }
56406
+ };
56407
+ var AuditExportResponse = class _AuditExportResponse extends Message {
56408
+ constructor(data) {
56409
+ super();
56410
+ proto3.util.initPartial(data, this);
56411
+ }
56412
+ static runtime = proto3;
56413
+ static typeName = "query.v1.AuditExportResponse";
56414
+ static fields = proto3.util.newFieldList(() => []);
56415
+ static fromBinary(bytes, options) {
56416
+ return new _AuditExportResponse().fromBinary(bytes, options);
56417
+ }
56418
+ static fromJson(jsonValue, options) {
56419
+ return new _AuditExportResponse().fromJson(jsonValue, options);
56420
+ }
56421
+ static fromJsonString(jsonString, options) {
56422
+ return new _AuditExportResponse().fromJsonString(jsonString, options);
56423
+ }
56424
+ static equals(a, b) {
56425
+ return proto3.util.equals(_AuditExportResponse, a, b);
56426
+ }
56427
+ };
56348
56428
 
56349
56429
  // src/gen/query_connect.ts
56350
56430
  var QueryService = {
@@ -56511,6 +56591,15 @@ var QueryService = {
56511
56591
  I: TerminateSessionRequest,
56512
56592
  O: TerminateSessionResponse,
56513
56593
  kind: MethodKind.Unary
56594
+ },
56595
+ /**
56596
+ * @generated from rpc query.v1.QueryService.AuditExport
56597
+ */
56598
+ auditExport: {
56599
+ name: "AuditExport",
56600
+ I: AuditExportRequest,
56601
+ O: AuditExportResponse,
56602
+ kind: MethodKind.Unary
56514
56603
  }
56515
56604
  }
56516
56605
  };
@@ -57484,12 +57573,17 @@ function setConnectionVersion(connectionId, version) {
57484
57573
  const info = { version };
57485
57574
  connectionCache.set(connectionId, info);
57486
57575
  }
57487
- function extractPostgresVersion(versionString) {
57576
+ async function testAndCacheConnection(client, connectionId) {
57577
+ await client`SELECT 1`;
57578
+ const versionResult = await client`SELECT version()`;
57579
+ const versionString = versionResult[0]?.version || "";
57488
57580
  const match = versionString.match(/PostgreSQL (\d+)/);
57489
57581
  if (!match?.[1]) {
57490
57582
  throw new Error(`Failed to extract PostgreSQL version from: ${versionString}`);
57491
57583
  }
57492
- return match[1];
57584
+ const version = match[1];
57585
+ setConnectionVersion(connectionId, version);
57586
+ return version;
57493
57587
  }
57494
57588
 
57495
57589
  // server/lib/iam.ts
@@ -57538,7 +57632,7 @@ function getUserPermissions(email, connectionId) {
57538
57632
  continue;
57539
57633
  }
57540
57634
  const matches = rule.members.some((member) => {
57541
- if (member === "allUsers") {
57635
+ if (member === "*") {
57542
57636
  return true;
57543
57637
  }
57544
57638
  if (member.startsWith("user:")) {
@@ -57640,11 +57734,7 @@ var connectionServiceHandlers = {
57640
57734
  sslMode: conn.ssl_mode || "prefer"
57641
57735
  }, user?.email);
57642
57736
  try {
57643
- await client`SELECT 1`;
57644
- const versionResult = await client`SELECT version()`;
57645
- const versionString = versionResult[0]?.version || "";
57646
- const version = extractPostgresVersion(versionString);
57647
- setConnectionVersion(req.id, version);
57737
+ await testAndCacheConnection(client, req.id);
57648
57738
  const latencyMs = Date.now() - start2;
57649
57739
  return { success: true, error: "", latencyMs };
57650
57740
  } catch (err) {
@@ -63197,6 +63287,21 @@ var queryServiceHandlers = {
63197
63287
  error: err instanceof Error ? err.message : "Failed to terminate session"
63198
63288
  };
63199
63289
  }
63290
+ },
63291
+ async auditExport(req, context) {
63292
+ if (!req.connectionId) {
63293
+ throw new ConnectError("connection_id is required", Code.InvalidArgument);
63294
+ }
63295
+ const user = await getUserFromContext(context.values);
63296
+ if (!user) {
63297
+ throw new ConnectError("Authentication required", Code.Unauthenticated);
63298
+ }
63299
+ const conn = getConnectionById(req.connectionId);
63300
+ if (!conn) {
63301
+ throw new ConnectError("Connection not found", Code.NotFound);
63302
+ }
63303
+ auditExport(user.email, req.connectionId, conn.database, req.sql, req.rowCount, req.format);
63304
+ return {};
63200
63305
  }
63201
63306
  };
63202
63307
 
@@ -92450,11 +92555,7 @@ async function testAllConnections() {
92450
92555
  sslMode: conn.ssl_mode || "prefer"
92451
92556
  });
92452
92557
  try {
92453
- await client`SELECT 1`;
92454
- const versionResult = await client`SELECT version()`;
92455
- const versionString = versionResult[0]?.version || "";
92456
- const version = extractPostgresVersion(versionString);
92457
- setConnectionVersion(conn.id, version);
92558
+ const version = await testAndCacheConnection(client, conn.id);
92458
92559
  console.log(` \u2713 ${conn.name} (PostgreSQL ${version})`);
92459
92560
  } finally {
92460
92561
  await client.end();
@@ -92532,6 +92633,7 @@ async function start() {
92532
92633
  const configPath = args.config || "pgconsole.toml";
92533
92634
  try {
92534
92635
  await loadConfig(configPath);
92636
+ console.log(`\u2713 Loaded config from: ${path4.resolve(configPath)}`);
92535
92637
  } catch (error) {
92536
92638
  console.error("Failed to load config:", error instanceof Error ? error.message : error);
92537
92639
  process.exit(1);
@@ -92561,7 +92663,7 @@ async function start() {
92561
92663
  \\ \\_\\ /\\____/
92562
92664
  \\/_/ \\_/__/
92563
92665
 
92564
- Version ${"0.0.4"}
92666
+ Version ${"0.1.1"}
92565
92667
  `);
92566
92668
  console.log(`Server running on http://localhost:${port}`);
92567
92669
  const browserUrl = false ? `http://localhost:5173` : getExternalUrl() || `http://localhost:${port}`;