postgresai 0.14.0-beta.1 → 0.14.0-beta.10

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.
Files changed (78) hide show
  1. package/README.md +104 -61
  2. package/bin/postgres-ai.ts +1304 -417
  3. package/bun.lock +258 -0
  4. package/bunfig.toml +20 -0
  5. package/dist/bin/postgres-ai.js +28559 -1778
  6. package/dist/sql/01.role.sql +16 -0
  7. package/dist/sql/02.permissions.sql +37 -0
  8. package/dist/sql/03.optional_rds.sql +6 -0
  9. package/dist/sql/04.optional_self_managed.sql +8 -0
  10. package/dist/sql/05.helpers.sql +439 -0
  11. package/dist/sql/sql/01.role.sql +16 -0
  12. package/dist/sql/sql/02.permissions.sql +37 -0
  13. package/dist/sql/sql/03.optional_rds.sql +6 -0
  14. package/dist/sql/sql/04.optional_self_managed.sql +8 -0
  15. package/dist/sql/sql/05.helpers.sql +439 -0
  16. package/lib/auth-server.ts +124 -106
  17. package/lib/checkup-api.ts +386 -0
  18. package/lib/checkup.ts +1330 -0
  19. package/lib/config.ts +6 -3
  20. package/lib/init.ts +415 -220
  21. package/lib/issues.ts +400 -191
  22. package/lib/mcp-server.ts +213 -90
  23. package/lib/metrics-embedded.ts +79 -0
  24. package/lib/metrics-loader.ts +127 -0
  25. package/lib/util.ts +61 -0
  26. package/package.json +20 -10
  27. package/packages/postgres-ai/README.md +26 -0
  28. package/packages/postgres-ai/bin/postgres-ai.js +27 -0
  29. package/packages/postgres-ai/package.json +27 -0
  30. package/scripts/embed-metrics.ts +154 -0
  31. package/sql/01.role.sql +8 -7
  32. package/sql/02.permissions.sql +9 -5
  33. package/sql/05.helpers.sql +439 -0
  34. package/test/auth.test.ts +258 -0
  35. package/test/checkup.integration.test.ts +321 -0
  36. package/test/checkup.test.ts +891 -0
  37. package/test/init.integration.test.ts +499 -0
  38. package/test/init.test.ts +417 -0
  39. package/test/issues.cli.test.ts +314 -0
  40. package/test/issues.test.ts +456 -0
  41. package/test/mcp-server.test.ts +988 -0
  42. package/test/schema-validation.test.ts +81 -0
  43. package/test/test-utils.ts +122 -0
  44. package/tsconfig.json +12 -20
  45. package/dist/bin/postgres-ai.d.ts +0 -3
  46. package/dist/bin/postgres-ai.d.ts.map +0 -1
  47. package/dist/bin/postgres-ai.js.map +0 -1
  48. package/dist/lib/auth-server.d.ts +0 -31
  49. package/dist/lib/auth-server.d.ts.map +0 -1
  50. package/dist/lib/auth-server.js +0 -263
  51. package/dist/lib/auth-server.js.map +0 -1
  52. package/dist/lib/config.d.ts +0 -45
  53. package/dist/lib/config.d.ts.map +0 -1
  54. package/dist/lib/config.js +0 -181
  55. package/dist/lib/config.js.map +0 -1
  56. package/dist/lib/init.d.ts +0 -75
  57. package/dist/lib/init.d.ts.map +0 -1
  58. package/dist/lib/init.js +0 -483
  59. package/dist/lib/init.js.map +0 -1
  60. package/dist/lib/issues.d.ts +0 -75
  61. package/dist/lib/issues.d.ts.map +0 -1
  62. package/dist/lib/issues.js +0 -336
  63. package/dist/lib/issues.js.map +0 -1
  64. package/dist/lib/mcp-server.d.ts +0 -9
  65. package/dist/lib/mcp-server.d.ts.map +0 -1
  66. package/dist/lib/mcp-server.js +0 -168
  67. package/dist/lib/mcp-server.js.map +0 -1
  68. package/dist/lib/pkce.d.ts +0 -32
  69. package/dist/lib/pkce.d.ts.map +0 -1
  70. package/dist/lib/pkce.js +0 -101
  71. package/dist/lib/pkce.js.map +0 -1
  72. package/dist/lib/util.d.ts +0 -27
  73. package/dist/lib/util.d.ts.map +0 -1
  74. package/dist/lib/util.js +0 -46
  75. package/dist/lib/util.js.map +0 -1
  76. package/dist/package.json +0 -46
  77. package/test/init.integration.test.cjs +0 -368
  78. package/test/init.test.cjs +0 -154
