@lumifai/harness-tool-pack-postgres 0.0.1 → 0.2.0

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.
@@ -0,0 +1,52 @@
1
+ import type { ToolExecutionContext } from '@mastra/core/tools';
2
+ import { z } from 'zod';
3
+ import type { PostgresToolsOptions } from './postgres';
4
+ declare const validateFileInputSchema: z.ZodObject<{
5
+ jsonFilePath: z.ZodString;
6
+ refreshSchema: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
7
+ schema: z.ZodDefault<z.ZodOptional<z.ZodString>>;
8
+ table: z.ZodString;
9
+ uniqueColumns: z.ZodOptional<z.ZodArray<z.ZodString>>;
10
+ formatRules: z.ZodOptional<z.ZodObject<{
11
+ emailColumns: z.ZodOptional<z.ZodArray<z.ZodString>>;
12
+ phoneColumns: z.ZodOptional<z.ZodArray<z.ZodString>>;
13
+ }, z.core.$strip>>;
14
+ schemaCacheTtlHours: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
15
+ }, z.core.$strip>;
16
+ declare const validateFileOutputSchema: z.ZodObject<{
17
+ validCount: z.ZodNumber;
18
+ rejectedCount: z.ZodNumber;
19
+ validFilePath: z.ZodString;
20
+ rejectedFilePath: z.ZodOptional<z.ZodString>;
21
+ schemaCachePath: z.ZodString;
22
+ uniqueColumns: z.ZodArray<z.ZodString>;
23
+ }, z.core.$strip>;
24
+ export type ValidateFileInput = z.infer<typeof validateFileInputSchema>;
25
+ export type ValidateFileOutput = z.infer<typeof validateFileOutputSchema>;
26
+ type TableRow = Record<string, unknown>;
27
+ export type TableValidationSchema = {
28
+ version: 1;
29
+ schema: string;
30
+ table: string;
31
+ generatedAt: string;
32
+ columns: Array<{
33
+ name: string;
34
+ dataType: string;
35
+ isNullable: boolean;
36
+ hasDefault: boolean;
37
+ isGenerated?: boolean;
38
+ enumValues?: string[];
39
+ ordinalPosition: number;
40
+ }>;
41
+ primaryKey: string[];
42
+ uniqueKeys: string[][];
43
+ };
44
+ export declare function createPostgresValidationTool(options: PostgresToolsOptions): import("@mastra/core/tools").Tool<InferPublicSchema<T>, InferPublicSchema<T>, InferPublicSchema<T>, InferPublicSchema<T>, ToolExecutionContext<InferPublicSchema<T>, InferPublicSchema<T>, unknown>, "postgres_validate_file", unknown>;
45
+ export declare function validatePostgresFile(input: ValidateFileInput, options: PostgresToolsOptions, context: ToolExecutionContext): Promise<ValidateFileOutput>;
46
+ export declare function validateRows(rows: TableRow[], schema: TableValidationSchema, uniqueColumns: string[], formatRules?: ValidateFileInput['formatRules']): {
47
+ valid: TableRow[];
48
+ rejected: Array<TableRow & {
49
+ errors: string[];
50
+ }>;
51
+ };
52
+ export {};
@@ -0,0 +1,395 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createPostgresValidationTool = createPostgresValidationTool;
4
+ exports.validatePostgresFile = validatePostgresFile;
5
+ exports.validateRows = validateRows;
6
+ const node_crypto_1 = require("node:crypto");
7
+ const tools_1 = require("@mastra/core/tools");
8
+ const zod_1 = require("zod");
9
+ const harness_tool_packs_1 = require("@lumifai/harness-tool-packs");
10
+ const catalog_cache_1 = require("./catalog-cache");
11
+ const constants_1 = require("./constants");
12
+ const pg_client_1 = require("./pg-client");
13
+ const query_executor_1 = require("./query-executor");
14
+ const postgres_write_1 = require("./postgres-write");
15
+ const workspaceFiles = (0, harness_tool_packs_1.createWorkspaceFiles)();
16
+ const IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]*$/;
17
+ const UUID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
18
+ const EMAIL = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
19
+ const PHONE = /^[+()\d][+()\d .-]{5,}$/;
20
+ const identifierSchema = (label) => zod_1.z.string().min(1).regex(IDENTIFIER, `${label} must be a valid SQL identifier.`);
21
+ const validateFileInputSchema = zod_1.z.object({
22
+ jsonFilePath: zod_1.z.string().min(1).describe('Workspace-relative JSON file containing table rows.'),
23
+ refreshSchema: zod_1.z.boolean().optional().default(false),
24
+ schema: identifierSchema('schema').optional().default('public'),
25
+ table: identifierSchema('table'),
26
+ uniqueColumns: zod_1.z.array(identifierSchema('uniqueColumns')).min(1).optional(),
27
+ formatRules: zod_1.z
28
+ .object({
29
+ emailColumns: zod_1.z.array(identifierSchema('emailColumns')).optional(),
30
+ phoneColumns: zod_1.z.array(identifierSchema('phoneColumns')).optional(),
31
+ })
32
+ .optional(),
33
+ schemaCacheTtlHours: zod_1.z.number().finite().positive().max(168).optional().default(24),
34
+ });
35
+ const validateFileOutputSchema = zod_1.z.object({
36
+ validCount: zod_1.z.number().int().nonnegative(),
37
+ rejectedCount: zod_1.z.number().int().nonnegative(),
38
+ validFilePath: zod_1.z.string(),
39
+ rejectedFilePath: zod_1.z.string().optional(),
40
+ schemaCachePath: zod_1.z.string(),
41
+ uniqueColumns: zod_1.z.array(zod_1.z.string()),
42
+ });
43
+ const cachedSchemaSchema = zod_1.z.object({
44
+ version: zod_1.z.literal(1),
45
+ schema: zod_1.z.string(),
46
+ table: zod_1.z.string(),
47
+ generatedAt: zod_1.z.string(),
48
+ columns: zod_1.z.array(zod_1.z.object({
49
+ name: zod_1.z.string(),
50
+ dataType: zod_1.z.string(),
51
+ isNullable: zod_1.z.boolean(),
52
+ hasDefault: zod_1.z.boolean(),
53
+ isGenerated: zod_1.z.boolean().optional(),
54
+ enumValues: zod_1.z.array(zod_1.z.string()).optional(),
55
+ ordinalPosition: zod_1.z.number().int().positive(),
56
+ })),
57
+ primaryKey: zod_1.z.array(zod_1.z.string()),
58
+ uniqueKeys: zod_1.z.array(zod_1.z.array(zod_1.z.string())),
59
+ });
60
+ function createPostgresValidationTool(options) {
61
+ return (0, tools_1.createTool)({
62
+ id: 'postgres_validate_file',
63
+ description: 'Validate JSON table rows against the live PostgreSQL schema, quarantine invalid rows, and write a valid JSON file for postgres_insert_from_file.',
64
+ inputSchema: validateFileInputSchema,
65
+ outputSchema: validateFileOutputSchema,
66
+ execute: async (inputData, context) => validatePostgresFile(inputData, options, context),
67
+ });
68
+ }
69
+ async function validatePostgresFile(input, options, context) {
70
+ const jsonFilePath = (0, harness_tool_packs_1.normalizeWorkspacePath)(input.jsonFilePath);
71
+ if (!options.allowedTables?.length) {
72
+ throw new Error('postgres_validate_file requires allowedTables with at least one schema.table entry.');
73
+ }
74
+ (0, postgres_write_1.assertAllowedTable)({ allowedTables: options.allowedTables }, input.schema, input.table);
75
+ const connectionString = await (0, pg_client_1.resolvePostgresConnectionString)(options, context);
76
+ const connectionOptions = {
77
+ ...options,
78
+ connectionString,
79
+ resolveConnectionString: undefined,
80
+ };
81
+ const cachePath = schemaCachePath(input.schema, input.table, connectionString);
82
+ const cache = await loadSchemaCache(context, cachePath, input.schema, input.table, input.schemaCacheTtlHours, input.refreshSchema);
83
+ const schema = cache ??
84
+ (await (0, pg_client_1.withPostgresClient)(connectionOptions, context, async (client) => {
85
+ const catalog = await (0, query_executor_1.withReadOnlyTransaction)(client, {
86
+ statementTimeoutMs: options.statementTimeoutMs,
87
+ lockTimeoutMs: options.lockTimeoutMs,
88
+ idleInTransactionTimeoutMs: options.idleInTransactionTimeoutMs,
89
+ }, () => (0, catalog_cache_1.loadCachedCatalog)(connectionString, client, [input.schema], options.catalogCacheTtlMs ?? constants_1.DEFAULT_CATALOG_CACHE_TTL_MS));
90
+ const relation = catalog.relations.get(`${input.schema}.${input.table}`);
91
+ if (!relation) {
92
+ throw new Error(`PostgreSQL relation ${input.schema}.${input.table} was not found.`);
93
+ }
94
+ const snapshot = toCachedSchema(relation);
95
+ await writeWorkspaceJson(context, cachePath, snapshot);
96
+ return snapshot;
97
+ }));
98
+ const rows = await readRows(context, jsonFilePath);
99
+ const maxRows = Math.min(options.maxRows ?? postgres_write_1.DEFAULT_POSTGRES_WRITE_MAX_ROWS, constants_1.MAX_INSERT_ROWS);
100
+ if (rows.length > maxRows) {
101
+ throw new Error(`Input file contains ${rows.length} rows; the maximum is ${maxRows}.`);
102
+ }
103
+ const uniqueColumns = input.uniqueColumns ?? resolveUniqueColumns(schema);
104
+ for (const column of uniqueColumns) {
105
+ if (!schema.columns.some((candidate) => candidate.name === column)) {
106
+ throw new Error(`Unique key column ${column} is not present on ${input.schema}.${input.table}.`);
107
+ }
108
+ }
109
+ for (const column of [
110
+ ...(input.formatRules?.emailColumns ?? []),
111
+ ...(input.formatRules?.phoneColumns ?? []),
112
+ ]) {
113
+ if (!schema.columns.some((candidate) => candidate.name === column)) {
114
+ throw new Error(`Format rule column ${column} is not present on ${input.schema}.${input.table}.`);
115
+ }
116
+ }
117
+ const validation = validateRows(rows, schema, uniqueColumns, input.formatRules);
118
+ const validFilePath = deriveOutputPath(jsonFilePath, '.valid.json');
119
+ const rejectedFilePath = validation.rejected.length > 0 ? deriveOutputPath(jsonFilePath, '.rejected.json') : undefined;
120
+ await writeWorkspaceJson(context, validFilePath, validation.valid);
121
+ if (rejectedFilePath) {
122
+ await writeWorkspaceJson(context, rejectedFilePath, validation.rejected);
123
+ }
124
+ return {
125
+ validCount: validation.valid.length,
126
+ rejectedCount: validation.rejected.length,
127
+ validFilePath,
128
+ ...(rejectedFilePath ? { rejectedFilePath } : {}),
129
+ schemaCachePath: cachePath,
130
+ uniqueColumns,
131
+ };
132
+ }
133
+ function validateRows(rows, schema, uniqueColumns, formatRules) {
134
+ const seen = new Set();
135
+ const valid = [];
136
+ const rejected = [];
137
+ for (const row of rows) {
138
+ const errors = validateRow(row, schema, uniqueColumns, seen, formatRules);
139
+ if (errors.length > 0) {
140
+ rejected.push({ ...row, errors });
141
+ }
142
+ else {
143
+ valid.push(row);
144
+ }
145
+ }
146
+ return { valid, rejected };
147
+ }
148
+ function validateRow(row, schema, uniqueColumns, seen, formatRules) {
149
+ const errors = [];
150
+ const columns = new Map(schema.columns.map((column) => [column.name, column]));
151
+ for (const column of schema.columns) {
152
+ const value = row[column.name];
153
+ // PostgreSQL NOT NULL rejects only NULL — empty string '' is a valid text value.
154
+ if (!column.isNullable && !column.hasDefault && isMissing(value)) {
155
+ errors.push(`${column.name} is required.`);
156
+ continue;
157
+ }
158
+ if (!isMissing(value)) {
159
+ if (column.isGenerated) {
160
+ errors.push(`${column.name} is generated by the database and must be omitted.`);
161
+ continue;
162
+ }
163
+ const typeError = validateValue(column.name, column.dataType, value, column.enumValues, formatRules);
164
+ if (typeError) {
165
+ errors.push(typeError);
166
+ }
167
+ }
168
+ }
169
+ for (const key of Object.keys(row)) {
170
+ if (!columns.has(key)) {
171
+ errors.push(`${key} is not a column on the target table.`);
172
+ }
173
+ }
174
+ if (errors.length === 0) {
175
+ const uniqueValues = uniqueColumns.map((column) => row[column]);
176
+ if (uniqueColumns.length > 0 && uniqueValues.every((value) => !isMissing(value))) {
177
+ const key = uniqueColumns
178
+ .map((column) => normalizeKey(row[column], columns.get(column)?.dataType))
179
+ .join('\u001f');
180
+ if (seen.has(key)) {
181
+ errors.push(`duplicate batch key for ${uniqueColumns.join(', ')}.`);
182
+ }
183
+ else {
184
+ seen.add(key);
185
+ }
186
+ }
187
+ }
188
+ return errors;
189
+ }
190
+ function validateValue(columnName, dataType, value, enumValues, formatRules) {
191
+ const type = dataType.toLowerCase();
192
+ if (enumValues && !enumValues.includes(String(value))) {
193
+ return `${columnName} must be one of: ${enumValues.join(', ')}.`;
194
+ }
195
+ if (formatRules?.emailColumns?.includes(columnName) &&
196
+ (typeof value !== 'string' || !EMAIL.test(value))) {
197
+ return `${columnName} must be a valid email address.`;
198
+ }
199
+ if (formatRules?.phoneColumns?.includes(columnName) &&
200
+ (typeof value !== 'string' || !PHONE.test(value))) {
201
+ return `${columnName} must be a valid phone value.`;
202
+ }
203
+ if ((type === 'uuid' || type.includes('uuid')) &&
204
+ (typeof value !== 'string' || !UUID.test(value))) {
205
+ return `${columnName} must be a UUID.`;
206
+ }
207
+ if (['boolean'].includes(type) &&
208
+ typeof value !== 'boolean' &&
209
+ value !== 'true' &&
210
+ value !== 'false') {
211
+ return `${columnName} must be a boolean.`;
212
+ }
213
+ if (isIntegerType(type)) {
214
+ const parsed = parseIntegerCandidate(value);
215
+ if (parsed === undefined) {
216
+ return `${columnName} must be an integer.`;
217
+ }
218
+ const range = INTEGER_RANGES[type];
219
+ if (parsed < range.min || parsed > range.max) {
220
+ return `${columnName} is out of range for ${type}.`;
221
+ }
222
+ }
223
+ else if (isNumericType(type) && !isNumericValue(value)) {
224
+ return `${columnName} must be numeric.`;
225
+ }
226
+ if (isTimeType(type)) {
227
+ if (!isValidTimeValue(value)) {
228
+ return `${columnName} must be a parseable time value.`;
229
+ }
230
+ }
231
+ else if (isDateOrTimestampType(type) &&
232
+ (typeof value !== 'string' || Number.isNaN(Date.parse(value)))) {
233
+ return `${columnName} must be a parseable date/time value.`;
234
+ }
235
+ if (isTextType(type) && typeof value !== 'string') {
236
+ return `${columnName} must be a string.`;
237
+ }
238
+ if (type === 'json' || type === 'jsonb') {
239
+ if (typeof value === 'string') {
240
+ try {
241
+ JSON.parse(value);
242
+ }
243
+ catch {
244
+ return `${columnName} must contain valid JSON.`;
245
+ }
246
+ }
247
+ else if (typeof value !== 'object') {
248
+ return `${columnName} must contain an object, array, or JSON string.`;
249
+ }
250
+ }
251
+ return undefined;
252
+ }
253
+ function isIntegerType(type) {
254
+ return type in INTEGER_RANGES;
255
+ }
256
+ function isNumericType(type) {
257
+ return ['numeric', 'decimal', 'real', 'double precision'].includes(type);
258
+ }
259
+ function isTextType(type) {
260
+ return ['text', 'character varying', 'varchar', 'character', 'char', 'citext', 'name'].includes(type);
261
+ }
262
+ const INTEGER_RANGES = {
263
+ smallint: { min: -32768n, max: 32767n },
264
+ integer: { min: -2147483648n, max: 2147483647n },
265
+ bigint: { min: -9223372036854775808n, max: 9223372036854775807n },
266
+ };
267
+ /** Accept only whole numbers (no fractional part); strings must be digit-only. */
268
+ function parseIntegerCandidate(value) {
269
+ if (typeof value === 'number') {
270
+ if (!Number.isFinite(value) || !Number.isInteger(value))
271
+ return undefined;
272
+ return BigInt(value);
273
+ }
274
+ if (typeof value === 'string') {
275
+ const trimmed = value.trim();
276
+ if (!/^[+-]?\d+$/.test(trimmed))
277
+ return undefined;
278
+ try {
279
+ return BigInt(trimmed);
280
+ }
281
+ catch {
282
+ return undefined;
283
+ }
284
+ }
285
+ return undefined;
286
+ }
287
+ function isNumericValue(value) {
288
+ return ((typeof value === 'number' && Number.isFinite(value)) ||
289
+ (typeof value === 'string' && value.trim() !== '' && Number.isFinite(Number(value))));
290
+ }
291
+ function isTimeType(type) {
292
+ return type === 'time' || type.startsWith('time without') || type.startsWith('time with');
293
+ }
294
+ function isDateOrTimestampType(type) {
295
+ return type.includes('date') || type.includes('timestamp');
296
+ }
297
+ function isValidTimeValue(value) {
298
+ if (typeof value !== 'string')
299
+ return false;
300
+ // HH:MM[:SS[.fraction]][±HH[:MM] or Z]
301
+ return /^([01]\d|2[0-3]):[0-5]\d(:[0-5]\d(\.\d{1,6})?)?(Z|[+-]\d{2}(:?\d{2})?)?$/i.test(value.trim());
302
+ }
303
+ function isMissing(value) {
304
+ return value === undefined || value === null;
305
+ }
306
+ /** Case-sensitive by default (matches PG unique text); citext compares case-insensitively. */
307
+ function normalizeKey(value, dataType) {
308
+ if (typeof value === 'string') {
309
+ return dataType?.toLowerCase() === 'citext' ? value.toLowerCase() : value;
310
+ }
311
+ if (typeof value === 'number' || typeof value === 'boolean') {
312
+ return String(value);
313
+ }
314
+ return JSON.stringify(value);
315
+ }
316
+ function resolveUniqueColumns(schema) {
317
+ if (schema.uniqueKeys[0])
318
+ return schema.uniqueKeys[0];
319
+ if (schema.primaryKey.length > 0)
320
+ return schema.primaryKey;
321
+ return [];
322
+ }
323
+ function toCachedSchema(relation) {
324
+ return {
325
+ version: 1,
326
+ schema: relation.schema,
327
+ table: relation.name,
328
+ generatedAt: new Date().toISOString(),
329
+ columns: relation.columns.map((column) => ({
330
+ name: column.name,
331
+ dataType: column.dataType,
332
+ isNullable: column.isNullable,
333
+ hasDefault: column.hasDefault === true,
334
+ ...(column.isGenerated ? { isGenerated: true } : {}),
335
+ ...(column.enumValues ? { enumValues: column.enumValues } : {}),
336
+ ordinalPosition: column.ordinalPosition,
337
+ })),
338
+ primaryKey: relation.primaryKey,
339
+ uniqueKeys: relation.uniqueKeys,
340
+ };
341
+ }
342
+ async function loadSchemaCache(context, cachePath, schemaName, tableName, ttlHours, refresh) {
343
+ if (refresh)
344
+ return undefined;
345
+ try {
346
+ const parsed = cachedSchemaSchema.safeParse(JSON.parse(await readWorkspaceText(context, cachePath)));
347
+ if (!parsed.success)
348
+ return undefined;
349
+ const value = parsed.data;
350
+ if (value.schema !== schemaName ||
351
+ value.table !== tableName ||
352
+ typeof value.generatedAt !== 'string' ||
353
+ !Number.isFinite(Date.parse(value.generatedAt)) ||
354
+ Date.now() - Date.parse(value.generatedAt) > ttlHours * 60 * 60 * 1000) {
355
+ return undefined;
356
+ }
357
+ return value;
358
+ }
359
+ catch {
360
+ return undefined;
361
+ }
362
+ }
363
+ async function readRows(context, filePath) {
364
+ const parsed = JSON.parse(await readWorkspaceText(context, filePath));
365
+ const rows = Array.isArray(parsed) ? parsed : [parsed];
366
+ if (rows.length === 0 || rows.some((row) => !isRecord(row))) {
367
+ throw new Error('JSON must contain one object or a non-empty array of objects.');
368
+ }
369
+ return rows;
370
+ }
371
+ async function readWorkspaceText(context, filePath) {
372
+ const file = await workspaceFiles.read(context, filePath);
373
+ return file.bytes.toString('utf8');
374
+ }
375
+ async function writeWorkspaceJson(context, filePath, value) {
376
+ await workspaceFiles.write(context, filePath, `${JSON.stringify(value, null, 2)}\n`, {
377
+ overwrite: true,
378
+ });
379
+ }
380
+ function deriveOutputPath(filePath, suffix) {
381
+ return filePath.toLowerCase().endsWith('.json')
382
+ ? `${filePath.slice(0, -'.json'.length)}${suffix}`
383
+ : `${filePath}${suffix}`;
384
+ }
385
+ function isRecord(value) {
386
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
387
+ }
388
+ function schemaCachePath(schema, table, connectionString) {
389
+ const fingerprint = (0, node_crypto_1.createHash)('sha256')
390
+ .update(connectionString, 'utf8')
391
+ .digest('hex')
392
+ .slice(0, 16);
393
+ return `.schema-cache/${schema}.${table}.${fingerprint}.json`;
394
+ }
395
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../src/validation.ts"],"names":[],"mappings":"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"}
@@ -2,46 +2,49 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.normalizeWorkspaceFilePath = normalizeWorkspaceFilePath;
4
4
  exports.readWorkspaceCsvText = readWorkspaceCsvText;
