intellitester 0.1.12

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 (89) hide show
  1. package/README.md +200 -0
  2. package/dist/chunk-35WJGNDA.cjs +136 -0
  3. package/dist/chunk-35WJGNDA.cjs.map +1 -0
  4. package/dist/chunk-4B54JUOP.js +234 -0
  5. package/dist/chunk-4B54JUOP.js.map +1 -0
  6. package/dist/chunk-5LFSLMQ7.js +2517 -0
  7. package/dist/chunk-5LFSLMQ7.js.map +1 -0
  8. package/dist/chunk-6PYKWWH5.js +63 -0
  9. package/dist/chunk-6PYKWWH5.js.map +1 -0
  10. package/dist/chunk-ARJYJVRM.cjs +302 -0
  11. package/dist/chunk-ARJYJVRM.cjs.map +1 -0
  12. package/dist/chunk-CN6HSJJX.js +133 -0
  13. package/dist/chunk-CN6HSJJX.js.map +1 -0
  14. package/dist/chunk-DE5UFTTG.js +31 -0
  15. package/dist/chunk-DE5UFTTG.js.map +1 -0
  16. package/dist/chunk-ECBA4GJ3.js +287 -0
  17. package/dist/chunk-ECBA4GJ3.js.map +1 -0
  18. package/dist/chunk-OFXNJXMV.cjs +237 -0
  19. package/dist/chunk-OFXNJXMV.cjs.map +1 -0
  20. package/dist/chunk-PAKODOH4.cjs +66 -0
  21. package/dist/chunk-PAKODOH4.cjs.map +1 -0
  22. package/dist/chunk-QMYM2TCH.cjs +36 -0
  23. package/dist/chunk-QMYM2TCH.cjs.map +1 -0
  24. package/dist/chunk-SAVY6D3X.js +125 -0
  25. package/dist/chunk-SAVY6D3X.js.map +1 -0
  26. package/dist/chunk-UUJXCHVT.cjs +128 -0
  27. package/dist/chunk-UUJXCHVT.cjs.map +1 -0
  28. package/dist/chunk-XWGUA67E.cjs +2552 -0
  29. package/dist/chunk-XWGUA67E.cjs.map +1 -0
  30. package/dist/cli/index.cjs +1985 -0
  31. package/dist/cli/index.cjs.map +1 -0
  32. package/dist/cli/index.d.cts +1 -0
  33. package/dist/cli/index.d.ts +1 -0
  34. package/dist/cli/index.js +1957 -0
  35. package/dist/cli/index.js.map +1 -0
  36. package/dist/core/cleanup/index.cjs +45 -0
  37. package/dist/core/cleanup/index.cjs.map +1 -0
  38. package/dist/core/cleanup/index.d.cts +117 -0
  39. package/dist/core/cleanup/index.d.ts +117 -0
  40. package/dist/core/cleanup/index.js +8 -0
  41. package/dist/core/cleanup/index.js.map +1 -0
  42. package/dist/index.cjs +110 -0
  43. package/dist/index.cjs.map +1 -0
  44. package/dist/index.d.cts +852 -0
  45. package/dist/index.d.ts +852 -0
  46. package/dist/index.js +9 -0
  47. package/dist/index.js.map +1 -0
  48. package/dist/integration/index.cjs +22 -0
  49. package/dist/integration/index.cjs.map +1 -0
  50. package/dist/integration/index.d.cts +42 -0
  51. package/dist/integration/index.d.ts +42 -0
  52. package/dist/integration/index.js +20 -0
  53. package/dist/integration/index.js.map +1 -0
  54. package/dist/providers/appwrite/index.cjs +16 -0
  55. package/dist/providers/appwrite/index.cjs.map +1 -0
  56. package/dist/providers/appwrite/index.d.cts +12 -0
  57. package/dist/providers/appwrite/index.d.ts +12 -0
  58. package/dist/providers/appwrite/index.js +3 -0
  59. package/dist/providers/appwrite/index.js.map +1 -0
  60. package/dist/providers/index.cjs +60 -0
  61. package/dist/providers/index.cjs.map +1 -0
  62. package/dist/providers/index.d.cts +13 -0
  63. package/dist/providers/index.d.ts +13 -0
  64. package/dist/providers/index.js +7 -0
  65. package/dist/providers/index.js.map +1 -0
  66. package/dist/providers/mysql/index.cjs +16 -0
  67. package/dist/providers/mysql/index.cjs.map +1 -0
  68. package/dist/providers/mysql/index.d.cts +14 -0
  69. package/dist/providers/mysql/index.d.ts +14 -0
  70. package/dist/providers/mysql/index.js +3 -0
  71. package/dist/providers/mysql/index.js.map +1 -0
  72. package/dist/providers/postgres/index.cjs +16 -0
  73. package/dist/providers/postgres/index.cjs.map +1 -0
  74. package/dist/providers/postgres/index.d.cts +10 -0
  75. package/dist/providers/postgres/index.d.ts +10 -0
  76. package/dist/providers/postgres/index.js +3 -0
  77. package/dist/providers/postgres/index.js.map +1 -0
  78. package/dist/providers/sqlite/index.cjs +16 -0
  79. package/dist/providers/sqlite/index.cjs.map +1 -0
  80. package/dist/providers/sqlite/index.d.cts +11 -0
  81. package/dist/providers/sqlite/index.d.ts +11 -0
  82. package/dist/providers/sqlite/index.js +3 -0
  83. package/dist/providers/sqlite/index.js.map +1 -0
  84. package/dist/types-LONNVTIF.d.cts +56 -0
  85. package/dist/types-l-ZaFKC-.d.ts +56 -0
  86. package/package.json +114 -0
  87. package/schemas/intellitester.config.schema.json +384 -0
  88. package/schemas/test.schema.json +517 -0
  89. package/schemas/workflow.schema.json +227 -0