@@ -1,154 +0,0 @@
1
- const test = require("node:test");
2
- const assert = require("node:assert/strict");
3
-
4
- // These tests intentionally import the compiled JS output.
5
- // Run via: npm --prefix cli test
6
- const init = require("../dist/lib/init.js");
7
-
8
- function runCli(args, env = {}) {
9
- const { spawnSync } = require("node:child_process");
10
- const path = require("node:path");
11
- const node = process.execPath;
12
- const cliPath = path.resolve(__dirname, "..", "dist", "bin", "postgres-ai.js");
13
- return spawnSync(node, [cliPath, ...args], {
14
- encoding: "utf8",
15
- env: { ...process.env, ...env },
16
- });
17
- }
18
-
19
- test("maskConnectionString hides password when present", () => {
20
- const masked = init.maskConnectionString("postgresql://user:secret@localhost:5432/mydb");
21
- assert.match(masked, /postgresql:\/\/user:\*{5}@localhost:5432\/mydb/);
22
- assert.doesNotMatch(masked, /secret/);
23
- });
24
-
25
- test("parseLibpqConninfo parses basic host/dbname/user/port/password", () => {
26
- const cfg = init.parseLibpqConninfo("dbname=mydb host=localhost user=alice port=5432 password=secret");
27
- assert.equal(cfg.database, "mydb");
28
- assert.equal(cfg.host, "localhost");
29
- assert.equal(cfg.user, "alice");
30
- assert.equal(cfg.port, 5432);
31
- assert.equal(cfg.password, "secret");
32
- });
33
-
34
- test("parseLibpqConninfo supports quoted values", () => {
35
- const cfg = init.parseLibpqConninfo("dbname='my db' host='local host'");
36
- assert.equal(cfg.database, "my db");
37
- assert.equal(cfg.host, "local host");
38
- });
39
-
40
- test("buildInitPlan includes create user when role does not exist", async () => {
41
- const plan = await init.buildInitPlan({
42
- database: "mydb",
43
- monitoringUser: "postgres_ai_mon",
44
- monitoringPassword: "pw",
45
- includeOptionalPermissions: false,
46
- roleExists: false,
47
- });
48
-
49
- assert.equal(plan.database, "mydb");
50
- const roleStep = plan.steps.find((s) => s.name === "01.role");
51
- assert.ok(roleStep);
52
- assert.match(roleStep.sql, /create\s+user/i);
53
- assert.ok(!plan.steps.some((s) => s.optional));
54
- });
55
-
56
- test("buildInitPlan includes role step when roleExists is omitted", async () => {
57
- const plan = await init.buildInitPlan({
58
- database: "mydb",
59
- monitoringUser: "postgres_ai_mon",
60
- monitoringPassword: "pw",
61
- includeOptionalPermissions: false,
62
- });
63
- const roleStep = plan.steps.find((s) => s.name === "01.role");
64
- assert.ok(roleStep);
65
- assert.match(roleStep.sql, /do\s+\$\$/i);
66
- });
67
-
68
- test("buildInitPlan inlines password safely for CREATE/ALTER ROLE grammar", async () => {
69
- const plan = await init.buildInitPlan({
70
- database: "mydb",
71
- monitoringUser: "postgres_ai_mon",
72
- monitoringPassword: "pa'ss",
73
- includeOptionalPermissions: false,
74
- roleExists: false,
75
- });
76
- const step = plan.steps.find((s) => s.name === "01.role");
77
- assert.ok(step);
78
- assert.match(step.sql, /password 'pa''ss'/);
79
- assert.equal(step.params, undefined);
80
- });
81
-
82
- test("buildInitPlan includes alter user when role exists", async () => {
83
- const plan = await init.buildInitPlan({
84
- database: "mydb",
85
- monitoringUser: "postgres_ai_mon",
86
- monitoringPassword: "pw",
87
- includeOptionalPermissions: true,
88
- roleExists: true,
89
- });
90
-
91
- const roleStep = plan.steps.find((s) => s.name === "01.role");
92
- assert.ok(roleStep);
93
- assert.match(roleStep.sql, /alter\s+user/i);
94
- assert.ok(plan.steps.some((s) => s.optional));
95
- });
96
-
97
- test("resolveAdminConnection accepts positional URI", () => {
98
- const r = init.resolveAdminConnection({ conn: "postgresql://u:p@h:5432/d" });
99
- assert.ok(r.clientConfig.connectionString);
100
- assert.doesNotMatch(r.display, /:p@/);
101
- });
102
-
103
- test("resolveAdminConnection accepts positional conninfo", () => {
104
- const r = init.resolveAdminConnection({ conn: "dbname=mydb host=localhost user=alice" });
105
- assert.equal(r.clientConfig.database, "mydb");
106
- assert.equal(r.clientConfig.host, "localhost");
107
- assert.equal(r.clientConfig.user, "alice");
108
- });
109
-
110
- test("resolveAdminConnection rejects invalid psql-like port", () => {
111
- assert.throws(
112
- () => init.resolveAdminConnection({ host: "localhost", port: "abc", username: "u", dbname: "d" }),
113
- /Invalid port value/
114
- );
115
- });
116
-
117
- test("resolveAdminConnection rejects when only PGPASSWORD is provided (no connection details)", () => {
118
- assert.throws(() => init.resolveAdminConnection({ envPassword: "pw" }), /Connection is required/);
119
- });
120
-
121
- test("resolveAdminConnection error message includes examples", () => {
122
- assert.throws(() => init.resolveAdminConnection({}), /Examples:/);
123
- });
124
-
125
- test("cli: init with missing connection prints init help/options", () => {
126
- const r = runCli(["init"]);
127
- assert.notEqual(r.status, 0);
128
- // We should show options, not just the error message.
129
- assert.match(r.stderr, /--print-sql/);
130
- assert.match(r.stderr, /--monitoring-user/);
131
- });
132
-
133
- test("print-sql redaction regex matches password literal with embedded quotes", async () => {
134
- const plan = await init.buildInitPlan({
135
- database: "mydb",
136
- monitoringUser: "postgres_ai_mon",
137
- monitoringPassword: "pa'ss",
138
- includeOptionalPermissions: false,
139
- roleExists: false,
140
- });
141
- const step = plan.steps.find((s) => s.name === "01.role");
142
- assert.ok(step);
143
- const redacted = step.sql.replace(/password\s+'(?:''|[^'])*'/gi, "password '<redacted>'");
144
- assert.match(redacted, /password '<redacted>'/i);
145
- });
146
-
147
- test("cli: init --print-sql works without connection (offline mode)", () => {
148
- const r = runCli(["init", "--print-sql", "-d", "mydb", "--password", "monpw"]);
149
- assert.equal(r.status, 0, r.stderr || r.stdout);
150
- assert.match(r.stdout, /SQL plan \(offline; not connected\)/);
151
- assert.match(r.stdout, /grant connect on database "mydb" to "postgres_ai_mon"/i);
152
- });
153
-
154
-