5
+ const harness_tool_packs_1 = require("@lumifai/harness-tool-packs");
5
6
  const errors_1 = require("./errors");
7
+ const workspaceFiles = (0, harness_tool_packs_1.createWorkspaceFiles)();
6
8
  function normalizeWorkspaceFilePath(path) {
7
- const trimmed = path.trim();
8
- if (!trimmed.startsWith('/')) {
9
- throw new errors_1.PostgresToolError('INVALID_INPUT', `Path must be absolute within the workspace: ${path}`, {
9
+ try {
10
+ return (0, harness_tool_packs_1.normalizeWorkspacePath)(path);
11
+ }
12
+ catch (error) {
13
+ throw new errors_1.PostgresToolError('INVALID_INPUT', error instanceof Error ? error.message : String(error), {
10
14
  path: 'source.path',
11
- hint: 'Use a workspace path such as /data/rows.csv.',
15
+ hint: 'Use a workspace path such as data/rows.csv.',
12
16
  });
13
17
  }
14
- return trimmed;
15
18
  }
16
19
  async function readWorkspaceCsvText(context, path, maxBytes) {
17
- const normalizedPath = normalizeWorkspaceFilePath(path);
18
- const filesystem = context.workspace?.filesystem;
19
- if (!filesystem?.readFile) {
20
- throw new errors_1.PostgresToolError('CONFIGURATION_ERROR', `Postgres insert requires a workspace filesystem to read ${normalizedPath}.`, { path: 'source.path' });
20
+ let file;
21
+ try {
22
+ file = await workspaceFiles.read(context, path, { maxBytes });
21
23
  }
22
- if (typeof filesystem.stat === 'function') {
23
- const stats = await filesystem.stat(normalizedPath);
24
- const size = typeof stats === 'object' && stats !== null && 'size' in stats
25
- ? Number(stats.size)
26
- : Number.NaN;
27
- if (Number.isFinite(size) && size > maxBytes) {
28
- throw new errors_1.PostgresToolError('COMPLEXITY_EXCEEDED', `CSV file ${normalizedPath} is ${size} bytes, exceeding the ${maxBytes} byte limit.`, {
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ if (/requires a workspace filesystem|filesystem\./i.test(message)) {
27
+ throw new errors_1.PostgresToolError('CONFIGURATION_ERROR', `Postgres insert requires a workspace filesystem to read ${normalizeWorkspaceFilePath(path)}.`, { path: 'source.path' });
28
+ }
29
+ if (/limit is/i.test(message)) {
30
+ throw new errors_1.PostgresToolError('COMPLEXITY_EXCEEDED', message.includes('bytes')
31
+ ? message.replace(/^File /, 'CSV file ')
32
+ : `CSV file exceeds the ${maxBytes} byte limit.`, {
29
33
  path: 'source.path',
30
34
  hint: 'Split the CSV or raise maxInsertCsvBytes on the tool pack.',
31
35
  });
32
36
  }
37
+ if (/workspace-relative paths|escapes the workspace/i.test(message)) {
38
+ throw new errors_1.PostgresToolError('INVALID_INPUT', message, {
39
+ path: 'source.path',
40
+ hint: 'Use a workspace path such as data/rows.csv.',
41
+ });
42
+ }
43
+ throw error;
33
44
  }
34
- const fileContent = await filesystem.readFile(normalizedPath, {
35
- encoding: 'utf8',
36
- });
37
- const content = typeof fileContent === 'string' ? fileContent : fileContent.toString('utf8');
38
- const byteLength = Buffer.byteLength(content, 'utf8');
39
- if (byteLength > maxBytes) {
40
- throw new errors_1.PostgresToolError('COMPLEXITY_EXCEEDED', `CSV file ${normalizedPath} is ${byteLength} bytes, exceeding the ${maxBytes} byte limit.`, {
41
- path: 'source.path',
42
- hint: 'Split the CSV or raise maxInsertCsvBytes on the tool pack.',
43
- });
44
- }
45
- return { normalizedPath, content };
45
+ return {
46
+ normalizedPath: file.path,
47
+ content: file.bytes.toString('utf8'),
48
+ };
46
49
  }
47
50
  //# sourceMappingURL=workspace-file.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"workspace-file.js","sourceRoot":"","sources":["../src/workspace-file.ts"],"names":[],"mappings":";;AAIA,gEAaC;AAED,oDAkDC;AAnED,qCAA6C;AAE7C,SAAgB,0BAA0B,CAAC,IAAY;IACrD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAC5B,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,0BAAiB,CACzB,eAAe,EACf,+CAA+C,IAAI,EAAE,EACrD;YACE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,8CAA8C;SACrD,CACF,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAEM,KAAK,UAAU,oBAAoB,CACxC,OAA6B,EAC7B,IAAY,EACZ,QAAgB;IAEhB,MAAM,cAAc,GAAG,0BAA0B,CAAC,IAAI,CAAC,CAAC;IACxD,MAAM,UAAU,GAAG,OAAO,CAAC,SAAS,EAAE,UAAU,CAAC;IACjD,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,0BAAiB,CACzB,qBAAqB,EACrB,2DAA2D,cAAc,GAAG,EAC5E,EAAE,IAAI,EAAE,aAAa,EAAE,CACxB,CAAC;IACJ,CAAC;IAED,IAAI,OAAO,UAAU,CAAC,IAAI,KAAK,UAAU,EAAE,CAAC;QAC1C,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;QACpD,MAAM,IAAI,GACR,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,IAAI,IAAI,MAAM,IAAI,KAAK;YAC5D,CAAC,CAAC,MAAM,CAAE,KAA4B,CAAC,IAAI,CAAC;YAC5C,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC;QACjB,IAAI,MAAM,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,IAAI,GAAG,QAAQ,EAAE,CAAC;YAC7C,MAAM,IAAI,0BAAiB,CACzB,qBAAqB,EACrB,YAAY,cAAc,OAAO,IAAI,yBAAyB,QAAQ,cAAc,EACpF;gBACE,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,4DAA4D;aACnE,CACF,CAAC;QACJ,CAAC;IACH,CAAC;IAED,MAAM,WAAW,GAAG,MAAM,UAAU,CAAC,QAAQ,CAAC,cAAc,EAAE;QAC5D,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,WAAW,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;IAC7F,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACtD,IAAI,UAAU,GAAG,QAAQ,EAAE,CAAC;QAC1B,MAAM,IAAI,0BAAiB,CACzB,qBAAqB,EACrB,YAAY,cAAc,OAAO,UAAU,yBAAyB,QAAQ,cAAc,EAC1F;YACE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,4DAA4D;SACnE,CACF,CAAC;IACJ,CAAC;IAED,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,CAAC;AACrC,CAAC"}
1
+ {"version":3,"file":"workspace-file.js","sourceRoot":"","sources":["../src/workspace-file.ts"],"names":[],"mappings":";;AAQA,gEAaC;AAED,oDA0CC;AA/DD,oEAA2F;AAE3F,qCAA6C;AAE7C,MAAM,cAAc,GAAG,IAAA,yCAAoB,GAAE,CAAC;AAE9C,SAAgB,0BAA0B,CAAC,IAAY;IACrD,IAAI,CAAC;QACH,OAAO,IAAA,2CAAsB,EAAC,IAAI,CAAC,CAAC;IACtC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,0BAAiB,CACzB,eAAe,EACf,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EACtD;YACE,IAAI,EAAE,aAAa;YACnB,IAAI,EAAE,6CAA6C;SACpD,CACF,CAAC;IACJ,CAAC;AACH,CAAC;AAEM,KAAK,UAAU,oBAAoB,CACxC,OAA6B,EAC7B,IAAY,EACZ,QAAgB;IAEhB,IAAI,IAAI,CAAC;IACT,IAAI,CAAC;QACH,IAAI,GAAG,MAAM,cAAc,CAAC,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;IAChE,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACvE,IAAI,+CAA+C,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAClE,MAAM,IAAI,0BAAiB,CACzB,qBAAqB,EACrB,2DAA2D,0BAA0B,CAAC,IAAI,CAAC,GAAG,EAC9F,EAAE,IAAI,EAAE,aAAa,EAAE,CACxB,CAAC;QACJ,CAAC;QACD,IAAI,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,0BAAiB,CACzB,qBAAqB,EACrB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;gBACvB,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,WAAW,CAAC;gBACxC,CAAC,CAAC,wBAAwB,QAAQ,cAAc,EAClD;gBACE,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,4DAA4D;aACnE,CACF,CAAC;QACJ,CAAC;QACD,IAAI,iDAAiD,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;YACpE,MAAM,IAAI,0BAAiB,CAAC,eAAe,EAAE,OAAO,EAAE;gBACpD,IAAI,EAAE,aAAa;gBACnB,IAAI,EAAE,6CAA6C;aACpD,CAAC,CAAC;QACL,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;IAED,OAAO;QACL,cAAc,EAAE,IAAI,CAAC,IAAI;QACzB,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,MAAM,CAAC;KACrC,CAAC;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,7 +1,12 @@
1
1
  {
2
2
  "name": "@lumifai/harness-tool-pack-postgres",
3
- "version": "0.0.1",
3
+ "version": "0.2.0",
4
4
  "license": "UNLICENSED",
5
+ "repository": {
6
+ "type": "git",
7
+ "url": "git+https://github.com/Lumif-ai/lumif-harness.git",
8
+ "directory": "packages/tool-packs/postgres"
9
+ },
5
10
  "engines": {
6
11
  "node": ">=22.13.0"
7
12
  },
@@ -22,12 +27,13 @@
22
27
  "skills"
23
28
  ],
24
29
  "dependencies": {
25
- "@mastra/core": "1.50.1",
30
+ "@lumifai/harness-tool-packs": "0.2.1",
31
+ "@mastra/core": "1.67.0",
26
32
  "csv-parse": "^7.0.0",
27
33
  "pg": "^8.16.3",
28
34
  "pg-cursor": "^2.21.0",
29
35
  "pg-sql2": "^5.0.1",
30
- "@lumifai/harness-tool-packs": "0.0.1"
36
+ "zod": "^4.4.3"
31
37
  },
32
38
  "devDependencies": {
33
39
  "@types/pg": "^8.15.5",
@@ -18,7 +18,8 @@ and insert rows from JSON or a workspace CSV.
18
18
  2. Call `postgres_get_schema_details` for columns, keys, and relationships. Metadata reflects whatever the database connection role can see.
19
19
  3. Call `postgres_preview_data` to sample rows from one relation.
20
20
  4. Call `postgres_query` with a versioned JSON `QueryPlan` for complex reads.
21
- 5. Call `postgres_insert` to write rows into one physical table from inline JSON or a CSV path in the Mastra workspace.
21
+ 5. When file-write tools are enabled (`allowedTables`), call `postgres_validate_file` before any file-based insert. Use only the returned `validFilePath` for insert; `rejectedFilePath` is omitted when every row is valid. Pass `refreshSchema: true` after DDL/migrations. Use optional `formatRules` only when text columns need semantic checks beyond SQL types.
22
+ 6. Call `postgres_insert` / `postgres_insert_from_file` to write rows into one physical table from inline JSON or a CSV path in the Mastra workspace.
22
23
 
23
24
  ## Safety rules
24
25
 
@@ -92,7 +93,7 @@ Workspace CSV:
92
93
  "relation": "users",
93
94
  "source": {
94
95
  "kind": "csv",
95
- "path": "/data/users.csv"
96
+ "path": "data/users.csv"
96
97
  }
97
98
  }
98
99
  ```