@@ -0,0 +1,66 @@
1
+ 'use strict';
2
+
3
+ // src/providers/sqlite/index.ts
4
+ function createSqliteProvider(config) {
5
+ let db = null;
6
+ const methods = {
7
+ deleteRow: async (resource) => {
8
+ if (!db) {
9
+ throw new Error("SQLite database not initialized. Call configure() first.");
10
+ }
11
+ const table = resource.table;
12
+ if (!table) {
13
+ throw new Error(`Missing table name for row ${resource.id}`);
14
+ }
15
+ const stmt = db.prepare(`DELETE FROM ${table} WHERE id = ?`);
16
+ stmt.run(resource.id);
17
+ },
18
+ deleteUser: async (resource) => {
19
+ if (!db) {
20
+ throw new Error("SQLite database not initialized. Call configure() first.");
21
+ }
22
+ const table = resource.table || "users";
23
+ const stmt = db.prepare(`DELETE FROM ${table} WHERE id = ?`);
24
+ stmt.run(resource.id);
25
+ },
26
+ customDelete: async (resource) => {
27
+ if (!db) {
28
+ throw new Error("SQLite database not initialized. Call configure() first.");
29
+ }
30
+ const query = resource.query;
31
+ const params = resource.params || [resource.id];
32
+ if (!query) {
33
+ throw new Error(`Missing query for custom delete of resource ${resource.id}`);
34
+ }
35
+ const stmt = db.prepare(query);
36
+ stmt.run(...params);
37
+ }
38
+ };
39
+ return {
40
+ name: "sqlite",
41
+ async configure() {
42
+ try {
43
+ const DatabaseModule = await import('better-sqlite3');
44
+ const Database = DatabaseModule.default || DatabaseModule;
45
+ db = new Database(config.database, {
46
+ readonly: config.readonly || false
47
+ });
48
+ } catch {
49
+ throw new Error(
50
+ 'Failed to initialize SQLite database. Make sure the "better-sqlite3" package is installed: npm install better-sqlite3'
51
+ );
52
+ }
53
+ },
54
+ methods
55
+ };
56
+ }
57
+ var sqliteTypeMappings = {
58
+ row: "sqlite.deleteRow",
59
+ user: "sqlite.deleteUser",
60
+ custom: "sqlite.customDelete"
61
+ };
62
+
63
+ exports.createSqliteProvider = createSqliteProvider;
64
+ exports.sqliteTypeMappings = sqliteTypeMappings;
65
+ //# sourceMappingURL=chunk-PAKODOH4.cjs.map
66
+ //# sourceMappingURL=chunk-PAKODOH4.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/sqlite/index.ts"],"names":[],"mappings":";;;AAQO,SAAS,qBAAqB,MAAA,EAAuC;AAE1E,EAAA,IAAI,EAAA,GAAU,IAAA;AAEd,EAAA,MAAM,OAAA,GAA0C;AAAA,IAC9C,SAAA,EAAW,OAAO,QAAA,KAA8B;AAC9C,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,MAC5E;AAEA,MAAA,MAAM,QAAQ,QAAA,CAAS,KAAA;AAEvB,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,2BAAA,EAA8B,QAAA,CAAS,EAAE,CAAA,CAAE,CAAA;AAAA,MAC7D;AAGA,MAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,CAAA,YAAA,EAAe,KAAK,CAAA,aAAA,CAAe,CAAA;AAC3D,MAAA,IAAA,CAAK,GAAA,CAAI,SAAS,EAAE,CAAA;AAAA,IACtB,CAAA;AAAA,IAEA,UAAA,EAAY,OAAO,QAAA,KAA8B;AAC/C,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,MAC5E;AAEA,MAAA,MAAM,KAAA,GAAS,SAAS,KAAA,IAAoB,OAAA;AAE5C,MAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,CAAA,YAAA,EAAe,KAAK,CAAA,aAAA,CAAe,CAAA;AAC3D,MAAA,IAAA,CAAK,GAAA,CAAI,SAAS,EAAE,CAAA;AAAA,IACtB,CAAA;AAAA,IAEA,YAAA,EAAc,OAAO,QAAA,KAA8B;AACjD,MAAA,IAAI,CAAC,EAAA,EAAI;AACP,QAAA,MAAM,IAAI,MAAM,0DAA0D,CAAA;AAAA,MAC5E;AAGA,MAAA,MAAM,QAAQ,QAAA,CAAS,KAAA;AACvB,MAAA,MAAM,MAAA,GAAU,QAAA,CAAS,MAAA,IAAoB,CAAC,SAAS,EAAE,CAAA;AAEzD,MAAA,IAAI,CAAC,KAAA,EAAO;AACV,QAAA,MAAM,IAAI,KAAA,CAAM,CAAA,4CAAA,EAA+C,QAAA,CAAS,EAAE,CAAA,CAAE,CAAA;AAAA,MAC9E;AAEA,MAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,KAAK,CAAA;AAC7B,MAAA,IAAA,CAAK,GAAA,CAAI,GAAG,MAAM,CAAA;AAAA,IACpB;AAAA,GACF;AAEA,EAAA,OAAO;AAAA,IACL,IAAA,EAAM,QAAA;AAAA,IACN,MAAM,SAAA,GAAY;AAChB,MAAA,IAAI;AAGF,QAAA,MAAM,cAAA,GAAiB,MAAM,OAAO,gBAAgB,CAAA;AACpD,QAAA,MAAM,QAAA,GAAW,eAAe,OAAA,IAAW,cAAA;AAC3C,QAAA,EAAA,GAAK,IAAI,QAAA,CAAS,MAAA,CAAO,QAAA,EAAU;AAAA,UACjC,QAAA,EAAU,OAAO,QAAA,IAAY;AAAA,SAC9B,CAAA;AAAA,MACH,CAAA,CAAA,MAAQ;AACN,QAAA,MAAM,IAAI,KAAA;AAAA,UACR;AAAA,SACF;AAAA,MACF;AAAA,IACF,CAAA;AAAA,IACA;AAAA,GACF;AACF;AAGO,IAAM,kBAAA,GAA6C;AAAA,EACxD,GAAA,EAAK,kBAAA;AAAA,EACL,IAAA,EAAM,mBAAA;AAAA,EACN,MAAA,EAAQ;AACV","file":"chunk-PAKODOH4.cjs","sourcesContent":["import type { CleanupProvider, CleanupHandler } from '../../core/cleanup/types.js';\nimport type { TrackedResource } from '../../integration/index.js';\n\ninterface SqliteConfig {\n database: string; // Path to the SQLite database file\n readonly?: boolean;\n}\n\nexport function createSqliteProvider(config: SqliteConfig): CleanupProvider {\n // Database will be lazily initialized in configure()\n let db: any = null;\n\n const methods: Record<string, CleanupHandler> = {\n deleteRow: async (resource: TrackedResource) => {\n if (!db) {\n throw new Error('SQLite database not initialized. Call configure() first.');\n }\n\n const table = resource.table as string;\n\n if (!table) {\n throw new Error(`Missing table name for row ${resource.id}`);\n }\n\n // Use parameterized query to prevent SQL injection\n const stmt = db.prepare(`DELETE FROM ${table} WHERE id = ?`);\n stmt.run(resource.id);\n },\n\n deleteUser: async (resource: TrackedResource) => {\n if (!db) {\n throw new Error('SQLite database not initialized. Call configure() first.');\n }\n\n const table = (resource.table as string) || 'users';\n\n const stmt = db.prepare(`DELETE FROM ${table} WHERE id = ?`);\n stmt.run(resource.id);\n },\n\n customDelete: async (resource: TrackedResource) => {\n if (!db) {\n throw new Error('SQLite database not initialized. Call configure() first.');\n }\n\n // Allow custom SQL queries via the query property\n const query = resource.query as string;\n const params = (resource.params as any[]) || [resource.id];\n\n if (!query) {\n throw new Error(`Missing query for custom delete of resource ${resource.id}`);\n }\n\n const stmt = db.prepare(query);\n stmt.run(...params);\n },\n };\n\n return {\n name: 'sqlite',\n async configure() {\n try {\n // Dynamic import since better-sqlite3 is an optional dependency\n // @ts-expect-error - better-sqlite3 is an optional peer dependency\n const DatabaseModule = await import('better-sqlite3');\n const Database = DatabaseModule.default || DatabaseModule;\n db = new Database(config.database, {\n readonly: config.readonly || false,\n });\n } catch {\n throw new Error(\n 'Failed to initialize SQLite database. Make sure the \"better-sqlite3\" package is installed: npm install better-sqlite3'\n );\n }\n },\n methods,\n };\n}\n\n// Default type mappings for SQLite resources\nexport const sqliteTypeMappings: Record<string, string> = {\n row: 'sqlite.deleteRow',\n user: 'sqlite.deleteUser',\n custom: 'sqlite.customDelete',\n};\n"]}
@@ -0,0 +1,36 @@
1
+ 'use strict';
2
+
3
+ var chunkPAKODOH4_cjs = require('./chunk-PAKODOH4.cjs');
4
+ var chunkOFXNJXMV_cjs = require('./chunk-OFXNJXMV.cjs');
5
+ var chunkUUJXCHVT_cjs = require('./chunk-UUJXCHVT.cjs');
6
+ var chunk35WJGNDA_cjs = require('./chunk-35WJGNDA.cjs');
7
+
8
+ // src/providers/index.ts
9
+ var providerFactories = {
10
+ appwrite: (config) => chunkOFXNJXMV_cjs.createAppwriteProvider(config),
11
+ postgres: (config) => chunkUUJXCHVT_cjs.createPostgresProvider(config),
12
+ mysql: (config) => chunk35WJGNDA_cjs.createMysqlProvider(config),
13
+ sqlite: (config) => chunkPAKODOH4_cjs.createSqliteProvider(config)
14
+ };
15
+ var typeMappingsRegistry = {
16
+ appwrite: chunkOFXNJXMV_cjs.appwriteTypeMappings,
17
+ postgres: chunkUUJXCHVT_cjs.postgresTypeMappings,
18
+ mysql: chunk35WJGNDA_cjs.mysqlTypeMappings,
19
+ sqlite: chunkPAKODOH4_cjs.sqliteTypeMappings
20
+ };
21
+ function getDefaultTypeMappings(provider) {
22
+ return typeMappingsRegistry[provider] ?? {};
23
+ }
24
+ function isProviderAvailable(provider) {
25
+ return provider in providerFactories;
26
+ }
27
+ function listAvailableProviders() {
28
+ return Object.keys(providerFactories);
29
+ }
30
+
31
+ exports.getDefaultTypeMappings = getDefaultTypeMappings;
32
+ exports.isProviderAvailable = isProviderAvailable;
33
+ exports.listAvailableProviders = listAvailableProviders;
34
+ exports.providerFactories = providerFactories;
35
+ //# sourceMappingURL=chunk-QMYM2TCH.cjs.map
36
+ //# sourceMappingURL=chunk-QMYM2TCH.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/index.ts"],"names":["createAppwriteProvider","createPostgresProvider","createMysqlProvider","createSqliteProvider","appwriteTypeMappings","postgresTypeMappings","mysqlTypeMappings","sqliteTypeMappings"],"mappings":";;;;;;;;AAaO,IAAM,iBAAA,GAAsE;AAAA,EACjF,QAAA,EAAU,CAAC,MAAA,KAAWA,wCAAA,CAAuB,MAAM,CAAA;AAAA,EACnD,QAAA,EAAU,CAAC,MAAA,KAAWC,wCAAA,CAAuB,MAAM,CAAA;AAAA,EACnD,KAAA,EAAO,CAAC,MAAA,KAAWC,qCAAA,CAAoB,MAAM,CAAA;AAAA,EAC7C,MAAA,EAAQ,CAAC,MAAA,KAAWC,sCAAA,CAAqB,MAAM;AACjD;AAGA,IAAM,oBAAA,GAA+D;AAAA,EACnE,QAAA,EAAUC,sCAAA;AAAA,EACV,QAAA,EAAUC,sCAAA;AAAA,EACV,KAAA,EAAOC,mCAAA;AAAA,EACP,MAAA,EAAQC;AACV,CAAA;AAGO,SAAS,uBAAuB,QAAA,EAA0C;AAC/E,EAAA,OAAO,oBAAA,CAAqB,QAAQ,CAAA,IAAK,EAAC;AAC5C;AAGO,SAAS,oBAAoB,QAAA,EAA2B;AAC7D,EAAA,OAAO,QAAA,IAAY,iBAAA;AACrB;AAGO,SAAS,sBAAA,GAAmC;AACjD,EAAA,OAAO,MAAA,CAAO,KAAK,iBAAiB,CAAA;AACtC","file":"chunk-QMYM2TCH.cjs","sourcesContent":["import { createAppwriteProvider, appwriteTypeMappings } from './appwrite/index.js';\nimport { createPostgresProvider, postgresTypeMappings } from './postgres/index.js';\nimport { createMysqlProvider, mysqlTypeMappings } from './mysql/index.js';\nimport { createSqliteProvider, sqliteTypeMappings } from './sqlite/index.js';\nimport type { CleanupProvider } from '../core/cleanup/types.js';\n\n// Re-export for convenience\nexport { createAppwriteProvider, appwriteTypeMappings } from './appwrite/index.js';\nexport { createPostgresProvider, postgresTypeMappings } from './postgres/index.js';\nexport { createMysqlProvider, mysqlTypeMappings } from './mysql/index.js';\nexport { createSqliteProvider, sqliteTypeMappings } from './sqlite/index.js';\n\n// Provider factory registry using static imports\nexport const providerFactories: Record<string, (config: any) => CleanupProvider> = {\n appwrite: (config) => createAppwriteProvider(config),\n postgres: (config) => createPostgresProvider(config),\n mysql: (config) => createMysqlProvider(config),\n sqlite: (config) => createSqliteProvider(config),\n};\n\n// Default type mappings for each provider\nconst typeMappingsRegistry: Record<string, Record<string, string>> = {\n appwrite: appwriteTypeMappings,\n postgres: postgresTypeMappings,\n mysql: mysqlTypeMappings,\n sqlite: sqliteTypeMappings,\n};\n\n// Get default type mappings for a provider\nexport function getDefaultTypeMappings(provider: string): Record<string, string> {\n return typeMappingsRegistry[provider] ?? {};\n}\n\n// Helper to check if a provider is available\nexport function isProviderAvailable(provider: string): boolean {\n return provider in providerFactories;\n}\n\n// Helper to list all available providers\nexport function listAvailableProviders(): string[] {\n return Object.keys(providerFactories);\n}\n"]}
@@ -0,0 +1,125 @@
1
+ // src/providers/postgres/index.ts
2
+ function createPostgresProvider(config) {
3
+ let client = null;
4
+ const methods = {
5
+ deleteRow: async (resource) => {
6
+ if (!client) {
7
+ throw new Error("Postgres client not initialized. Call configure() first.");
8
+ }
9
+ const schema = resource.schema || "public";
10
+ const table = resource.table;
11
+ if (!table) {
12
+ throw new Error(`Missing table name for row ${resource.id}`);
13
+ }
14
+ await client.query(
15
+ `DELETE FROM "${schema}"."${table}" WHERE id = $1`,
16
+ [resource.id]
17
+ );
18
+ },
19
+ deleteUser: async (resource) => {
20
+ if (!client) {
21
+ throw new Error("Postgres client not initialized. Call configure() first.");
22
+ }
23
+ const table = resource.table || "users";
24
+ const schema = resource.schema || "public";
25
+ await client.query(
26
+ `DELETE FROM "${schema}"."${table}" WHERE id = $1`,
27
+ [resource.id]
28
+ );
29
+ },
30
+ customDelete: async (resource) => {
31
+ if (!client) {
32
+ throw new Error("Postgres client not initialized. Call configure() first.");
33
+ }
34
+ const query = resource.query;
35
+ const params = resource.params || [resource.id];
36
+ if (!query) {
37
+ throw new Error(`Missing query for custom delete of resource ${resource.id}`);
38
+ }
39
+ await client.query(query, params);
40
+ }
41
+ };
42
+ async function cleanupUntracked(options) {
43
+ if (!client) {
44
+ throw new Error("Postgres client not initialized. Call configure() first.");
45
+ }
46
+ const { testStartTime, userId } = options;
47
+ const deleted = [];
48
+ const failed = [];
49
+ let scanned = 0;
50
+ const tablesResult = await client.query(`
51
+ SELECT table_name
52
+ FROM information_schema.tables
53
+ WHERE table_schema = 'public'
54
+ AND table_type = 'BASE TABLE'
55
+ AND table_name NOT LIKE '_intellitester%'
56
+ `);
57
+ for (const row of tablesResult.rows) {
58
+ const tableName = row.table_name;
59
+ scanned++;
60
+ const columnsResult = await client.query(`
61
+ SELECT column_name
62
+ FROM information_schema.columns
63
+ WHERE table_name = $1
64
+ `, [tableName]);
65
+ const columns = columnsResult.rows.map((r) => r.column_name);
66
+ const hasCreatedAt = columns.some((c) => ["created_at", "createdat", "created"].includes(c.toLowerCase()));
67
+ const userIdColumn = columns.find((c) => ["user_id", "userid", "owner_id", "author_id"].includes(c.toLowerCase()));
68
+ if (!hasCreatedAt) continue;
69
+ let deleteQuery = `DELETE FROM "${tableName}" WHERE `;
70
+ const conditions = [];
71
+ const params = [];
72
+ const createdAtCol = columns.find((c) => ["created_at", "createdat", "created"].includes(c.toLowerCase()));
73
+ if (createdAtCol) {
74
+ conditions.push(`"${createdAtCol}" >= $${params.length + 1}`);
75
+ params.push(testStartTime);
76
+ }
77
+ if (userId && userIdColumn) {
78
+ conditions.push(`"${userIdColumn}" = $${params.length + 1}`);
79
+ params.push(userId);
80
+ }
81
+ if (conditions.length === 0) continue;
82
+ deleteQuery += conditions.join(" AND ") + " RETURNING id";
83
+ try {
84
+ const result = await client.query(deleteQuery, params);
85
+ for (const deletedRow of result.rows) {
86
+ deleted.push(`${tableName}:${deletedRow.id}`);
87
+ }
88
+ } catch {
89
+ failed.push(`${tableName}:error`);
90
+ }
91
+ }
92
+ return {
93
+ success: failed.length === 0,
94
+ scanned,
95
+ deleted,
96
+ failed
97
+ };
98
+ }
99
+ return {
100
+ name: "postgres",
101
+ async configure() {
102
+ try {
103
+ const pg = await import('pg');
104
+ const Client = pg.Client || pg.default?.Client;
105
+ client = new Client({ connectionString: config.connectionString });
106
+ await client.connect();
107
+ } catch {
108
+ throw new Error(
109
+ 'Failed to initialize Postgres client. Make sure the "pg" package is installed: npm install pg'
110
+ );
111
+ }
112
+ },
113
+ methods,
114
+ cleanupUntracked
115
+ };
116
+ }
117
+ var postgresTypeMappings = {
118
+ row: "postgres.deleteRow",
119
+ user: "postgres.deleteUser",
120
+ custom: "postgres.customDelete"
121
+ };
122
+
123
+ export { createPostgresProvider, postgresTypeMappings };
124
+ //# sourceMappingURL=chunk-SAVY6D3X.js.map
125
+ //# sourceMappingURL=chunk-SAVY6D3X.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/postgres/index.ts"],"names":[],"mappings":"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","file":"chunk-SAVY6D3X.js","sourcesContent":["import type { CleanupProvider, CleanupHandler, CleanupUntrackedOptions, CleanupUntrackedResult } from '../../core/cleanup/types.js';\nimport type { TrackedResource } from '../../integration/index.js';\n\ninterface PostgresConfig {\n connectionString: string;\n}\n\nexport function createPostgresProvider(config: PostgresConfig): CleanupProvider {\n // Client will be lazily initialized in configure()\n let client: any = null;\n\n const methods: Record<string, CleanupHandler> = {\n deleteRow: async (resource: TrackedResource) => {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n const schema = (resource.schema as string) || 'public';\n const table = resource.table as string;\n\n if (!table) {\n throw new Error(`Missing table name for row ${resource.id}`);\n }\n\n // Use parameterized query to prevent SQL injection\n await client.query(\n `DELETE FROM \"${schema}\".\"${table}\" WHERE id = $1`,\n [resource.id]\n );\n },\n\n deleteUser: async (resource: TrackedResource) => {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n const table = (resource.table as string) || 'users';\n const schema = (resource.schema as string) || 'public';\n\n await client.query(\n `DELETE FROM \"${schema}\".\"${table}\" WHERE id = $1`,\n [resource.id]\n );\n },\n\n customDelete: async (resource: TrackedResource) => {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n // Allow custom SQL queries via the query property\n const query = resource.query as string;\n const params = (resource.params as any[]) || [resource.id];\n\n if (!query) {\n throw new Error(`Missing query for custom delete of resource ${resource.id}`);\n }\n\n await client.query(query, params);\n },\n };\n\n async function cleanupUntracked(options: CleanupUntrackedOptions): Promise<CleanupUntrackedResult> {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n const { testStartTime, userId } = options;\n const deleted: string[] = [];\n const failed: string[] = [];\n let scanned = 0;\n\n // 1. Get all tables in public schema\n const tablesResult = await client.query(`\n SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type = 'BASE TABLE'\n AND table_name NOT LIKE '_intellitester%'\n `);\n\n for (const row of tablesResult.rows) {\n const tableName = row.table_name;\n scanned++;\n\n // 2. Check if table has created_at and user_id columns\n const columnsResult = await client.query(`\n SELECT column_name\n FROM information_schema.columns\n WHERE table_name = $1\n `, [tableName]);\n\n const columns: string[] = columnsResult.rows.map((r: { column_name: string }) => r.column_name);\n const hasCreatedAt = columns.some(c => ['created_at', 'createdat', 'created'].includes(c.toLowerCase()));\n const userIdColumn = columns.find(c => ['user_id', 'userid', 'owner_id', 'author_id'].includes(c.toLowerCase()));\n\n if (!hasCreatedAt) continue;\n\n // 3. Build and execute delete query\n let deleteQuery = `DELETE FROM \"${tableName}\" WHERE `;\n const conditions: string[] = [];\n const params: (string | undefined)[] = [];\n\n // Add created_at condition\n const createdAtCol = columns.find(c => ['created_at', 'createdat', 'created'].includes(c.toLowerCase()));\n if (createdAtCol) {\n conditions.push(`\"${createdAtCol}\" >= $${params.length + 1}`);\n params.push(testStartTime);\n }\n\n // Add user_id condition if available\n if (userId && userIdColumn) {\n conditions.push(`\"${userIdColumn}\" = $${params.length + 1}`);\n params.push(userId);\n }\n\n if (conditions.length === 0) continue;\n\n deleteQuery += conditions.join(' AND ') + ' RETURNING id';\n\n try {\n const result = await client.query(deleteQuery, params);\n for (const deletedRow of result.rows) {\n deleted.push(`${tableName}:${deletedRow.id}`);\n }\n } catch {\n failed.push(`${tableName}:error`);\n }\n }\n\n return {\n success: failed.length === 0,\n scanned,\n deleted,\n failed,\n };\n }\n\n return {\n name: 'postgres',\n async configure() {\n try {\n // Dynamic import since pg is an optional dependency\n // @ts-expect-error - pg is an optional peer dependency\n const pg = await import('pg');\n const Client = pg.Client || pg.default?.Client;\n client = new Client({ connectionString: config.connectionString });\n await client.connect();\n } catch {\n throw new Error(\n 'Failed to initialize Postgres client. Make sure the \"pg\" package is installed: npm install pg'\n );\n }\n },\n methods,\n cleanupUntracked,\n };\n}\n\n// Default type mappings for Postgres resources\nexport const postgresTypeMappings: Record<string, string> = {\n row: 'postgres.deleteRow',\n user: 'postgres.deleteUser',\n custom: 'postgres.customDelete',\n};\n"]}
@@ -0,0 +1,128 @@
1
+ 'use strict';
2
+
3
+ // src/providers/postgres/index.ts
4
+ function createPostgresProvider(config) {
5
+ let client = null;
6
+ const methods = {
7
+ deleteRow: async (resource) => {
8
+ if (!client) {
9
+ throw new Error("Postgres client not initialized. Call configure() first.");
10
+ }
11
+ const schema = resource.schema || "public";
12
+ const table = resource.table;
13
+ if (!table) {
14
+ throw new Error(`Missing table name for row ${resource.id}`);
15
+ }
16
+ await client.query(
17
+ `DELETE FROM "${schema}"."${table}" WHERE id = $1`,
18
+ [resource.id]
19
+ );
20
+ },
21
+ deleteUser: async (resource) => {
22
+ if (!client) {
23
+ throw new Error("Postgres client not initialized. Call configure() first.");
24
+ }
25
+ const table = resource.table || "users";
26
+ const schema = resource.schema || "public";
27
+ await client.query(
28
+ `DELETE FROM "${schema}"."${table}" WHERE id = $1`,
29
+ [resource.id]
30
+ );
31
+ },
32
+ customDelete: async (resource) => {
33
+ if (!client) {
34
+ throw new Error("Postgres client not initialized. Call configure() first.");
35
+ }
36
+ const query = resource.query;
37
+ const params = resource.params || [resource.id];
38
+ if (!query) {
39
+ throw new Error(`Missing query for custom delete of resource ${resource.id}`);
40
+ }
41
+ await client.query(query, params);
42
+ }
43
+ };
44
+ async function cleanupUntracked(options) {
45
+ if (!client) {
46
+ throw new Error("Postgres client not initialized. Call configure() first.");
47
+ }
48
+ const { testStartTime, userId } = options;
49
+ const deleted = [];
50
+ const failed = [];
51
+ let scanned = 0;
52
+ const tablesResult = await client.query(`
53
+ SELECT table_name
54
+ FROM information_schema.tables
55
+ WHERE table_schema = 'public'
56
+ AND table_type = 'BASE TABLE'
57
+ AND table_name NOT LIKE '_intellitester%'
58
+ `);
59
+ for (const row of tablesResult.rows) {
60
+ const tableName = row.table_name;
61
+ scanned++;
62
+ const columnsResult = await client.query(`
63
+ SELECT column_name
64
+ FROM information_schema.columns
65
+ WHERE table_name = $1
66
+ `, [tableName]);
67
+ const columns = columnsResult.rows.map((r) => r.column_name);
68
+ const hasCreatedAt = columns.some((c) => ["created_at", "createdat", "created"].includes(c.toLowerCase()));
69
+ const userIdColumn = columns.find((c) => ["user_id", "userid", "owner_id", "author_id"].includes(c.toLowerCase()));
70
+ if (!hasCreatedAt) continue;
71
+ let deleteQuery = `DELETE FROM "${tableName}" WHERE `;
72
+ const conditions = [];
73
+ const params = [];
74
+ const createdAtCol = columns.find((c) => ["created_at", "createdat", "created"].includes(c.toLowerCase()));
75
+ if (createdAtCol) {
76
+ conditions.push(`"${createdAtCol}" >= $${params.length + 1}`);
77
+ params.push(testStartTime);
78
+ }
79
+ if (userId && userIdColumn) {
80
+ conditions.push(`"${userIdColumn}" = $${params.length + 1}`);
81
+ params.push(userId);
82
+ }
83
+ if (conditions.length === 0) continue;
84
+ deleteQuery += conditions.join(" AND ") + " RETURNING id";
85
+ try {
86
+ const result = await client.query(deleteQuery, params);
87
+ for (const deletedRow of result.rows) {
88
+ deleted.push(`${tableName}:${deletedRow.id}`);
89
+ }
90
+ } catch {
91
+ failed.push(`${tableName}:error`);
92
+ }
93
+ }
94
+ return {
95
+ success: failed.length === 0,
96
+ scanned,
97
+ deleted,
98
+ failed
99
+ };
100
+ }
101
+ return {
102
+ name: "postgres",
103
+ async configure() {
104
+ try {
105
+ const pg = await import('pg');
106
+ const Client = pg.Client || pg.default?.Client;
107
+ client = new Client({ connectionString: config.connectionString });
108
+ await client.connect();
109
+ } catch {
110
+ throw new Error(
111
+ 'Failed to initialize Postgres client. Make sure the "pg" package is installed: npm install pg'
112
+ );
113
+ }
114
+ },
115
+ methods,
116
+ cleanupUntracked
117
+ };
118
+ }
119
+ var postgresTypeMappings = {
120
+ row: "postgres.deleteRow",
121
+ user: "postgres.deleteUser",
122
+ custom: "postgres.customDelete"
123
+ };
124
+
125
+ exports.createPostgresProvider = createPostgresProvider;
126
+ exports.postgresTypeMappings = postgresTypeMappings;
127
+ //# sourceMappingURL=chunk-UUJXCHVT.cjs.map
128
+ //# sourceMappingURL=chunk-UUJXCHVT.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/providers/postgres/index.ts"],"names":[],"mappings":"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","file":"chunk-UUJXCHVT.cjs","sourcesContent":["import type { CleanupProvider, CleanupHandler, CleanupUntrackedOptions, CleanupUntrackedResult } from '../../core/cleanup/types.js';\nimport type { TrackedResource } from '../../integration/index.js';\n\ninterface PostgresConfig {\n connectionString: string;\n}\n\nexport function createPostgresProvider(config: PostgresConfig): CleanupProvider {\n // Client will be lazily initialized in configure()\n let client: any = null;\n\n const methods: Record<string, CleanupHandler> = {\n deleteRow: async (resource: TrackedResource) => {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n const schema = (resource.schema as string) || 'public';\n const table = resource.table as string;\n\n if (!table) {\n throw new Error(`Missing table name for row ${resource.id}`);\n }\n\n // Use parameterized query to prevent SQL injection\n await client.query(\n `DELETE FROM \"${schema}\".\"${table}\" WHERE id = $1`,\n [resource.id]\n );\n },\n\n deleteUser: async (resource: TrackedResource) => {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n const table = (resource.table as string) || 'users';\n const schema = (resource.schema as string) || 'public';\n\n await client.query(\n `DELETE FROM \"${schema}\".\"${table}\" WHERE id = $1`,\n [resource.id]\n );\n },\n\n customDelete: async (resource: TrackedResource) => {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n // Allow custom SQL queries via the query property\n const query = resource.query as string;\n const params = (resource.params as any[]) || [resource.id];\n\n if (!query) {\n throw new Error(`Missing query for custom delete of resource ${resource.id}`);\n }\n\n await client.query(query, params);\n },\n };\n\n async function cleanupUntracked(options: CleanupUntrackedOptions): Promise<CleanupUntrackedResult> {\n if (!client) {\n throw new Error('Postgres client not initialized. Call configure() first.');\n }\n\n const { testStartTime, userId } = options;\n const deleted: string[] = [];\n const failed: string[] = [];\n let scanned = 0;\n\n // 1. Get all tables in public schema\n const tablesResult = await client.query(`\n SELECT table_name\n FROM information_schema.tables\n WHERE table_schema = 'public'\n AND table_type = 'BASE TABLE'\n AND table_name NOT LIKE '_intellitester%'\n `);\n\n for (const row of tablesResult.rows) {\n const tableName = row.table_name;\n scanned++;\n\n // 2. Check if table has created_at and user_id columns\n const columnsResult = await client.query(`\n SELECT column_name\n FROM information_schema.columns\n WHERE table_name = $1\n `, [tableName]);\n\n const columns: string[] = columnsResult.rows.map((r: { column_name: string }) => r.column_name);\n const hasCreatedAt = columns.some(c => ['created_at', 'createdat', 'created'].includes(c.toLowerCase()));\n const userIdColumn = columns.find(c => ['user_id', 'userid', 'owner_id', 'author_id'].includes(c.toLowerCase()));\n\n if (!hasCreatedAt) continue;\n\n // 3. Build and execute delete query\n let deleteQuery = `DELETE FROM \"${tableName}\" WHERE `;\n const conditions: string[] = [];\n const params: (string | undefined)[] = [];\n\n // Add created_at condition\n const createdAtCol = columns.find(c => ['created_at', 'createdat', 'created'].includes(c.toLowerCase()));\n if (createdAtCol) {\n conditions.push(`\"${createdAtCol}\" >= $${params.length + 1}`);\n params.push(testStartTime);\n }\n\n // Add user_id condition if available\n if (userId && userIdColumn) {\n conditions.push(`\"${userIdColumn}\" = $${params.length + 1}`);\n params.push(userId);\n }\n\n if (conditions.length === 0) continue;\n\n deleteQuery += conditions.join(' AND ') + ' RETURNING id';\n\n try {\n const result = await client.query(deleteQuery, params);\n for (const deletedRow of result.rows) {\n deleted.push(`${tableName}:${deletedRow.id}`);\n }\n } catch {\n failed.push(`${tableName}:error`);\n }\n }\n\n return {\n success: failed.length === 0,\n scanned,\n deleted,\n failed,\n };\n }\n\n return {\n name: 'postgres',\n async configure() {\n try {\n // Dynamic import since pg is an optional dependency\n // @ts-expect-error - pg is an optional peer dependency\n const pg = await import('pg');\n const Client = pg.Client || pg.default?.Client;\n client = new Client({ connectionString: config.connectionString });\n await client.connect();\n } catch {\n throw new Error(\n 'Failed to initialize Postgres client. Make sure the \"pg\" package is installed: npm install pg'\n );\n }\n },\n methods,\n cleanupUntracked,\n };\n}\n\n// Default type mappings for Postgres resources\nexport const postgresTypeMappings: Record<string, string> = {\n row: 'postgres.deleteRow',\n user: 'postgres.deleteUser',\n custom: 'postgres.customDelete',\n};\n"]}