@mastra/dsql 0.0.0-ag-example-20260516005230

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 (38) hide show
  1. package/CHANGELOG.md +60 -0
  2. package/LICENSE.md +30 -0
  3. package/README.md +357 -0
  4. package/dist/index.cjs +4478 -0
  5. package/dist/index.cjs.map +1 -0
  6. package/dist/index.d.ts +4 -0
  7. package/dist/index.d.ts.map +1 -0
  8. package/dist/index.js +4469 -0
  9. package/dist/index.js.map +1 -0
  10. package/dist/shared/batch.d.ts +55 -0
  11. package/dist/shared/batch.d.ts.map +1 -0
  12. package/dist/shared/config.d.ts +129 -0
  13. package/dist/shared/config.d.ts.map +1 -0
  14. package/dist/shared/retry.d.ts +207 -0
  15. package/dist/shared/retry.d.ts.map +1 -0
  16. package/dist/storage/client.d.ts +91 -0
  17. package/dist/storage/client.d.ts.map +1 -0
  18. package/dist/storage/db/index.d.ts +179 -0
  19. package/dist/storage/db/index.d.ts.map +1 -0
  20. package/dist/storage/domains/agents/index.d.ts +47 -0
  21. package/dist/storage/domains/agents/index.d.ts.map +1 -0
  22. package/dist/storage/domains/memory/index.d.ts +80 -0
  23. package/dist/storage/domains/memory/index.d.ts.map +1 -0
  24. package/dist/storage/domains/observability/index.d.ts +37 -0
  25. package/dist/storage/domains/observability/index.d.ts.map +1 -0
  26. package/dist/storage/domains/scores/index.d.ts +53 -0
  27. package/dist/storage/domains/scores/index.d.ts.map +1 -0
  28. package/dist/storage/domains/utils.d.ts +14 -0
  29. package/dist/storage/domains/utils.d.ts.map +1 -0
  30. package/dist/storage/domains/workflows/index.d.ts +61 -0
  31. package/dist/storage/domains/workflows/index.d.ts.map +1 -0
  32. package/dist/storage/index.d.ts +46 -0
  33. package/dist/storage/index.d.ts.map +1 -0
  34. package/dist/storage/performance-indexes/performance-test.d.ts +47 -0
  35. package/dist/storage/performance-indexes/performance-test.d.ts.map +1 -0
  36. package/dist/storage/test-utils.d.ts +14 -0
  37. package/dist/storage/test-utils.d.ts.map +1 -0
  38. package/package.json +69 -0
package/dist/index.cjs ADDED
@@ -0,0 +1,4478 @@
1
+ 'use strict';
2
+
3
+ var auroraDsqlNodePostgresConnector = require('@aws/aurora-dsql-node-postgres-connector');
4
+ var error = require('@mastra/core/error');
5
+ var storage = require('@mastra/core/storage');
6
+ var pg = require('pg');
7
+ var base = require('@mastra/core/base');
8
+ var utils = require('@mastra/core/utils');
9
+ var agent = require('@mastra/core/agent');
10
+ var evals = require('@mastra/core/evals');
11
+
12
+ // src/storage/index.ts
13
+
14
+ // src/shared/config.ts
15
+ var DSQL_POOL_DEFAULTS = {
16
+ /** Maximum connections in the pool */
17
+ max: 10,
18
+ /** Minimum connections in the pool */
19
+ min: 0,
20
+ /** Close idle connections after 10 minutes */
21
+ idleTimeoutMillis: 6e5,
22
+ /** Force connection rotation before DSQL's 60-minute limit */
23
+ maxLifetimeSeconds: 3300,
24
+ /** Connection acquisition timeout */
25
+ connectionTimeoutMillis: 5e3,
26
+ /** Allow process to exit when idle */
27
+ allowExitOnIdle: true
28
+ };
29
+ var isPoolConfig = (cfg) => {
30
+ return "pool" in cfg;
31
+ };
32
+ var isHostConfig = (cfg) => {
33
+ return "host" in cfg;
34
+ };
35
+ var validateConfig = (config) => {
36
+ if (!config.id || typeof config.id !== "string" || config.id.trim() === "") {
37
+ throw new Error("DSQLStore: id must be provided and cannot be empty.");
38
+ }
39
+ if (isPoolConfig(config)) {
40
+ if (!config.pool) {
41
+ throw new Error("DSQLStore: pool must be provided when using pool config.");
42
+ }
43
+ return;
44
+ }
45
+ if (!isHostConfig(config)) {
46
+ throw new Error("DSQLStore: host must be provided and cannot be empty.");
47
+ }
48
+ if (!config.host || config.host.trim() === "") {
49
+ throw new Error("DSQLStore: host must be provided and cannot be empty.");
50
+ }
51
+ if (config.maxLifetimeSeconds !== void 0 && config.maxLifetimeSeconds >= 3600) {
52
+ throw new Error(
53
+ "DSQLStore: maxLifetimeSeconds must be less than 3600 (60 minutes) due to Aurora DSQL connection duration limit."
54
+ );
55
+ }
56
+ };
57
+ var extractRegionFromHost = (host) => {
58
+ const match = host.match(/\.dsql\.([a-z0-9-]+)\.on\.aws$/);
59
+ return match?.[1];
60
+ };
61
+ var getEffectiveRegion = (config) => {
62
+ if (config.region) {
63
+ return config.region;
64
+ }
65
+ const extractedRegion = extractRegionFromHost(config.host);
66
+ if (extractedRegion) {
67
+ return extractedRegion;
68
+ }
69
+ throw new Error(
70
+ "DSQLStore: region could not be determined. Provide region in config or use a standard DSQL endpoint."
71
+ );
72
+ };
73
+
74
+ // src/storage/client.ts
75
+ function truncateQuery(query, maxLength = 100) {
76
+ const normalized = query.replace(/\s+/g, " ").trim();
77
+ if (normalized.length <= maxLength) {
78
+ return normalized;
79
+ }
80
+ return normalized.slice(0, maxLength) + "...";
81
+ }
82
+ var PoolAdapter = class {
83
+ constructor($pool) {
84
+ this.$pool = $pool;
85
+ }
86
+ $pool;
87
+ connect() {
88
+ return this.$pool.connect();
89
+ }
90
+ async none(query, values) {
91
+ await this.$pool.query(query, values);
92
+ return null;
93
+ }
94
+ async one(query, values) {
95
+ const result = await this.$pool.query(query, values);
96
+ if (result.rows.length === 0) {
97
+ throw new Error(`No data returned from query: ${truncateQuery(query)}`);
98
+ }
99
+ if (result.rows.length > 1) {
100
+ throw new Error(`Multiple rows returned when one was expected: ${truncateQuery(query)}`);
101
+ }
102
+ return result.rows[0];
103
+ }
104
+ async oneOrNone(query, values) {
105
+ const result = await this.$pool.query(query, values);
106
+ if (result.rows.length === 0) {
107
+ return null;
108
+ }
109
+ if (result.rows.length > 1) {
110
+ throw new Error(`Multiple rows returned when one or none was expected: ${truncateQuery(query)}`);
111
+ }
112
+ return result.rows[0];
113
+ }
114
+ async any(query, values) {
115
+ const result = await this.$pool.query(query, values);
116
+ return result.rows;
117
+ }
118
+ async manyOrNone(query, values) {
119
+ return this.any(query, values);
120
+ }
121
+ async many(query, values) {
122
+ const result = await this.$pool.query(query, values);
123
+ if (result.rows.length === 0) {
124
+ throw new Error(`No data returned from query: ${truncateQuery(query)}`);
125
+ }
126
+ return result.rows;
127
+ }
128
+ async query(query, values) {
129
+ return this.$pool.query(query, values);
130
+ }
131
+ async tx(callback) {
132
+ const client = await this.$pool.connect();
133
+ try {
134
+ await client.query("BEGIN");
135
+ const txClient = new TransactionClient(client);
136
+ const result = await callback(txClient);
137
+ await client.query("COMMIT");
138
+ return result;
139
+ } catch (error) {
140
+ try {
141
+ await client.query("ROLLBACK");
142
+ } catch (rollbackError) {
143
+ console.error("Transaction rollback failed:", rollbackError);
144
+ }
145
+ throw error;
146
+ } finally {
147
+ client.release();
148
+ }
149
+ }
150
+ };
151
+ var TransactionClient = class {
152
+ constructor(client) {
153
+ this.client = client;
154
+ }
155
+ client;
156
+ async none(query, values) {
157
+ await this.client.query(query, values);
158
+ return null;
159
+ }
160
+ async one(query, values) {
161
+ const result = await this.client.query(query, values);
162
+ if (result.rows.length === 0) {
163
+ throw new Error(`No data returned from query: ${truncateQuery(query)}`);
164
+ }
165
+ if (result.rows.length > 1) {
166
+ throw new Error(`Multiple rows returned when one was expected: ${truncateQuery(query)}`);
167
+ }
168
+ return result.rows[0];
169
+ }
170
+ async oneOrNone(query, values) {
171
+ const result = await this.client.query(query, values);
172
+ if (result.rows.length === 0) {
173
+ return null;
174
+ }
175
+ if (result.rows.length > 1) {
176
+ throw new Error(`Multiple rows returned when one or none was expected: ${truncateQuery(query)}`);
177
+ }
178
+ return result.rows[0];
179
+ }
180
+ async any(query, values) {
181
+ const result = await this.client.query(query, values);
182
+ return result.rows;
183
+ }
184
+ async manyOrNone(query, values) {
185
+ return this.any(query, values);
186
+ }
187
+ async many(query, values) {
188
+ const result = await this.client.query(query, values);
189
+ if (result.rows.length === 0) {
190
+ throw new Error(`No data returned from query: ${truncateQuery(query)}`);
191
+ }
192
+ return result.rows;
193
+ }
194
+ async query(query, values) {
195
+ return this.client.query(query, values);
196
+ }
197
+ async batch(promises) {
198
+ return Promise.all(promises);
199
+ }
200
+ };
201
+
202
+ // src/shared/retry.ts
203
+ var RETRIABLE_ERROR_CODES = {
204
+ /** Serialization failure - OCC conflict in Aurora DSQL (default retriable) */
205
+ SERIALIZATION_FAILURE: "40001"};
206
+ var DEFAULT_RETRIABLE_SQLSTATES = /* @__PURE__ */ new Set([RETRIABLE_ERROR_CODES.SERIALIZATION_FAILURE]);
207
+ var DEFAULT_RETRY_OPTIONS = {
208
+ maxAttempts: 5,
209
+ initialDelayMs: 100,
210
+ maxDelayMs: 2e3,
211
+ backoffMultiplier: 2,
212
+ jitter: true
213
+ };
214
+ function isPostgresError(error) {
215
+ return error instanceof Error && "code" in error && typeof error.code === "string";
216
+ }
217
+ function getErrorCode(error) {
218
+ if (isPostgresError(error)) {
219
+ return error.code;
220
+ }
221
+ return void 0;
222
+ }
223
+ var SQLSTATE_PATTERN = /^[0-9A-Z]{5}$/;
224
+ function getPostgresSqlStateCode(error) {
225
+ const raw = getErrorCode(error);
226
+ if (!raw) return void 0;
227
+ const code = raw.toUpperCase();
228
+ if (SQLSTATE_PATTERN.test(code)) {
229
+ return code;
230
+ }
231
+ return void 0;
232
+ }
233
+ function isRetriableError(error) {
234
+ const sqlstate = getPostgresSqlStateCode(error);
235
+ if (!sqlstate) {
236
+ return false;
237
+ }
238
+ return DEFAULT_RETRIABLE_SQLSTATES.has(sqlstate);
239
+ }
240
+ function calculateRetryDelay(attempt, options = {}) {
241
+ const {
242
+ initialDelayMs = DEFAULT_RETRY_OPTIONS.initialDelayMs,
243
+ maxDelayMs = DEFAULT_RETRY_OPTIONS.maxDelayMs,
244
+ backoffMultiplier = DEFAULT_RETRY_OPTIONS.backoffMultiplier,
245
+ jitter = DEFAULT_RETRY_OPTIONS.jitter
246
+ } = options;
247
+ const baseDelay = initialDelayMs * Math.pow(backoffMultiplier, attempt - 1);
248
+ const cappedDelay = Math.min(baseDelay, maxDelayMs);
249
+ if (jitter) {
250
+ return Math.floor(Math.random() * (cappedDelay + 1));
251
+ }
252
+ return cappedDelay;
253
+ }
254
+ function sleep(ms) {
255
+ return new Promise((resolve) => setTimeout(resolve, ms));
256
+ }
257
+ function validateRetryOptions(options) {
258
+ const { maxAttempts, initialDelayMs, maxDelayMs, backoffMultiplier } = options;
259
+ if (maxAttempts < 1) {
260
+ throw new Error(`Invalid retry option: maxAttempts must be >= 1, got ${maxAttempts}`);
261
+ }
262
+ if (initialDelayMs < 0) {
263
+ throw new Error(`Invalid retry option: initialDelayMs must be >= 0, got ${initialDelayMs}`);
264
+ }
265
+ if (maxDelayMs <= 0) {
266
+ throw new Error(`Invalid retry option: maxDelayMs must be > 0, got ${maxDelayMs}`);
267
+ }
268
+ if (backoffMultiplier < 1) {
269
+ throw new Error(`Invalid retry option: backoffMultiplier must be >= 1, got ${backoffMultiplier}`);
270
+ }
271
+ if (maxDelayMs < initialDelayMs) {
272
+ throw new Error(`Invalid retry option: maxDelayMs (${maxDelayMs}) must be >= initialDelayMs (${initialDelayMs})`);
273
+ }
274
+ }
275
+ async function withRetry(fn, options = {}) {
276
+ const {
277
+ maxAttempts = DEFAULT_RETRY_OPTIONS.maxAttempts,
278
+ initialDelayMs = DEFAULT_RETRY_OPTIONS.initialDelayMs,
279
+ maxDelayMs = DEFAULT_RETRY_OPTIONS.maxDelayMs,
280
+ backoffMultiplier = DEFAULT_RETRY_OPTIONS.backoffMultiplier,
281
+ jitter = DEFAULT_RETRY_OPTIONS.jitter,
282
+ onRetry,
283
+ isRetriable = isRetriableError
284
+ } = options;
285
+ validateRetryOptions({ maxAttempts, initialDelayMs, maxDelayMs, backoffMultiplier });
286
+ const startTime = Date.now();
287
+ let lastError;
288
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
289
+ try {
290
+ const result = await fn();
291
+ return {
292
+ result,
293
+ attempts: attempt,
294
+ totalTimeMs: Date.now() - startTime
295
+ };
296
+ } catch (error) {
297
+ lastError = error instanceof Error ? error : new Error(String(error));
298
+ if (attempt === maxAttempts || !isRetriable(error)) {
299
+ throw lastError;
300
+ }
301
+ const delay = calculateRetryDelay(attempt, {
302
+ initialDelayMs,
303
+ maxDelayMs,
304
+ backoffMultiplier,
305
+ jitter
306
+ });
307
+ if (onRetry) {
308
+ onRetry(lastError, attempt, delay);
309
+ }
310
+ await sleep(delay);
311
+ }
312
+ }
313
+ throw lastError;
314
+ }
315
+
316
+ // src/shared/batch.ts
317
+ var DEFAULT_MAX_ROWS_PER_BATCH = 3e3;
318
+ function splitIntoBatches(records, options = {}) {
319
+ const maxRows = options.maxRows ?? DEFAULT_MAX_ROWS_PER_BATCH;
320
+ if (records.length === 0) {
321
+ return {
322
+ batches: [],
323
+ totalRecords: 0,
324
+ batchCount: 0
325
+ };
326
+ }
327
+ if (maxRows <= 0) {
328
+ throw new Error(`maxRows must be a positive number, got: ${maxRows}`);
329
+ }
330
+ const batches = [];
331
+ for (let i = 0; i < records.length; i += maxRows) {
332
+ batches.push(records.slice(i, i + maxRows));
333
+ }
334
+ return {
335
+ batches,
336
+ totalRecords: records.length,
337
+ batchCount: batches.length
338
+ };
339
+ }
340
+
341
+ // src/storage/db/index.ts
342
+ function resolveDsqlConfig(config) {
343
+ if ("client" in config) {
344
+ return {
345
+ client: config.client,
346
+ schemaName: config.schemaName,
347
+ skipDefaultIndexes: config.skipDefaultIndexes,
348
+ indexes: config.indexes
349
+ };
350
+ }
351
+ if ("pool" in config) {
352
+ return {
353
+ client: new PoolAdapter(config.pool),
354
+ schemaName: config.schemaName,
355
+ skipDefaultIndexes: config.skipDefaultIndexes,
356
+ indexes: config.indexes
357
+ };
358
+ }
359
+ const pool = new pg.Pool({
360
+ host: config.host,
361
+ database: config.database,
362
+ user: config.user,
363
+ Client: auroraDsqlNodePostgresConnector.AuroraDSQLClient
364
+ });
365
+ return {
366
+ client: new PoolAdapter(pool),
367
+ schemaName: config.schemaName,
368
+ skipDefaultIndexes: config.skipDefaultIndexes,
369
+ indexes: config.indexes
370
+ };
371
+ }
372
+ function getSchemaName(schema) {
373
+ return schema ? `"${utils.parseSqlIdentifier(schema, "schema name")}"` : '"public"';
374
+ }
375
+ function getTableName({ indexName, schemaName }) {
376
+ const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
377
+ const quotedIndexName = `"${parsedIndexName}"`;
378
+ const quotedSchemaName = schemaName;
379
+ return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
380
+ }
381
+ var schemaSetupRegistry = /* @__PURE__ */ new Map();
382
+ var DsqlDB = class extends base.MastraBase {
383
+ client;
384
+ schemaName;
385
+ skipDefaultIndexes;
386
+ constructor(config) {
387
+ super({
388
+ component: "STORAGE",
389
+ name: "DSQL_DB_LAYER"
390
+ });
391
+ this.client = config.client;
392
+ this.schemaName = config.schemaName;
393
+ this.skipDefaultIndexes = config.skipDefaultIndexes;
394
+ }
395
+ async hasColumn(table, column) {
396
+ const schema = this.schemaName || "public";
397
+ const result = await this.client.oneOrNone(
398
+ `SELECT 1 FROM information_schema.columns WHERE table_schema = $1 AND table_name = $2 AND (column_name = $3 OR column_name = $4)`,
399
+ [schema, table, column, column.toLowerCase()]
400
+ );
401
+ return !!result;
402
+ }
403
+ /**
404
+ * Prepares values for insertion, handling TEXT columns storing JSON by stringifying them.
405
+ * Aurora DSQL does not support JSONB natively, so we store JSON as TEXT.
406
+ */
407
+ prepareValuesForInsert(record, tableName) {
408
+ return Object.entries(record).map(([key, value]) => {
409
+ const schema = storage.TABLE_SCHEMAS[tableName];
410
+ const columnSchema = schema?.[key];
411
+ if (columnSchema?.type === "jsonb" && value !== null && value !== void 0 && typeof value === "object") {
412
+ return JSON.stringify(value);
413
+ }
414
+ return value;
415
+ });
416
+ }
417
+ /**
418
+ * Adds timestamp Z columns to a record if timestamp columns exist
419
+ */
420
+ addTimestampZColumns(record) {
421
+ if (record.createdAt) {
422
+ record.createdAtZ = record.createdAt;
423
+ }
424
+ if (record.created_at) {
425
+ record.created_atZ = record.created_at;
426
+ }
427
+ if (record.updatedAt) {
428
+ record.updatedAtZ = record.updatedAt;
429
+ }
430
+ }
431
+ /**
432
+ * Prepares a value for database operations, handling Date objects and JSON serialization.
433
+ * This is schema-aware and stringifies objects for TEXT columns storing JSON.
434
+ * Aurora DSQL: We use TEXT instead of JSONB and cast to ::jsonb when filtering.
435
+ */
436
+ prepareValue(value, columnName, tableName) {
437
+ if (value === null || value === void 0) {
438
+ return value;
439
+ }
440
+ if (value instanceof Date) {
441
+ return value.toISOString();
442
+ }
443
+ const schema = storage.TABLE_SCHEMAS[tableName];
444
+ const columnSchema = schema?.[columnName];
445
+ if (columnSchema?.type === "jsonb") {
446
+ if (typeof value === "object") {
447
+ return JSON.stringify(value);
448
+ }
449
+ }
450
+ if (typeof value === "object") {
451
+ return JSON.stringify(value);
452
+ }
453
+ return value;
454
+ }
455
+ async setupSchema() {
456
+ if (!this.schemaName) {
457
+ return;
458
+ }
459
+ let registryEntry = schemaSetupRegistry.get(this.schemaName);
460
+ if (registryEntry?.complete) {
461
+ return;
462
+ }
463
+ const quotedSchemaName = getSchemaName(this.schemaName);
464
+ if (!registryEntry?.promise) {
465
+ const schemaNameCapture = this.schemaName;
466
+ const setupPromise = (async () => {
467
+ try {
468
+ const schemaExists = await this.client.oneOrNone(
469
+ `
470
+ SELECT EXISTS (
471
+ SELECT 1 FROM information_schema.schemata
472
+ WHERE schema_name = $1
473
+ )
474
+ `,
475
+ [schemaNameCapture]
476
+ );
477
+ if (!schemaExists?.exists) {
478
+ try {
479
+ await this.client.none(`CREATE SCHEMA IF NOT EXISTS ${quotedSchemaName}`);
480
+ this.logger.info(`Schema "${schemaNameCapture}" created successfully`);
481
+ } catch (error) {
482
+ this.logger.error(`Failed to create schema "${schemaNameCapture}"`, { error });
483
+ throw new Error(
484
+ `Unable to create schema "${schemaNameCapture}". This requires CREATE privilege on the database. Either create the schema manually or grant CREATE privilege to the user.`
485
+ );
486
+ }
487
+ }
488
+ const entry = schemaSetupRegistry.get(schemaNameCapture);
489
+ if (entry) {
490
+ entry.complete = true;
491
+ }
492
+ this.logger.debug(`Schema "${quotedSchemaName}" is ready for use`);
493
+ } catch (error) {
494
+ schemaSetupRegistry.delete(schemaNameCapture);
495
+ throw error;
496
+ }
497
+ })();
498
+ schemaSetupRegistry.set(this.schemaName, { promise: setupPromise, complete: false });
499
+ registryEntry = schemaSetupRegistry.get(this.schemaName);
500
+ }
501
+ await registryEntry.promise;
502
+ }
503
+ /**
504
+ * Override getSqlType to map JSONB to TEXT for Aurora DSQL compatibility.
505
+ * Aurora DSQL does not fully support native JSONB, so we store JSON as TEXT
506
+ * and cast to ::jsonb only when filtering/querying.
507
+ */
508
+ getSqlType(type) {
509
+ switch (type) {
510
+ case "jsonb":
511
+ return "TEXT";
512
+ case "uuid":
513
+ return "UUID";
514
+ case "boolean":
515
+ return "BOOLEAN";
516
+ default:
517
+ return storage.getSqlType(type);
518
+ }
519
+ }
520
+ getDefaultValue(type) {
521
+ switch (type) {
522
+ case "timestamp":
523
+ return "DEFAULT NOW()";
524
+ case "jsonb":
525
+ return "DEFAULT '{}'";
526
+ default:
527
+ return storage.getDefaultValue(type);
528
+ }
529
+ }
530
+ async insert({ tableName, record }) {
531
+ this.addTimestampZColumns(record);
532
+ const schemaName = getSchemaName(this.schemaName);
533
+ const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
534
+ const values = this.prepareValuesForInsert(record, tableName);
535
+ const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
536
+ await withRetry(
537
+ async () => {
538
+ await this.client.none(
539
+ `INSERT INTO ${getTableName({ indexName: tableName, schemaName })} (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
540
+ values
541
+ );
542
+ },
543
+ {
544
+ onRetry: (error, attempt, delay) => {
545
+ this.logger?.warn?.(`insert retry ${attempt} for table ${tableName} after ${delay}ms: ${error.message}`);
546
+ }
547
+ }
548
+ ).catch((error$1) => {
549
+ throw new error.MastraError(
550
+ {
551
+ id: storage.createStorageErrorId("DSQL", "INSERT", "FAILED"),
552
+ domain: error.ErrorDomain.STORAGE,
553
+ category: error.ErrorCategory.THIRD_PARTY,
554
+ details: {
555
+ tableName
556
+ }
557
+ },
558
+ error$1
559
+ );
560
+ });
561
+ }
562
+ async clearTable({ tableName }) {
563
+ try {
564
+ await withRetry(
565
+ async () => {
566
+ const schemaName = getSchemaName(this.schemaName);
567
+ const tableNameWithSchema = getTableName({ indexName: tableName, schemaName });
568
+ await this.client.none(`DELETE FROM ${tableNameWithSchema}`);
569
+ },
570
+ {
571
+ onRetry: (error, attempt, delay) => {
572
+ this.logger?.warn?.(`clearTable retry ${attempt} for ${tableName} after ${delay}ms: ${error.message}`);
573
+ }
574
+ }
575
+ );
576
+ } catch (error$1) {
577
+ throw new error.MastraError(
578
+ {
579
+ id: storage.createStorageErrorId("DSQL", "CLEAR_TABLE", "FAILED"),
580
+ domain: error.ErrorDomain.STORAGE,
581
+ category: error.ErrorCategory.THIRD_PARTY,
582
+ details: {
583
+ tableName
584
+ }
585
+ },
586
+ error$1
587
+ );
588
+ }
589
+ }
590
+ async createTable({
591
+ tableName,
592
+ schema
593
+ }) {
594
+ await withRetry(
595
+ async () => {
596
+ const timeZColumnNames = Object.entries(schema).filter(([_, def]) => def.type === "timestamp").map(([name]) => name);
597
+ const timeZColumns = Object.entries(schema).filter(([_, def]) => def.type === "timestamp").map(([name]) => {
598
+ const parsedName = utils.parseSqlIdentifier(name, "column name");
599
+ return `"${parsedName}Z" TIMESTAMPTZ DEFAULT NOW()`;
600
+ });
601
+ const columns = Object.entries(schema).map(([name, def]) => {
602
+ const parsedName = utils.parseSqlIdentifier(name, "column name");
603
+ const constraints = [];
604
+ if (def.primaryKey) constraints.push("PRIMARY KEY");
605
+ if (!def.nullable) constraints.push("NOT NULL");
606
+ const sqlType = this.getSqlType(def.type);
607
+ return `"${parsedName}" ${sqlType} ${constraints.join(" ")}`;
608
+ });
609
+ if (this.schemaName) {
610
+ await this.setupSchema();
611
+ }
612
+ const finalColumns = [...columns, ...timeZColumns].join(",\n");
613
+ const constraintPrefix = this.schemaName ? `${this.schemaName}_` : "";
614
+ const schemaName = getSchemaName(this.schemaName);
615
+ const createTableSql = `
616
+ CREATE TABLE IF NOT EXISTS ${getTableName({ indexName: tableName, schemaName })} (
617
+ ${finalColumns}
618
+ );
619
+ `;
620
+ await this.client.none(createTableSql);
621
+ if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
622
+ const indexName = `${constraintPrefix}mastra_workflow_snapshot_workflow_name_run_id_key`;
623
+ const fullTableName = getTableName({ indexName: tableName, schemaName });
624
+ try {
625
+ const indexExists = await this.client.oneOrNone(`SELECT 1 FROM pg_indexes WHERE indexname = $1`, [
626
+ indexName
627
+ ]);
628
+ if (!indexExists) {
629
+ const result = await this.client.oneOrNone(
630
+ `CREATE UNIQUE INDEX ASYNC "${indexName}" ON ${fullTableName} ("workflow_name", "run_id")`
631
+ );
632
+ if (result?.job_uuid) {
633
+ await this.waitForDSQLJob(result.job_uuid);
634
+ }
635
+ this.logger?.debug?.(`Created unique index ${indexName} on ${fullTableName}`);
636
+ }
637
+ } catch (error) {
638
+ this.logger?.warn?.(`Failed to create unique index ${indexName}:`, error);
639
+ }
640
+ }
641
+ await this.alterTable({
642
+ tableName,
643
+ schema,
644
+ ifNotExists: timeZColumnNames
645
+ });
646
+ if (tableName === storage.TABLE_SPANS) {
647
+ await this.setupTimestampTriggers(tableName);
648
+ await this.migrateSpansTable();
649
+ }
650
+ },
651
+ {
652
+ onRetry: (error, attempt, delay) => {
653
+ this.logger?.warn?.(`createTable retry ${attempt} for ${tableName} after ${delay}ms: ${error.message}`);
654
+ }
655
+ }
656
+ ).catch((error$1) => {
657
+ throw new error.MastraError(
658
+ {
659
+ id: storage.createStorageErrorId("DSQL", "CREATE_TABLE", "FAILED"),
660
+ domain: error.ErrorDomain.STORAGE,
661
+ category: error.ErrorCategory.THIRD_PARTY,
662
+ details: {
663
+ tableName
664
+ }
665
+ },
666
+ error$1
667
+ );
668
+ });
669
+ }
670
+ /**
671
+ * Set up timestamp triggers for a table to automatically manage createdAt/updatedAt
672
+ * Note: Aurora DSQL doesn't support triggers, PL/pgSQL, or CREATE FUNCTION.
673
+ * Timestamps are managed at the application level in insert/update operations.
674
+ * This method is kept as a no-op for API compatibility.
675
+ */
676
+ async setupTimestampTriggers(_tableName) {
677
+ return;
678
+ }
679
+ /**
680
+ * Migrates the spans table schema from OLD_SPAN_SCHEMA to current SPAN_SCHEMA.
681
+ * This adds new columns that don't exist in old schema.
682
+ */
683
+ async migrateSpansTable() {
684
+ const fullTableName = getTableName({ indexName: storage.TABLE_SPANS, schemaName: getSchemaName(this.schemaName) });
685
+ const schema = storage.TABLE_SCHEMAS[storage.TABLE_SPANS];
686
+ try {
687
+ for (const [columnName, columnDef] of Object.entries(schema)) {
688
+ const columnExists = await this.hasColumn(storage.TABLE_SPANS, columnName);
689
+ if (!columnExists) {
690
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
691
+ const sqlType = this.getSqlType(columnDef.type);
692
+ const nullable = columnDef.nullable ? "" : "NOT NULL";
693
+ const defaultValue = !columnDef.nullable ? this.getDefaultValue(columnDef.type) : "";
694
+ const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}" ${sqlType} ${nullable} ${defaultValue}`.trim();
695
+ await this.client.none(alterSql);
696
+ this.logger?.debug?.(`Added column '${columnName}' to ${fullTableName}`);
697
+ if (sqlType === "TIMESTAMP") {
698
+ const timestampZSql = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}Z" TIMESTAMPTZ DEFAULT NOW()`.trim();
699
+ await this.client.none(timestampZSql);
700
+ this.logger?.debug?.(`Added timezone column '${columnName}Z' to ${fullTableName}`);
701
+ }
702
+ }
703
+ }
704
+ for (const [columnName, columnDef] of Object.entries(schema)) {
705
+ if (columnDef.type === "timestamp") {
706
+ const tzColumnName = `${columnName}Z`;
707
+ const tzColumnExists = await this.hasColumn(storage.TABLE_SPANS, tzColumnName);
708
+ if (!tzColumnExists) {
709
+ const parsedTzColumnName = utils.parseSqlIdentifier(tzColumnName, "column name");
710
+ const timestampZSql = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedTzColumnName}" TIMESTAMPTZ DEFAULT NOW()`.trim();
711
+ await this.client.none(timestampZSql);
712
+ this.logger?.debug?.(`Added timezone column '${tzColumnName}' to ${fullTableName}`);
713
+ }
714
+ }
715
+ }
716
+ this.logger?.info?.(`Migration completed for ${fullTableName}`);
717
+ } catch (error) {
718
+ this.logger?.warn?.(`Failed to migrate spans table ${fullTableName}:`, error);
719
+ }
720
+ }
721
+ /**
722
+ * Alters table schema to add columns if they don't exist
723
+ * @param tableName Name of the table
724
+ * @param schema Schema of the table
725
+ * @param ifNotExists Array of column names to add if they don't exist
726
+ */
727
+ async alterTable({
728
+ tableName,
729
+ schema,
730
+ ifNotExists
731
+ }) {
732
+ const fullTableName = getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) });
733
+ try {
734
+ for (const columnName of ifNotExists) {
735
+ if (schema[columnName]) {
736
+ const columnDef = schema[columnName];
737
+ const sqlType = this.getSqlType(columnDef.type);
738
+ const parsedColumnName = utils.parseSqlIdentifier(columnName, "column name");
739
+ const alterSql = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}" ${sqlType}`;
740
+ await this.client.none(alterSql);
741
+ if (sqlType === "TIMESTAMP") {
742
+ const alterSqlZ = `ALTER TABLE ${fullTableName} ADD COLUMN IF NOT EXISTS "${parsedColumnName}Z" TIMESTAMPTZ`;
743
+ await this.client.none(alterSqlZ);
744
+ }
745
+ this.logger?.debug?.(`Ensured column ${parsedColumnName} exists in table ${fullTableName}`);
746
+ }
747
+ }
748
+ } catch (error$1) {
749
+ throw new error.MastraError(
750
+ {
751
+ id: storage.createStorageErrorId("DSQL", "ALTER_TABLE", "FAILED"),
752
+ domain: error.ErrorDomain.STORAGE,
753
+ category: error.ErrorCategory.THIRD_PARTY,
754
+ details: {
755
+ tableName
756
+ }
757
+ },
758
+ error$1
759
+ );
760
+ }
761
+ }
762
+ async load({ tableName, keys }) {
763
+ try {
764
+ const keyEntries = Object.entries(keys).map(([key, value]) => [utils.parseSqlIdentifier(key, "column name"), value]);
765
+ const conditions = keyEntries.map(([key], index) => `"${key}" = $${index + 1}`).join(" AND ");
766
+ const values = keyEntries.map(([_, value]) => value);
767
+ const result = await this.client.oneOrNone(
768
+ `SELECT * FROM ${getTableName({ indexName: tableName, schemaName: getSchemaName(this.schemaName) })} WHERE ${conditions} ORDER BY "createdAt" DESC LIMIT 1`,
769
+ values
770
+ );
771
+ if (!result) {
772
+ return null;
773
+ }
774
+ if (tableName === storage.TABLE_WORKFLOW_SNAPSHOT) {
775
+ const snapshot = result;
776
+ if (typeof snapshot.snapshot === "string") {
777
+ snapshot.snapshot = JSON.parse(snapshot.snapshot);
778
+ }
779
+ return snapshot;
780
+ }
781
+ return result;
782
+ } catch (error$1) {
783
+ throw new error.MastraError(
784
+ {
785
+ id: storage.createStorageErrorId("DSQL", "LOAD", "FAILED"),
786
+ domain: error.ErrorDomain.STORAGE,
787
+ category: error.ErrorCategory.THIRD_PARTY,
788
+ details: {
789
+ tableName
790
+ }
791
+ },
792
+ error$1
793
+ );
794
+ }
795
+ }
796
+ async batchInsert({ tableName, records }) {
797
+ if (records.length === 0) {
798
+ return;
799
+ }
800
+ try {
801
+ const { batches } = splitIntoBatches(records, { maxRows: DEFAULT_MAX_ROWS_PER_BATCH });
802
+ for (const batch of batches) {
803
+ await withRetry(
804
+ async () => {
805
+ await this.client.tx(async (t) => {
806
+ for (const record of batch) {
807
+ this.addTimestampZColumns(record);
808
+ const schemaName = getSchemaName(this.schemaName);
809
+ const columns = Object.keys(record).map((col) => utils.parseSqlIdentifier(col, "column name"));
810
+ const values = this.prepareValuesForInsert(record, tableName);
811
+ const placeholders = values.map((_, i) => `$${i + 1}`).join(", ");
812
+ await t.none(
813
+ `INSERT INTO ${getTableName({ indexName: tableName, schemaName })} (${columns.map((c) => `"${c}"`).join(", ")}) VALUES (${placeholders})`,
814
+ values
815
+ );
816
+ }
817
+ });
818
+ },
819
+ {
820
+ onRetry: (error, attempt, delay) => {
821
+ this.logger?.warn?.(
822
+ `Batch insert retry ${attempt} for table ${tableName} after ${delay}ms: ${error.message}`
823
+ );
824
+ }
825
+ }
826
+ );
827
+ }
828
+ } catch (error$1) {
829
+ throw new error.MastraError(
830
+ {
831
+ id: storage.createStorageErrorId("DSQL", "BATCH_INSERT", "FAILED"),
832
+ domain: error.ErrorDomain.STORAGE,
833
+ category: error.ErrorCategory.THIRD_PARTY,
834
+ details: {
835
+ tableName,
836
+ numberOfRecords: records.length
837
+ }
838
+ },
839
+ error$1
840
+ );
841
+ }
842
+ }
843
+ async dropTable({ tableName }) {
844
+ try {
845
+ const schemaName = getSchemaName(this.schemaName);
846
+ const tableNameWithSchema = getTableName({ indexName: tableName, schemaName });
847
+ await this.client.none(`DROP TABLE IF EXISTS ${tableNameWithSchema}`);
848
+ } catch (error$1) {
849
+ throw new error.MastraError(
850
+ {
851
+ id: storage.createStorageErrorId("DSQL", "DROP_TABLE", "FAILED"),
852
+ domain: error.ErrorDomain.STORAGE,
853
+ category: error.ErrorCategory.THIRD_PARTY,
854
+ details: {
855
+ tableName
856
+ }
857
+ },
858
+ error$1
859
+ );
860
+ }
861
+ }
862
+ /**
863
+ * Wait for an asynchronous DSQL job to complete.
864
+ * Aurora DSQL requires CREATE INDEX ASYNC and sys.wait_for_job() to wait for completion.
865
+ */
866
+ async waitForDSQLJob(jobUuid, timeoutMs = 6e4) {
867
+ const pollIntervalMs = 1e3;
868
+ const startTime = Date.now();
869
+ while (Date.now() - startTime < timeoutMs) {
870
+ const result = await this.client.oneOrNone(`SELECT sys.wait_for_job($1, 1) as status`, [
871
+ jobUuid
872
+ ]);
873
+ if (result?.status === "COMPLETED") {
874
+ return;
875
+ }
876
+ if (result?.status === "FAILED") {
877
+ throw new Error(`DSQL async job ${jobUuid} failed`);
878
+ }
879
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
880
+ }
881
+ throw new Error(`DSQL async job ${jobUuid} timed out after ${timeoutMs}ms`);
882
+ }
883
+ async createIndex(options) {
884
+ try {
885
+ const {
886
+ name,
887
+ table,
888
+ columns,
889
+ unique = false,
890
+ // Note: 'concurrent' option is ignored in DSQL - always uses ASYNC
891
+ where,
892
+ method = "btree",
893
+ opclass,
894
+ storage,
895
+ tablespace
896
+ } = options;
897
+ const schemaName = this.schemaName || "public";
898
+ const fullTableName = getTableName({
899
+ indexName: table,
900
+ schemaName: getSchemaName(this.schemaName)
901
+ });
902
+ const indexExists = await this.client.oneOrNone(
903
+ `SELECT 1 as exists FROM pg_indexes
904
+ WHERE indexname = $1
905
+ AND schemaname = $2`,
906
+ [name, schemaName]
907
+ );
908
+ if (indexExists) {
909
+ return;
910
+ }
911
+ const uniqueStr = unique ? "UNIQUE " : "";
912
+ const methodStr = method !== "btree" ? `USING ${method} ` : "";
913
+ const columnsStr = columns.map((col) => {
914
+ const colName = col.replace(/\s+(DESC|ASC)$/i, "").trim();
915
+ const quotedCol = `"${utils.parseSqlIdentifier(colName, "column name")}"`;
916
+ return opclass ? `${quotedCol} ${opclass}` : quotedCol;
917
+ }).join(", ");
918
+ const whereStr = where ? ` WHERE ${where}` : "";
919
+ const tablespaceStr = tablespace ? ` TABLESPACE ${tablespace}` : "";
920
+ let withStr = "";
921
+ if (storage && Object.keys(storage).length > 0) {
922
+ const storageParams = Object.entries(storage).map(([key, value]) => `${key} = ${value}`).join(", ");
923
+ withStr = ` WITH (${storageParams})`;
924
+ }
925
+ const quotedIndexName = `"${utils.parseSqlIdentifier(name, "index name")}"`;
926
+ const sql = `CREATE ${uniqueStr}INDEX ASYNC ${quotedIndexName} ON ${fullTableName} ${methodStr}(${columnsStr})${withStr}${tablespaceStr}${whereStr}`;
927
+ const result = await this.client.oneOrNone(sql);
928
+ if (result?.job_uuid) {
929
+ await this.waitForDSQLJob(result.job_uuid);
930
+ }
931
+ } catch (error$1) {
932
+ throw new error.MastraError(
933
+ {
934
+ id: storage.createStorageErrorId("DSQL", "INDEX_CREATE", "FAILED"),
935
+ domain: error.ErrorDomain.STORAGE,
936
+ category: error.ErrorCategory.THIRD_PARTY,
937
+ details: {
938
+ indexName: options.name,
939
+ tableName: options.table
940
+ }
941
+ },
942
+ error$1
943
+ );
944
+ }
945
+ }
946
+ async dropIndex(indexName) {
947
+ const schemaName = this.schemaName || "public";
948
+ await withRetry(
949
+ async () => {
950
+ const indexExists = await this.client.oneOrNone(
951
+ `SELECT 1 FROM pg_indexes
952
+ WHERE indexname = $1
953
+ AND schemaname = $2`,
954
+ [indexName, schemaName]
955
+ );
956
+ if (!indexExists) {
957
+ return;
958
+ }
959
+ const quotedIndexName = `"${utils.parseSqlIdentifier(indexName, "index name")}"`;
960
+ const sql = `DROP INDEX IF EXISTS ${getSchemaName(this.schemaName)}.${quotedIndexName}`;
961
+ await this.client.none(sql);
962
+ },
963
+ {
964
+ onRetry: (error, attempt, delay) => {
965
+ this.logger?.warn?.(`dropIndex retry ${attempt} for ${indexName} after ${delay}ms: ${error.message}`);
966
+ }
967
+ }
968
+ ).catch((error$1) => {
969
+ throw new error.MastraError(
970
+ {
971
+ id: storage.createStorageErrorId("DSQL", "INDEX_DROP", "FAILED"),
972
+ domain: error.ErrorDomain.STORAGE,
973
+ category: error.ErrorCategory.THIRD_PARTY,
974
+ details: {
975
+ indexName
976
+ }
977
+ },
978
+ error$1
979
+ );
980
+ });
981
+ }
982
+ async listIndexes(tableName) {
983
+ try {
984
+ const schemaName = this.schemaName || "public";
985
+ let query;
986
+ let params;
987
+ if (tableName) {
988
+ query = `
989
+ SELECT
990
+ i.indexname as name,
991
+ i.tablename as table,
992
+ i.indexdef as definition,
993
+ ix.indisunique as is_unique,
994
+ pg_size_pretty(pg_relation_size(c.oid)) as size,
995
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns
996
+ FROM pg_indexes i
997
+ JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
998
+ JOIN pg_index ix ON ix.indexrelid = c.oid
999
+ JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
1000
+ WHERE i.schemaname = $1
1001
+ AND i.tablename = $2
1002
+ GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
1003
+ `;
1004
+ params = [schemaName, tableName];
1005
+ } else {
1006
+ query = `
1007
+ SELECT
1008
+ i.indexname as name,
1009
+ i.tablename as table,
1010
+ i.indexdef as definition,
1011
+ ix.indisunique as is_unique,
1012
+ pg_size_pretty(pg_relation_size(c.oid)) as size,
1013
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns
1014
+ FROM pg_indexes i
1015
+ JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
1016
+ JOIN pg_index ix ON ix.indexrelid = c.oid
1017
+ JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
1018
+ WHERE i.schemaname = $1
1019
+ GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid
1020
+ `;
1021
+ params = [schemaName];
1022
+ }
1023
+ const results = await this.client.manyOrNone(query, params);
1024
+ return results.map((row) => {
1025
+ let columns = [];
1026
+ if (typeof row.columns === "string" && row.columns.startsWith("{") && row.columns.endsWith("}")) {
1027
+ const arrayContent = row.columns.slice(1, -1);
1028
+ columns = arrayContent ? arrayContent.split(",") : [];
1029
+ } else if (Array.isArray(row.columns)) {
1030
+ columns = row.columns;
1031
+ }
1032
+ return {
1033
+ name: row.name,
1034
+ table: row.table,
1035
+ columns,
1036
+ unique: row.is_unique || false,
1037
+ size: row.size || "0",
1038
+ definition: row.definition || ""
1039
+ };
1040
+ });
1041
+ } catch (error$1) {
1042
+ throw new error.MastraError(
1043
+ {
1044
+ id: storage.createStorageErrorId("DSQL", "INDEX_LIST", "FAILED"),
1045
+ domain: error.ErrorDomain.STORAGE,
1046
+ category: error.ErrorCategory.THIRD_PARTY,
1047
+ details: tableName ? {
1048
+ tableName
1049
+ } : {}
1050
+ },
1051
+ error$1
1052
+ );
1053
+ }
1054
+ }
1055
+ async describeIndex(indexName) {
1056
+ try {
1057
+ const schemaName = this.schemaName || "public";
1058
+ const query = `
1059
+ SELECT
1060
+ i.indexname as name,
1061
+ i.tablename as table,
1062
+ i.indexdef as definition,
1063
+ ix.indisunique as is_unique,
1064
+ pg_size_pretty(pg_relation_size(c.oid)) as size,
1065
+ array_agg(a.attname ORDER BY array_position(ix.indkey, a.attnum)) as columns,
1066
+ am.amname as method,
1067
+ s.idx_scan as scans,
1068
+ s.idx_tup_read as tuples_read,
1069
+ s.idx_tup_fetch as tuples_fetched
1070
+ FROM pg_indexes i
1071
+ JOIN pg_class c ON c.relname = i.indexname AND c.relnamespace = (SELECT oid FROM pg_namespace WHERE nspname = i.schemaname)
1072
+ JOIN pg_index ix ON ix.indexrelid = c.oid
1073
+ JOIN pg_attribute a ON a.attrelid = ix.indrelid AND a.attnum = ANY(ix.indkey)
1074
+ JOIN pg_am am ON c.relam = am.oid
1075
+ LEFT JOIN pg_stat_user_indexes s ON s.indexrelname = i.indexname AND s.schemaname = i.schemaname
1076
+ WHERE i.schemaname = $1
1077
+ AND i.indexname = $2
1078
+ GROUP BY i.indexname, i.tablename, i.indexdef, ix.indisunique, c.oid, am.amname, s.idx_scan, s.idx_tup_read, s.idx_tup_fetch
1079
+ `;
1080
+ const result = await this.client.oneOrNone(query, [schemaName, indexName]);
1081
+ if (!result) {
1082
+ throw new Error(`Index "${indexName}" not found in schema "${schemaName}"`);
1083
+ }
1084
+ let columns = [];
1085
+ if (typeof result.columns === "string" && result.columns.startsWith("{") && result.columns.endsWith("}")) {
1086
+ const arrayContent = result.columns.slice(1, -1);
1087
+ columns = arrayContent ? arrayContent.split(",") : [];
1088
+ } else if (Array.isArray(result.columns)) {
1089
+ columns = result.columns;
1090
+ }
1091
+ const normalizedMethod = result.method === "btree_index" ? "btree" : result.method || "btree";
1092
+ return {
1093
+ name: result.name,
1094
+ table: result.table,
1095
+ columns,
1096
+ unique: result.is_unique || false,
1097
+ size: result.size || "0",
1098
+ definition: result.definition || "",
1099
+ method: normalizedMethod,
1100
+ scans: parseInt(result.scans) || 0,
1101
+ tuples_read: parseInt(result.tuples_read) || 0,
1102
+ tuples_fetched: parseInt(result.tuples_fetched) || 0
1103
+ };
1104
+ } catch (error$1) {
1105
+ throw new error.MastraError(
1106
+ {
1107
+ id: storage.createStorageErrorId("DSQL", "INDEX_DESCRIBE", "FAILED"),
1108
+ domain: error.ErrorDomain.STORAGE,
1109
+ category: error.ErrorCategory.THIRD_PARTY,
1110
+ details: {
1111
+ indexName
1112
+ }
1113
+ },
1114
+ error$1
1115
+ );
1116
+ }
1117
+ }
1118
+ async update({
1119
+ tableName,
1120
+ keys,
1121
+ data
1122
+ }) {
1123
+ const setColumns = [];
1124
+ const setValues = [];
1125
+ let paramIndex = 1;
1126
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1127
+ const dataWithTimestamp = {
1128
+ ...data,
1129
+ updatedAt: now,
1130
+ updatedAtZ: now
1131
+ };
1132
+ Object.entries(dataWithTimestamp).forEach(([key, value]) => {
1133
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1134
+ setColumns.push(`"${parsedKey}" = $${paramIndex++}`);
1135
+ setValues.push(this.prepareValue(value, key, tableName));
1136
+ });
1137
+ const whereConditions = [];
1138
+ const whereValues = [];
1139
+ Object.entries(keys).forEach(([key, value]) => {
1140
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1141
+ whereConditions.push(`"${parsedKey}" = $${paramIndex++}`);
1142
+ whereValues.push(this.prepareValue(value, key, tableName));
1143
+ });
1144
+ const tableName_ = getTableName({
1145
+ indexName: tableName,
1146
+ schemaName: getSchemaName(this.schemaName)
1147
+ });
1148
+ const sql = `UPDATE ${tableName_} SET ${setColumns.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
1149
+ const values = [...setValues, ...whereValues];
1150
+ await withRetry(
1151
+ async () => {
1152
+ await this.client.none(sql, values);
1153
+ },
1154
+ {
1155
+ onRetry: (error, attempt, delay) => {
1156
+ this.logger?.warn?.(`update retry ${attempt} for table ${tableName} after ${delay}ms: ${error.message}`);
1157
+ }
1158
+ }
1159
+ ).catch((error$1) => {
1160
+ throw new error.MastraError(
1161
+ {
1162
+ id: storage.createStorageErrorId("DSQL", "UPDATE", "FAILED"),
1163
+ domain: error.ErrorDomain.STORAGE,
1164
+ category: error.ErrorCategory.THIRD_PARTY,
1165
+ details: {
1166
+ tableName
1167
+ }
1168
+ },
1169
+ error$1
1170
+ );
1171
+ });
1172
+ }
1173
+ async batchUpdate({
1174
+ tableName,
1175
+ updates
1176
+ }) {
1177
+ if (updates.length === 0) {
1178
+ return;
1179
+ }
1180
+ try {
1181
+ const { batches } = splitIntoBatches(updates, { maxRows: DEFAULT_MAX_ROWS_PER_BATCH });
1182
+ for (const batch of batches) {
1183
+ await withRetry(
1184
+ async () => {
1185
+ await this.client.tx(async (t) => {
1186
+ for (const { keys, data } of batch) {
1187
+ const setClauses = [];
1188
+ const whereConditions = [];
1189
+ const values = [];
1190
+ let paramIndex = 1;
1191
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1192
+ const dataWithTimestamp = {
1193
+ ...data,
1194
+ updatedAt: now,
1195
+ updatedAtZ: now
1196
+ };
1197
+ Object.entries(dataWithTimestamp).forEach(([key, value]) => {
1198
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1199
+ const preparedValue = this.prepareValue(value, key, tableName);
1200
+ setClauses.push(`"${parsedKey}" = $${paramIndex++}`);
1201
+ values.push(preparedValue);
1202
+ });
1203
+ Object.entries(keys).forEach(([key, value]) => {
1204
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1205
+ whereConditions.push(`"${parsedKey}" = $${paramIndex++}`);
1206
+ values.push(value);
1207
+ });
1208
+ const tableName_ = getTableName({
1209
+ indexName: tableName,
1210
+ schemaName: getSchemaName(this.schemaName)
1211
+ });
1212
+ const sql = `UPDATE ${tableName_} SET ${setClauses.join(", ")} WHERE ${whereConditions.join(" AND ")}`;
1213
+ await t.none(sql, values);
1214
+ }
1215
+ });
1216
+ },
1217
+ {
1218
+ onRetry: (error, attempt, delay) => {
1219
+ this.logger?.warn?.(
1220
+ `Batch update retry ${attempt} for table ${tableName} after ${delay}ms: ${error.message}`
1221
+ );
1222
+ }
1223
+ }
1224
+ );
1225
+ }
1226
+ } catch (error$1) {
1227
+ throw new error.MastraError(
1228
+ {
1229
+ id: storage.createStorageErrorId("DSQL", "BATCH_UPDATE", "FAILED"),
1230
+ domain: error.ErrorDomain.STORAGE,
1231
+ category: error.ErrorCategory.THIRD_PARTY,
1232
+ details: {
1233
+ tableName,
1234
+ numberOfRecords: updates.length
1235
+ }
1236
+ },
1237
+ error$1
1238
+ );
1239
+ }
1240
+ }
1241
+ async batchDelete({ tableName, keys }) {
1242
+ if (keys.length === 0) {
1243
+ return;
1244
+ }
1245
+ try {
1246
+ const tableName_ = getTableName({
1247
+ indexName: tableName,
1248
+ schemaName: getSchemaName(this.schemaName)
1249
+ });
1250
+ const { batches } = splitIntoBatches(keys, { maxRows: DEFAULT_MAX_ROWS_PER_BATCH });
1251
+ for (const batch of batches) {
1252
+ await withRetry(
1253
+ async () => {
1254
+ await this.client.tx(async (t) => {
1255
+ for (const keySet of batch) {
1256
+ const conditions = [];
1257
+ const values = [];
1258
+ let paramIndex = 1;
1259
+ Object.entries(keySet).forEach(([key, value]) => {
1260
+ const parsedKey = utils.parseSqlIdentifier(key, "column name");
1261
+ conditions.push(`"${parsedKey}" = $${paramIndex++}`);
1262
+ values.push(value);
1263
+ });
1264
+ const sql = `DELETE FROM ${tableName_} WHERE ${conditions.join(" AND ")}`;
1265
+ await t.none(sql, values);
1266
+ }
1267
+ });
1268
+ },
1269
+ {
1270
+ onRetry: (error, attempt, delay) => {
1271
+ this.logger?.warn?.(
1272
+ `Batch delete retry ${attempt} for table ${tableName} after ${delay}ms: ${error.message}`
1273
+ );
1274
+ }
1275
+ }
1276
+ );
1277
+ }
1278
+ } catch (error$1) {
1279
+ throw new error.MastraError(
1280
+ {
1281
+ id: storage.createStorageErrorId("DSQL", "BATCH_DELETE", "FAILED"),
1282
+ domain: error.ErrorDomain.STORAGE,
1283
+ category: error.ErrorCategory.THIRD_PARTY,
1284
+ details: {
1285
+ tableName,
1286
+ numberOfRecords: keys.length
1287
+ }
1288
+ },
1289
+ error$1
1290
+ );
1291
+ }
1292
+ }
1293
+ /**
1294
+ * Delete all data from a table (alias for clearTable for consistency with other stores)
1295
+ */
1296
+ async deleteData({ tableName }) {
1297
+ return this.clearTable({ tableName });
1298
+ }
1299
+ };
1300
+ function getSchemaName2(schema) {
1301
+ return schema ? `"${utils.parseSqlIdentifier(schema, "schema name")}"` : void 0;
1302
+ }
1303
+ function getTableName2({ indexName, schemaName }) {
1304
+ const parsedIndexName = utils.parseSqlIdentifier(indexName, "index name");
1305
+ const quotedIndexName = `"${parsedIndexName}"`;
1306
+ const quotedSchemaName = schemaName;
1307
+ return quotedSchemaName ? `${quotedSchemaName}.${quotedIndexName}` : quotedIndexName;
1308
+ }
1309
+ function transformFromSqlRow({
1310
+ tableName,
1311
+ sqlRow
1312
+ }) {
1313
+ const schema = storage.TABLE_SCHEMAS[tableName];
1314
+ const result = {};
1315
+ Object.entries(sqlRow).forEach(([key, value]) => {
1316
+ const columnSchema = schema?.[key];
1317
+ if (columnSchema?.type === "jsonb" && typeof value === "string") {
1318
+ try {
1319
+ result[key] = JSON.parse(value);
1320
+ } catch {
1321
+ result[key] = value;
1322
+ }
1323
+ } else if (columnSchema?.type === "timestamp" && value && typeof value === "string") {
1324
+ result[key] = new Date(value);
1325
+ } else if (columnSchema?.type === "timestamp" && value instanceof Date) {
1326
+ result[key] = value;
1327
+ } else if (columnSchema?.type === "boolean") {
1328
+ result[key] = Boolean(value);
1329
+ } else {
1330
+ result[key] = value;
1331
+ }
1332
+ });
1333
+ return result;
1334
+ }
1335
+
1336
+ // src/storage/domains/agents/index.ts
1337
+ var AgentsDSQL = class _AgentsDSQL extends storage.AgentsStorage {
1338
+ #db;
1339
+ #schema;
1340
+ #skipDefaultIndexes;
1341
+ #indexes;
1342
+ /** Tables managed by this domain */
1343
+ static MANAGED_TABLES = [storage.TABLE_AGENTS, storage.TABLE_AGENT_VERSIONS];
1344
+ constructor(config) {
1345
+ super();
1346
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolveDsqlConfig(config);
1347
+ this.#db = new DsqlDB({ client, schemaName, skipDefaultIndexes });
1348
+ this.#schema = schemaName || "public";
1349
+ this.#skipDefaultIndexes = skipDefaultIndexes;
1350
+ this.#indexes = indexes?.filter((idx) => _AgentsDSQL.MANAGED_TABLES.includes(idx.table));
1351
+ }
1352
+ /**
1353
+ * Returns default index definitions for the agents domain tables.
1354
+ * Currently no default indexes are defined for agents.
1355
+ */
1356
+ getDefaultIndexDefinitions() {
1357
+ return [];
1358
+ }
1359
+ /**
1360
+ * Creates default indexes for optimal query performance.
1361
+ * Currently no default indexes are defined for agents.
1362
+ */
1363
+ async createDefaultIndexes() {
1364
+ if (this.#skipDefaultIndexes) {
1365
+ return;
1366
+ }
1367
+ }
1368
+ async init() {
1369
+ await this.#db.createTable({ tableName: storage.TABLE_AGENTS, schema: storage.TABLE_SCHEMAS[storage.TABLE_AGENTS] });
1370
+ await this.#db.createTable({ tableName: storage.TABLE_AGENT_VERSIONS, schema: storage.TABLE_SCHEMAS[storage.TABLE_AGENT_VERSIONS] });
1371
+ await this.createDefaultIndexes();
1372
+ await this.createCustomIndexes();
1373
+ }
1374
+ /**
1375
+ * Creates custom user-defined indexes for this domain's tables.
1376
+ */
1377
+ async createCustomIndexes() {
1378
+ if (!this.#indexes || this.#indexes.length === 0) {
1379
+ return;
1380
+ }
1381
+ for (const indexDef of this.#indexes) {
1382
+ try {
1383
+ await this.#db.createIndex(indexDef);
1384
+ } catch (error) {
1385
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
1386
+ }
1387
+ }
1388
+ }
1389
+ async dangerouslyClearAll() {
1390
+ await this.#db.clearTable({ tableName: storage.TABLE_AGENT_VERSIONS });
1391
+ await this.#db.clearTable({ tableName: storage.TABLE_AGENTS });
1392
+ }
1393
+ parseJson(value, fieldName) {
1394
+ if (!value) return void 0;
1395
+ if (typeof value !== "string") return value;
1396
+ try {
1397
+ return JSON.parse(value);
1398
+ } catch (error$1) {
1399
+ const details = {
1400
+ value: value.length > 100 ? value.substring(0, 100) + "..." : value
1401
+ };
1402
+ if (fieldName) {
1403
+ details.field = fieldName;
1404
+ }
1405
+ throw new error.MastraError(
1406
+ {
1407
+ id: storage.createStorageErrorId("DSQL", "PARSE_JSON", "INVALID_JSON"),
1408
+ domain: error.ErrorDomain.STORAGE,
1409
+ category: error.ErrorCategory.SYSTEM,
1410
+ text: `Failed to parse JSON${fieldName ? ` for field "${fieldName}"` : ""}: ${error$1 instanceof Error ? error$1.message : "Unknown error"}`,
1411
+ details
1412
+ },
1413
+ error$1
1414
+ );
1415
+ }
1416
+ }
1417
+ parseRow(row) {
1418
+ return {
1419
+ id: row.id,
1420
+ status: row.status,
1421
+ activeVersionId: row.activeVersionId,
1422
+ authorId: row.authorId,
1423
+ metadata: this.parseJson(row.metadata, "metadata"),
1424
+ createdAt: row.createdAtZ || row.createdAt,
1425
+ updatedAt: row.updatedAtZ || row.updatedAt
1426
+ };
1427
+ }
1428
+ async getById(id) {
1429
+ try {
1430
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENTS, schemaName: getSchemaName2(this.#schema) });
1431
+ const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
1432
+ if (!result) {
1433
+ return null;
1434
+ }
1435
+ return this.parseRow(result);
1436
+ } catch (error$1) {
1437
+ if (error$1 instanceof error.MastraError) throw error$1;
1438
+ throw new error.MastraError(
1439
+ {
1440
+ id: storage.createStorageErrorId("DSQL", "GET_AGENT_BY_ID", "FAILED"),
1441
+ domain: error.ErrorDomain.STORAGE,
1442
+ category: error.ErrorCategory.THIRD_PARTY,
1443
+ details: { agentId: id }
1444
+ },
1445
+ error$1
1446
+ );
1447
+ }
1448
+ }
1449
+ async create(input) {
1450
+ const { agent } = input;
1451
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENTS, schemaName: getSchemaName2(this.#schema) });
1452
+ const now = /* @__PURE__ */ new Date();
1453
+ const nowIso = now.toISOString();
1454
+ try {
1455
+ await withRetry(
1456
+ () => this.#db.client.none(
1457
+ `INSERT INTO ${tableName} (
1458
+ id, status, "authorId", metadata,
1459
+ "activeVersionId",
1460
+ "createdAt", "createdAtZ", "updatedAt", "updatedAtZ"
1461
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)`,
1462
+ [
1463
+ agent.id,
1464
+ "draft",
1465
+ agent.authorId ?? null,
1466
+ agent.metadata ? JSON.stringify(agent.metadata) : null,
1467
+ null,
1468
+ // activeVersionId starts as null
1469
+ nowIso,
1470
+ nowIso,
1471
+ nowIso,
1472
+ nowIso
1473
+ ]
1474
+ )
1475
+ );
1476
+ const { id: _id, authorId: _authorId, metadata: _metadata, ...snapshotConfig } = agent;
1477
+ const versionId = crypto.randomUUID();
1478
+ await this.createVersion({
1479
+ id: versionId,
1480
+ agentId: agent.id,
1481
+ versionNumber: 1,
1482
+ ...snapshotConfig,
1483
+ changedFields: Object.keys(snapshotConfig),
1484
+ changeMessage: "Initial version"
1485
+ });
1486
+ return {
1487
+ id: agent.id,
1488
+ status: "draft",
1489
+ activeVersionId: void 0,
1490
+ authorId: agent.authorId,
1491
+ metadata: agent.metadata,
1492
+ createdAt: now,
1493
+ updatedAt: now
1494
+ };
1495
+ } catch (error$1) {
1496
+ if (error$1 instanceof error.MastraError) throw error$1;
1497
+ try {
1498
+ await this.#db.client.none(
1499
+ `DELETE FROM ${tableName} WHERE id = $1 AND status = 'draft' AND "activeVersionId" IS NULL`,
1500
+ [agent.id]
1501
+ );
1502
+ } catch {
1503
+ }
1504
+ throw new error.MastraError(
1505
+ {
1506
+ id: storage.createStorageErrorId("DSQL", "CREATE_AGENT", "FAILED"),
1507
+ domain: error.ErrorDomain.STORAGE,
1508
+ category: error.ErrorCategory.THIRD_PARTY,
1509
+ details: { agentId: agent.id }
1510
+ },
1511
+ error$1
1512
+ );
1513
+ }
1514
+ }
1515
+ async update(input) {
1516
+ const { id, ...updates } = input;
1517
+ try {
1518
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENTS, schemaName: getSchemaName2(this.#schema) });
1519
+ const existingAgent = await this.getById(id);
1520
+ if (!existingAgent) {
1521
+ throw new error.MastraError({
1522
+ id: storage.createStorageErrorId("DSQL", "UPDATE_AGENT", "NOT_FOUND"),
1523
+ domain: error.ErrorDomain.STORAGE,
1524
+ category: error.ErrorCategory.USER,
1525
+ text: `Agent ${id} not found`,
1526
+ details: { agentId: id }
1527
+ });
1528
+ }
1529
+ const { authorId, activeVersionId, metadata, status } = updates;
1530
+ const setClauses = [];
1531
+ const values = [];
1532
+ let paramIndex = 1;
1533
+ if (authorId !== void 0) {
1534
+ setClauses.push(`"authorId" = $${paramIndex++}`);
1535
+ values.push(authorId);
1536
+ }
1537
+ if (activeVersionId !== void 0) {
1538
+ setClauses.push(`"activeVersionId" = $${paramIndex++}`);
1539
+ values.push(activeVersionId);
1540
+ }
1541
+ if (status !== void 0) {
1542
+ setClauses.push(`status = $${paramIndex++}`);
1543
+ values.push(status);
1544
+ }
1545
+ if (metadata !== void 0) {
1546
+ setClauses.push(`metadata = $${paramIndex++}`);
1547
+ values.push(JSON.stringify(metadata));
1548
+ }
1549
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1550
+ setClauses.push(`"updatedAt" = $${paramIndex++}`);
1551
+ values.push(now);
1552
+ setClauses.push(`"updatedAtZ" = $${paramIndex++}`);
1553
+ values.push(now);
1554
+ values.push(id);
1555
+ await withRetry(
1556
+ () => this.#db.client.none(`UPDATE ${tableName} SET ${setClauses.join(", ")} WHERE id = ${paramIndex}`, values)
1557
+ );
1558
+ const updatedAgent = await this.getById(id);
1559
+ if (!updatedAgent) {
1560
+ throw new error.MastraError({
1561
+ id: storage.createStorageErrorId("DSQL", "UPDATE_AGENT", "NOT_FOUND_AFTER_UPDATE"),
1562
+ domain: error.ErrorDomain.STORAGE,
1563
+ category: error.ErrorCategory.SYSTEM,
1564
+ text: `Agent ${id} not found after update`,
1565
+ details: { agentId: id }
1566
+ });
1567
+ }
1568
+ return updatedAgent;
1569
+ } catch (error$1) {
1570
+ if (error$1 instanceof error.MastraError) throw error$1;
1571
+ throw new error.MastraError(
1572
+ {
1573
+ id: storage.createStorageErrorId("DSQL", "UPDATE_AGENT", "FAILED"),
1574
+ domain: error.ErrorDomain.STORAGE,
1575
+ category: error.ErrorCategory.THIRD_PARTY,
1576
+ details: { agentId: id }
1577
+ },
1578
+ error$1
1579
+ );
1580
+ }
1581
+ }
1582
+ async delete(id) {
1583
+ try {
1584
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENTS, schemaName: getSchemaName2(this.#schema) });
1585
+ await this.deleteVersionsByParentId(id);
1586
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1`, [id]);
1587
+ } catch (error$1) {
1588
+ if (error$1 instanceof error.MastraError) throw error$1;
1589
+ throw new error.MastraError(
1590
+ {
1591
+ id: storage.createStorageErrorId("DSQL", "DELETE_AGENT", "FAILED"),
1592
+ domain: error.ErrorDomain.STORAGE,
1593
+ category: error.ErrorCategory.THIRD_PARTY,
1594
+ details: { agentId: id }
1595
+ },
1596
+ error$1
1597
+ );
1598
+ }
1599
+ }
1600
+ async list(args) {
1601
+ const { page = 0, perPage: perPageInput, orderBy, authorId, metadata, status } = args || {};
1602
+ const { field, direction } = this.parseOrderBy(orderBy);
1603
+ if (page < 0) {
1604
+ throw new error.MastraError(
1605
+ {
1606
+ id: storage.createStorageErrorId("DSQL", "LIST_AGENTS", "INVALID_PAGE"),
1607
+ domain: error.ErrorDomain.STORAGE,
1608
+ category: error.ErrorCategory.USER,
1609
+ details: { page }
1610
+ },
1611
+ new Error("page must be >= 0")
1612
+ );
1613
+ }
1614
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1615
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1616
+ try {
1617
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENTS, schemaName: getSchemaName2(this.#schema) });
1618
+ const conditions = [];
1619
+ const queryParams = [];
1620
+ let paramIdx = 1;
1621
+ if (status) {
1622
+ conditions.push(`status = $${paramIdx++}`);
1623
+ queryParams.push(status);
1624
+ }
1625
+ if (authorId !== void 0) {
1626
+ conditions.push(`"authorId" = $${paramIdx++}`);
1627
+ queryParams.push(authorId);
1628
+ }
1629
+ if (metadata && Object.keys(metadata).length > 0) {
1630
+ conditions.push(`metadata::text = $${paramIdx++}`);
1631
+ queryParams.push(JSON.stringify(metadata));
1632
+ }
1633
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1634
+ const countResult = await this.#db.client.one(
1635
+ `SELECT COUNT(*) as count FROM ${tableName} ${whereClause}`,
1636
+ queryParams
1637
+ );
1638
+ const total = parseInt(countResult.count, 10);
1639
+ if (total === 0) {
1640
+ return {
1641
+ agents: [],
1642
+ total: 0,
1643
+ page,
1644
+ perPage: perPageForResponse,
1645
+ hasMore: false
1646
+ };
1647
+ }
1648
+ const limitValue = perPageInput === false ? total : perPage;
1649
+ const dataResult = await this.#db.client.manyOrNone(
1650
+ `SELECT * FROM ${tableName} ${whereClause} ORDER BY "${field}" ${direction} LIMIT $${paramIdx++} OFFSET $${paramIdx++}`,
1651
+ [...queryParams, limitValue, offset]
1652
+ );
1653
+ const agents = (dataResult || []).map((row) => this.parseRow(row));
1654
+ return {
1655
+ agents,
1656
+ total,
1657
+ page,
1658
+ perPage: perPageForResponse,
1659
+ hasMore: perPageInput === false ? false : offset + perPage < total
1660
+ };
1661
+ } catch (error$1) {
1662
+ if (error$1 instanceof error.MastraError) throw error$1;
1663
+ throw new error.MastraError(
1664
+ {
1665
+ id: storage.createStorageErrorId("DSQL", "LIST_AGENTS", "FAILED"),
1666
+ domain: error.ErrorDomain.STORAGE,
1667
+ category: error.ErrorCategory.THIRD_PARTY
1668
+ },
1669
+ error$1
1670
+ );
1671
+ }
1672
+ }
1673
+ // ==========================================================================
1674
+ // Agent Version Methods
1675
+ // ==========================================================================
1676
+ async createVersion(input) {
1677
+ try {
1678
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1679
+ const now = /* @__PURE__ */ new Date();
1680
+ const nowIso = now.toISOString();
1681
+ await withRetry(
1682
+ () => this.#db.client.none(
1683
+ `INSERT INTO ${tableName} (
1684
+ id, "agentId", "versionNumber",
1685
+ name, description, instructions, model, tools,
1686
+ "defaultOptions", workflows, agents, "integrationTools",
1687
+ "inputProcessors", "outputProcessors", memory, scorers,
1688
+ "mcpClients", "requestContextSchema", workspace, skills, "skillsFormat",
1689
+ "changedFields", "changeMessage",
1690
+ "createdAt", "createdAtZ"
1691
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15, $16, $17, $18, $19, $20, $21, $22, $23, $24, $25)`,
1692
+ [
1693
+ input.id,
1694
+ input.agentId,
1695
+ input.versionNumber,
1696
+ input.name,
1697
+ input.description ?? null,
1698
+ this.serializeInstructions(input.instructions),
1699
+ JSON.stringify(input.model),
1700
+ input.tools ? JSON.stringify(input.tools) : null,
1701
+ input.defaultOptions ? JSON.stringify(input.defaultOptions) : null,
1702
+ input.workflows ? JSON.stringify(input.workflows) : null,
1703
+ input.agents ? JSON.stringify(input.agents) : null,
1704
+ input.integrationTools ? JSON.stringify(input.integrationTools) : null,
1705
+ input.inputProcessors ? JSON.stringify(input.inputProcessors) : null,
1706
+ input.outputProcessors ? JSON.stringify(input.outputProcessors) : null,
1707
+ input.memory ? JSON.stringify(input.memory) : null,
1708
+ input.scorers ? JSON.stringify(input.scorers) : null,
1709
+ input.mcpClients ? JSON.stringify(input.mcpClients) : null,
1710
+ input.requestContextSchema ? JSON.stringify(input.requestContextSchema) : null,
1711
+ input.workspace ? JSON.stringify(input.workspace) : null,
1712
+ input.skills ? JSON.stringify(input.skills) : null,
1713
+ input.skillsFormat ?? null,
1714
+ input.changedFields ? JSON.stringify(input.changedFields) : null,
1715
+ input.changeMessage ?? null,
1716
+ nowIso,
1717
+ nowIso
1718
+ ]
1719
+ )
1720
+ );
1721
+ return {
1722
+ ...input,
1723
+ createdAt: now
1724
+ };
1725
+ } catch (error$1) {
1726
+ if (error$1 instanceof error.MastraError) throw error$1;
1727
+ throw new error.MastraError(
1728
+ {
1729
+ id: storage.createStorageErrorId("DSQL", "CREATE_VERSION", "FAILED"),
1730
+ domain: error.ErrorDomain.STORAGE,
1731
+ category: error.ErrorCategory.THIRD_PARTY,
1732
+ details: { versionId: input.id, agentId: input.agentId }
1733
+ },
1734
+ error$1
1735
+ );
1736
+ }
1737
+ }
1738
+ async getVersion(id) {
1739
+ try {
1740
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1741
+ const result = await this.#db.client.oneOrNone(`SELECT * FROM ${tableName} WHERE id = $1`, [id]);
1742
+ if (!result) {
1743
+ return null;
1744
+ }
1745
+ return this.parseVersionRow(result);
1746
+ } catch (error$1) {
1747
+ if (error$1 instanceof error.MastraError) throw error$1;
1748
+ throw new error.MastraError(
1749
+ {
1750
+ id: storage.createStorageErrorId("DSQL", "GET_VERSION", "FAILED"),
1751
+ domain: error.ErrorDomain.STORAGE,
1752
+ category: error.ErrorCategory.THIRD_PARTY,
1753
+ details: { versionId: id }
1754
+ },
1755
+ error$1
1756
+ );
1757
+ }
1758
+ }
1759
+ async getVersionByNumber(agentId, versionNumber) {
1760
+ try {
1761
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1762
+ const result = await this.#db.client.oneOrNone(
1763
+ `SELECT * FROM ${tableName} WHERE "agentId" = $1 AND "versionNumber" = $2`,
1764
+ [agentId, versionNumber]
1765
+ );
1766
+ if (!result) {
1767
+ return null;
1768
+ }
1769
+ return this.parseVersionRow(result);
1770
+ } catch (error$1) {
1771
+ if (error$1 instanceof error.MastraError) throw error$1;
1772
+ throw new error.MastraError(
1773
+ {
1774
+ id: storage.createStorageErrorId("DSQL", "GET_VERSION_BY_NUMBER", "FAILED"),
1775
+ domain: error.ErrorDomain.STORAGE,
1776
+ category: error.ErrorCategory.THIRD_PARTY,
1777
+ details: { agentId, versionNumber }
1778
+ },
1779
+ error$1
1780
+ );
1781
+ }
1782
+ }
1783
+ async getLatestVersion(agentId) {
1784
+ try {
1785
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1786
+ const result = await this.#db.client.oneOrNone(
1787
+ `SELECT * FROM ${tableName} WHERE "agentId" = $1 ORDER BY "versionNumber" DESC LIMIT 1`,
1788
+ [agentId]
1789
+ );
1790
+ if (!result) {
1791
+ return null;
1792
+ }
1793
+ return this.parseVersionRow(result);
1794
+ } catch (error$1) {
1795
+ if (error$1 instanceof error.MastraError) throw error$1;
1796
+ throw new error.MastraError(
1797
+ {
1798
+ id: storage.createStorageErrorId("DSQL", "GET_LATEST_VERSION", "FAILED"),
1799
+ domain: error.ErrorDomain.STORAGE,
1800
+ category: error.ErrorCategory.THIRD_PARTY,
1801
+ details: { agentId }
1802
+ },
1803
+ error$1
1804
+ );
1805
+ }
1806
+ }
1807
+ async listVersions(input) {
1808
+ const { agentId, page = 0, perPage: perPageInput, orderBy } = input;
1809
+ const perPage = storage.normalizePerPage(perPageInput, 100);
1810
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
1811
+ const sortField = orderBy?.field || "versionNumber";
1812
+ const sortDirection = orderBy?.direction || "DESC";
1813
+ try {
1814
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1815
+ const countResult = await this.#db.client.one(`SELECT COUNT(*) as count FROM ${tableName} WHERE "agentId" = $1`, [
1816
+ agentId
1817
+ ]);
1818
+ const total = parseInt(countResult.count, 10);
1819
+ if (total === 0) {
1820
+ return {
1821
+ versions: [],
1822
+ total: 0,
1823
+ page,
1824
+ perPage: perPageForResponse,
1825
+ hasMore: false
1826
+ };
1827
+ }
1828
+ const limitValue = perPageInput === false ? total : perPage;
1829
+ const rows = await this.#db.client.manyOrNone(
1830
+ `SELECT * FROM ${tableName} WHERE "agentId" = $1 ORDER BY "${sortField}" ${sortDirection} LIMIT $2 OFFSET $3`,
1831
+ [agentId, limitValue, offset]
1832
+ );
1833
+ const versions = (rows || []).map((row) => this.parseVersionRow(row));
1834
+ return {
1835
+ versions,
1836
+ total,
1837
+ page,
1838
+ perPage: perPageForResponse,
1839
+ hasMore: perPageInput === false ? false : offset + perPage < total
1840
+ };
1841
+ } catch (error$1) {
1842
+ if (error$1 instanceof error.MastraError) throw error$1;
1843
+ throw new error.MastraError(
1844
+ {
1845
+ id: storage.createStorageErrorId("DSQL", "LIST_VERSIONS", "FAILED"),
1846
+ domain: error.ErrorDomain.STORAGE,
1847
+ category: error.ErrorCategory.THIRD_PARTY,
1848
+ details: { agentId }
1849
+ },
1850
+ error$1
1851
+ );
1852
+ }
1853
+ }
1854
+ async deleteVersion(id) {
1855
+ try {
1856
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1857
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE id = $1`, [id]);
1858
+ } catch (error$1) {
1859
+ if (error$1 instanceof error.MastraError) throw error$1;
1860
+ throw new error.MastraError(
1861
+ {
1862
+ id: storage.createStorageErrorId("DSQL", "DELETE_VERSION", "FAILED"),
1863
+ domain: error.ErrorDomain.STORAGE,
1864
+ category: error.ErrorCategory.THIRD_PARTY,
1865
+ details: { versionId: id }
1866
+ },
1867
+ error$1
1868
+ );
1869
+ }
1870
+ }
1871
+ async deleteVersionsByParentId(agentId) {
1872
+ try {
1873
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1874
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE "agentId" = $1`, [agentId]);
1875
+ } catch (error$1) {
1876
+ if (error$1 instanceof error.MastraError) throw error$1;
1877
+ throw new error.MastraError(
1878
+ {
1879
+ id: storage.createStorageErrorId("DSQL", "DELETE_VERSIONS_BY_PARENT", "FAILED"),
1880
+ domain: error.ErrorDomain.STORAGE,
1881
+ category: error.ErrorCategory.THIRD_PARTY,
1882
+ details: { agentId }
1883
+ },
1884
+ error$1
1885
+ );
1886
+ }
1887
+ }
1888
+ async countVersions(agentId) {
1889
+ try {
1890
+ const tableName = getTableName2({ indexName: storage.TABLE_AGENT_VERSIONS, schemaName: getSchemaName2(this.#schema) });
1891
+ const result = await this.#db.client.one(`SELECT COUNT(*) as count FROM ${tableName} WHERE "agentId" = $1`, [
1892
+ agentId
1893
+ ]);
1894
+ return parseInt(result.count, 10);
1895
+ } catch (error$1) {
1896
+ if (error$1 instanceof error.MastraError) throw error$1;
1897
+ throw new error.MastraError(
1898
+ {
1899
+ id: storage.createStorageErrorId("DSQL", "COUNT_VERSIONS", "FAILED"),
1900
+ domain: error.ErrorDomain.STORAGE,
1901
+ category: error.ErrorCategory.THIRD_PARTY,
1902
+ details: { agentId }
1903
+ },
1904
+ error$1
1905
+ );
1906
+ }
1907
+ }
1908
+ // ==========================================================================
1909
+ // Private Helpers
1910
+ // ==========================================================================
1911
+ serializeInstructions(instructions) {
1912
+ if (instructions == null) return void 0;
1913
+ return Array.isArray(instructions) ? JSON.stringify(instructions) : instructions;
1914
+ }
1915
+ deserializeInstructions(raw) {
1916
+ if (!raw) return "";
1917
+ try {
1918
+ const parsed = JSON.parse(raw);
1919
+ if (Array.isArray(parsed)) return parsed;
1920
+ } catch {
1921
+ }
1922
+ return raw;
1923
+ }
1924
+ parseVersionRow(row) {
1925
+ return {
1926
+ id: row.id,
1927
+ agentId: row.agentId,
1928
+ versionNumber: row.versionNumber,
1929
+ name: row.name,
1930
+ description: row.description,
1931
+ instructions: this.deserializeInstructions(row.instructions),
1932
+ model: this.parseJson(row.model, "model"),
1933
+ tools: this.parseJson(row.tools, "tools"),
1934
+ defaultOptions: this.parseJson(row.defaultOptions, "defaultOptions"),
1935
+ workflows: this.parseJson(row.workflows, "workflows"),
1936
+ agents: this.parseJson(row.agents, "agents"),
1937
+ integrationTools: this.parseJson(row.integrationTools, "integrationTools"),
1938
+ inputProcessors: this.parseJson(row.inputProcessors, "inputProcessors"),
1939
+ outputProcessors: this.parseJson(row.outputProcessors, "outputProcessors"),
1940
+ memory: this.parseJson(row.memory, "memory"),
1941
+ scorers: this.parseJson(row.scorers, "scorers"),
1942
+ mcpClients: this.parseJson(row.mcpClients, "mcpClients"),
1943
+ requestContextSchema: this.parseJson(row.requestContextSchema, "requestContextSchema"),
1944
+ workspace: this.parseJson(row.workspace, "workspace"),
1945
+ skills: this.parseJson(row.skills, "skills"),
1946
+ skillsFormat: row.skillsFormat,
1947
+ changedFields: this.parseJson(row.changedFields, "changedFields"),
1948
+ changeMessage: row.changeMessage,
1949
+ createdAt: row.createdAtZ || row.createdAt
1950
+ };
1951
+ }
1952
+ };
1953
+ function inPlaceholders(count, startIndex = 1) {
1954
+ return Array.from({ length: count }, (_, i) => `$${i + startIndex}`).join(", ");
1955
+ }
1956
+ var MemoryDSQL = class _MemoryDSQL extends storage.MemoryStorage {
1957
+ #db;
1958
+ #schema;
1959
+ #skipDefaultIndexes;
1960
+ #indexes;
1961
+ /** Tables managed by this domain */
1962
+ static MANAGED_TABLES = [storage.TABLE_THREADS, storage.TABLE_MESSAGES, storage.TABLE_RESOURCES];
1963
+ constructor(config) {
1964
+ super();
1965
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolveDsqlConfig(config);
1966
+ this.#db = new DsqlDB({ client, schemaName, skipDefaultIndexes });
1967
+ this.#schema = schemaName || "public";
1968
+ this.#skipDefaultIndexes = skipDefaultIndexes;
1969
+ this.#indexes = indexes?.filter((idx) => _MemoryDSQL.MANAGED_TABLES.includes(idx.table));
1970
+ }
1971
+ async init() {
1972
+ await this.#db.createTable({ tableName: storage.TABLE_THREADS, schema: storage.TABLE_SCHEMAS[storage.TABLE_THREADS] });
1973
+ await this.#db.createTable({ tableName: storage.TABLE_MESSAGES, schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES] });
1974
+ await this.#db.createTable({ tableName: storage.TABLE_RESOURCES, schema: storage.TABLE_SCHEMAS[storage.TABLE_RESOURCES] });
1975
+ await this.#db.alterTable({
1976
+ tableName: storage.TABLE_MESSAGES,
1977
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_MESSAGES],
1978
+ ifNotExists: ["resourceId"]
1979
+ });
1980
+ await this.createDefaultIndexes();
1981
+ await this.createCustomIndexes();
1982
+ }
1983
+ /**
1984
+ * Returns default index definitions for the memory domain tables.
1985
+ * Note: Aurora DSQL does not support ASC/DESC in index columns.
1986
+ */
1987
+ getDefaultIndexDefinitions() {
1988
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
1989
+ return [
1990
+ {
1991
+ name: `${schemaPrefix}mastra_threads_resourceid_createdat_idx`,
1992
+ table: storage.TABLE_THREADS,
1993
+ columns: ["resourceId", "createdAt"]
1994
+ },
1995
+ {
1996
+ name: `${schemaPrefix}mastra_messages_thread_id_createdat_idx`,
1997
+ table: storage.TABLE_MESSAGES,
1998
+ columns: ["thread_id", "createdAt"]
1999
+ }
2000
+ ];
2001
+ }
2002
+ /**
2003
+ * Creates default indexes for optimal query performance.
2004
+ */
2005
+ async createDefaultIndexes() {
2006
+ if (this.#skipDefaultIndexes) {
2007
+ return;
2008
+ }
2009
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
2010
+ try {
2011
+ await this.#db.createIndex(indexDef);
2012
+ } catch (error) {
2013
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
2014
+ }
2015
+ }
2016
+ }
2017
+ /**
2018
+ * Creates custom user-defined indexes for this domain's tables.
2019
+ */
2020
+ async createCustomIndexes() {
2021
+ if (!this.#indexes || this.#indexes.length === 0) {
2022
+ return;
2023
+ }
2024
+ for (const indexDef of this.#indexes) {
2025
+ try {
2026
+ await this.#db.createIndex(indexDef);
2027
+ } catch (error) {
2028
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
2029
+ }
2030
+ }
2031
+ }
2032
+ async dangerouslyClearAll() {
2033
+ await this.#db.clearTable({ tableName: storage.TABLE_MESSAGES });
2034
+ await this.#db.clearTable({ tableName: storage.TABLE_THREADS });
2035
+ await this.#db.clearTable({ tableName: storage.TABLE_RESOURCES });
2036
+ }
2037
+ /**
2038
+ * Normalizes message row from database by applying createdAtZ fallback
2039
+ */
2040
+ normalizeMessageRow(row) {
2041
+ return {
2042
+ id: row.id,
2043
+ content: row.content,
2044
+ role: row.role,
2045
+ type: row.type,
2046
+ createdAt: row.createdAtZ || row.createdAt,
2047
+ threadId: row.threadId,
2048
+ resourceId: row.resourceId
2049
+ };
2050
+ }
2051
+ async getThreadById({ threadId }) {
2052
+ try {
2053
+ const tableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2054
+ const thread = await this.#db.client.oneOrNone(
2055
+ `SELECT * FROM ${tableName} WHERE id = $1`,
2056
+ [threadId]
2057
+ );
2058
+ if (!thread) {
2059
+ return null;
2060
+ }
2061
+ return {
2062
+ id: thread.id,
2063
+ resourceId: thread.resourceId,
2064
+ title: thread.title,
2065
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
2066
+ createdAt: thread.createdAtZ || thread.createdAt,
2067
+ updatedAt: thread.updatedAtZ || thread.updatedAt
2068
+ };
2069
+ } catch (error$1) {
2070
+ throw new error.MastraError(
2071
+ {
2072
+ id: storage.createStorageErrorId("DSQL", "GET_THREAD_BY_ID", "FAILED"),
2073
+ domain: error.ErrorDomain.STORAGE,
2074
+ category: error.ErrorCategory.THIRD_PARTY,
2075
+ details: {
2076
+ threadId
2077
+ }
2078
+ },
2079
+ error$1
2080
+ );
2081
+ }
2082
+ }
2083
+ async listThreads(args) {
2084
+ const { page = 0, perPage: perPageInput, orderBy, filter } = args;
2085
+ try {
2086
+ this.validatePaginationInput(page, perPageInput ?? 100);
2087
+ } catch (error$1) {
2088
+ throw new error.MastraError({
2089
+ id: storage.createStorageErrorId("DSQL", "LIST_THREADS", "INVALID_PAGE"),
2090
+ domain: error.ErrorDomain.STORAGE,
2091
+ category: error.ErrorCategory.USER,
2092
+ text: error$1 instanceof Error ? error$1.message : "Invalid pagination parameters",
2093
+ details: { page, ...perPageInput !== void 0 && { perPage: perPageInput } }
2094
+ });
2095
+ }
2096
+ const perPage = storage.normalizePerPage(perPageInput, 100);
2097
+ try {
2098
+ this.validateMetadataKeys(filter?.metadata);
2099
+ } catch (error$1) {
2100
+ throw new error.MastraError({
2101
+ id: storage.createStorageErrorId("DSQL", "LIST_THREADS", "INVALID_METADATA_KEY"),
2102
+ domain: error.ErrorDomain.STORAGE,
2103
+ category: error.ErrorCategory.USER,
2104
+ text: error$1 instanceof Error ? error$1.message : "Invalid metadata key",
2105
+ details: { metadataKeys: filter?.metadata ? Object.keys(filter.metadata).join(", ") : "" }
2106
+ });
2107
+ }
2108
+ const { field, direction } = this.parseOrderBy(orderBy);
2109
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2110
+ try {
2111
+ const tableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2112
+ const whereClauses = [];
2113
+ const queryParams = [];
2114
+ let paramIndex = 1;
2115
+ if (filter?.resourceId) {
2116
+ whereClauses.push(`"resourceId" = ${paramIndex}`);
2117
+ queryParams.push(filter.resourceId);
2118
+ paramIndex++;
2119
+ }
2120
+ if (filter?.metadata && Object.keys(filter.metadata).length > 0) {
2121
+ for (const [key, value] of Object.entries(filter.metadata)) {
2122
+ whereClauses.push(`metadata::jsonb @> ${paramIndex}::jsonb`);
2123
+ queryParams.push(JSON.stringify({ [key]: value }));
2124
+ paramIndex++;
2125
+ }
2126
+ }
2127
+ const whereClause = whereClauses.length > 0 ? `WHERE ${whereClauses.join(" AND ")}` : "";
2128
+ const baseQuery = `FROM ${tableName} ${whereClause}`;
2129
+ const countQuery = `SELECT COUNT(*) ${baseQuery}`;
2130
+ const countResult = await this.#db.client.one(countQuery, queryParams);
2131
+ const total = parseInt(countResult.count, 10);
2132
+ if (total === 0) {
2133
+ return {
2134
+ threads: [],
2135
+ total: 0,
2136
+ page,
2137
+ perPage: perPageForResponse,
2138
+ hasMore: false
2139
+ };
2140
+ }
2141
+ const limitValue = perPageInput === false ? total : perPage;
2142
+ const dataQuery = `SELECT id, "resourceId", title, metadata, "createdAt", "createdAtZ", "updatedAt", "updatedAtZ" ${baseQuery} ORDER BY "${field}" ${direction} LIMIT ${paramIndex} OFFSET ${paramIndex + 1}`;
2143
+ const rows = await this.#db.client.manyOrNone(
2144
+ dataQuery,
2145
+ [...queryParams, limitValue, offset]
2146
+ );
2147
+ const threads = (rows || []).map((thread) => ({
2148
+ id: thread.id,
2149
+ resourceId: thread.resourceId,
2150
+ title: thread.title,
2151
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
2152
+ createdAt: thread.createdAtZ || thread.createdAt,
2153
+ updatedAt: thread.updatedAtZ || thread.updatedAt
2154
+ }));
2155
+ return {
2156
+ threads,
2157
+ total,
2158
+ page,
2159
+ perPage: perPageForResponse,
2160
+ hasMore: perPageInput === false ? false : offset + perPage < total
2161
+ };
2162
+ } catch (error$1) {
2163
+ const mastraError = new error.MastraError(
2164
+ {
2165
+ id: storage.createStorageErrorId("DSQL", "LIST_THREADS", "FAILED"),
2166
+ domain: error.ErrorDomain.STORAGE,
2167
+ category: error.ErrorCategory.THIRD_PARTY,
2168
+ details: {
2169
+ ...filter?.resourceId && { resourceId: filter.resourceId },
2170
+ hasMetadataFilter: !!filter?.metadata,
2171
+ page
2172
+ }
2173
+ },
2174
+ error$1
2175
+ );
2176
+ this.logger?.error?.(mastraError.toString());
2177
+ this.logger?.trackException(mastraError);
2178
+ return {
2179
+ threads: [],
2180
+ total: 0,
2181
+ page,
2182
+ perPage: perPageForResponse,
2183
+ hasMore: false
2184
+ };
2185
+ }
2186
+ }
2187
+ async saveThread({ thread }) {
2188
+ const tableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2189
+ await withRetry(
2190
+ async () => {
2191
+ await this.#db.client.none(
2192
+ `INSERT INTO ${tableName} (
2193
+ id,
2194
+ "resourceId",
2195
+ title,
2196
+ metadata,
2197
+ "createdAt",
2198
+ "createdAtZ",
2199
+ "updatedAt",
2200
+ "updatedAtZ"
2201
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
2202
+ ON CONFLICT (id) DO UPDATE SET
2203
+ "resourceId" = EXCLUDED."resourceId",
2204
+ title = EXCLUDED.title,
2205
+ metadata = EXCLUDED.metadata,
2206
+ "createdAt" = EXCLUDED."createdAt",
2207
+ "createdAtZ" = EXCLUDED."createdAtZ",
2208
+ "updatedAt" = EXCLUDED."updatedAt",
2209
+ "updatedAtZ" = EXCLUDED."updatedAtZ"`,
2210
+ [
2211
+ thread.id,
2212
+ thread.resourceId,
2213
+ thread.title,
2214
+ thread.metadata ? JSON.stringify(thread.metadata) : null,
2215
+ thread.createdAt,
2216
+ thread.createdAt,
2217
+ thread.updatedAt,
2218
+ thread.updatedAt
2219
+ ]
2220
+ );
2221
+ },
2222
+ {
2223
+ onRetry: (error, attempt, delay) => {
2224
+ this.logger?.warn?.(`saveThread retry ${attempt} for ${thread.id} after ${delay}ms: ${error.message}`);
2225
+ }
2226
+ }
2227
+ ).catch((error$1) => {
2228
+ throw new error.MastraError(
2229
+ {
2230
+ id: storage.createStorageErrorId("DSQL", "SAVE_THREAD", "FAILED"),
2231
+ domain: error.ErrorDomain.STORAGE,
2232
+ category: error.ErrorCategory.THIRD_PARTY,
2233
+ details: {
2234
+ threadId: thread.id
2235
+ }
2236
+ },
2237
+ error$1
2238
+ );
2239
+ });
2240
+ return thread;
2241
+ }
2242
+ async updateThread({
2243
+ id,
2244
+ title,
2245
+ metadata
2246
+ }) {
2247
+ const threadTableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2248
+ const { result } = await withRetry(
2249
+ async () => {
2250
+ const existingThread = await this.getThreadById({ threadId: id });
2251
+ if (!existingThread) {
2252
+ throw new error.MastraError({
2253
+ id: storage.createStorageErrorId("DSQL", "UPDATE_THREAD", "NOT_FOUND"),
2254
+ domain: error.ErrorDomain.STORAGE,
2255
+ category: error.ErrorCategory.USER,
2256
+ text: `Thread ${id} not found`,
2257
+ details: {
2258
+ threadId: id,
2259
+ title
2260
+ }
2261
+ });
2262
+ }
2263
+ const mergedMetadata = {
2264
+ ...existingThread.metadata,
2265
+ ...metadata
2266
+ };
2267
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2268
+ const thread = await this.#db.client.one(
2269
+ `UPDATE ${threadTableName}
2270
+ SET
2271
+ title = $1,
2272
+ metadata = $2,
2273
+ "updatedAt" = $3::timestamp,
2274
+ "updatedAtZ" = $4::timestamptz
2275
+ WHERE id = $5
2276
+ RETURNING *
2277
+ `,
2278
+ [title, JSON.stringify(mergedMetadata), now, now, id]
2279
+ );
2280
+ return {
2281
+ id: thread.id,
2282
+ resourceId: thread.resourceId,
2283
+ title: thread.title,
2284
+ metadata: typeof thread.metadata === "string" ? JSON.parse(thread.metadata) : thread.metadata,
2285
+ createdAt: thread.createdAtZ || thread.createdAt,
2286
+ updatedAt: thread.updatedAtZ || thread.updatedAt
2287
+ };
2288
+ },
2289
+ {
2290
+ onRetry: (error, attempt, delay) => {
2291
+ this.logger?.warn?.(`updateThread retry ${attempt} for ${id} after ${delay}ms: ${error.message}`);
2292
+ }
2293
+ }
2294
+ ).catch((error$1) => {
2295
+ if (error$1 instanceof error.MastraError) {
2296
+ throw error$1;
2297
+ }
2298
+ throw new error.MastraError(
2299
+ {
2300
+ id: storage.createStorageErrorId("DSQL", "UPDATE_THREAD", "FAILED"),
2301
+ domain: error.ErrorDomain.STORAGE,
2302
+ category: error.ErrorCategory.THIRD_PARTY,
2303
+ details: {
2304
+ threadId: id,
2305
+ title
2306
+ }
2307
+ },
2308
+ error$1
2309
+ );
2310
+ });
2311
+ return result;
2312
+ }
2313
+ async deleteThread({ threadId }) {
2314
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) });
2315
+ const threadTableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2316
+ await withRetry(
2317
+ async () => {
2318
+ await this.#db.client.tx(async (t) => {
2319
+ await t.none(`DELETE FROM ${tableName} WHERE thread_id = $1`, [threadId]);
2320
+ await t.none(`DELETE FROM ${threadTableName} WHERE id = $1`, [threadId]);
2321
+ });
2322
+ },
2323
+ {
2324
+ onRetry: (error, attempt, delay) => {
2325
+ this.logger?.warn?.(`deleteThread retry ${attempt} for ${threadId} after ${delay}ms: ${error.message}`);
2326
+ }
2327
+ }
2328
+ ).catch((error$1) => {
2329
+ throw new error.MastraError(
2330
+ {
2331
+ id: storage.createStorageErrorId("DSQL", "DELETE_THREAD", "FAILED"),
2332
+ domain: error.ErrorDomain.STORAGE,
2333
+ category: error.ErrorCategory.THIRD_PARTY,
2334
+ details: {
2335
+ threadId
2336
+ }
2337
+ },
2338
+ error$1
2339
+ );
2340
+ });
2341
+ }
2342
+ async _getIncludedMessages({ include }) {
2343
+ if (!include || include.length === 0) return null;
2344
+ const unionQueries = [];
2345
+ const params = [];
2346
+ let paramIdx = 1;
2347
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) });
2348
+ for (const inc of include) {
2349
+ const { id, withPreviousMessages = 0, withNextMessages = 0 } = inc;
2350
+ unionQueries.push(
2351
+ `
2352
+ SELECT * FROM (
2353
+ WITH target_thread AS (
2354
+ SELECT thread_id FROM ${tableName} WHERE id = $${paramIdx}
2355
+ ),
2356
+ ordered_messages AS (
2357
+ SELECT
2358
+ *,
2359
+ ROW_NUMBER() OVER (ORDER BY "createdAt" ASC) as row_num
2360
+ FROM ${tableName}
2361
+ WHERE thread_id = (SELECT thread_id FROM target_thread)
2362
+ )
2363
+ SELECT
2364
+ m.id,
2365
+ m.content,
2366
+ m.role,
2367
+ m.type,
2368
+ m."createdAt",
2369
+ m."createdAtZ",
2370
+ m.thread_id AS "threadId",
2371
+ m."resourceId"
2372
+ FROM ordered_messages m
2373
+ WHERE m.id = $${paramIdx}
2374
+ OR EXISTS (
2375
+ SELECT 1 FROM ordered_messages target
2376
+ WHERE target.id = $${paramIdx}
2377
+ AND (
2378
+ (m.row_num < target.row_num AND m.row_num >= target.row_num - $${paramIdx + 1})
2379
+ OR
2380
+ (m.row_num > target.row_num AND m.row_num <= target.row_num + $${paramIdx + 2})
2381
+ )
2382
+ )
2383
+ ) AS query_${paramIdx}
2384
+ `
2385
+ );
2386
+ params.push(id, withPreviousMessages, withNextMessages);
2387
+ paramIdx += 3;
2388
+ }
2389
+ const finalQuery = unionQueries.join(" UNION ALL ") + ' ORDER BY "createdAt" ASC';
2390
+ const includedRows = await this.#db.client.manyOrNone(finalQuery, params);
2391
+ const seen = /* @__PURE__ */ new Set();
2392
+ const dedupedRows = includedRows.filter((row) => {
2393
+ if (seen.has(row.id)) return false;
2394
+ seen.add(row.id);
2395
+ return true;
2396
+ });
2397
+ return dedupedRows;
2398
+ }
2399
+ parseRow(row) {
2400
+ const normalized = this.normalizeMessageRow(row);
2401
+ let content = normalized.content;
2402
+ try {
2403
+ content = JSON.parse(normalized.content);
2404
+ } catch {
2405
+ }
2406
+ return {
2407
+ id: normalized.id,
2408
+ content,
2409
+ role: normalized.role,
2410
+ createdAt: new Date(normalized.createdAt),
2411
+ threadId: normalized.threadId,
2412
+ resourceId: normalized.resourceId,
2413
+ ...normalized.type && normalized.type !== "v2" ? { type: normalized.type } : {}
2414
+ };
2415
+ }
2416
+ async listMessagesById({ messageIds }) {
2417
+ if (messageIds.length === 0) return { messages: [] };
2418
+ const selectStatement = `SELECT id, content, role, type, "createdAt", "createdAtZ", thread_id AS "threadId", "resourceId"`;
2419
+ try {
2420
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) });
2421
+ const query = `
2422
+ ${selectStatement} FROM ${tableName}
2423
+ WHERE id IN (${inPlaceholders(messageIds.length)})
2424
+ ORDER BY "createdAt" DESC
2425
+ `;
2426
+ const resultRows = await this.#db.client.manyOrNone(query, messageIds);
2427
+ const list = new agent.MessageList().add(
2428
+ resultRows.map((row) => this.parseRow(row)),
2429
+ "memory"
2430
+ );
2431
+ return { messages: list.get.all.db() };
2432
+ } catch (error$1) {
2433
+ const mastraError = new error.MastraError(
2434
+ {
2435
+ id: storage.createStorageErrorId("DSQL", "LIST_MESSAGES_BY_ID", "FAILED"),
2436
+ domain: error.ErrorDomain.STORAGE,
2437
+ category: error.ErrorCategory.THIRD_PARTY,
2438
+ details: {
2439
+ messageIds: JSON.stringify(messageIds)
2440
+ }
2441
+ },
2442
+ error$1
2443
+ );
2444
+ this.logger?.error?.(mastraError.toString());
2445
+ this.logger?.trackException(mastraError);
2446
+ return { messages: [] };
2447
+ }
2448
+ }
2449
+ async listMessages(args) {
2450
+ const { threadId, resourceId, include, filter, perPage: perPageInput, page = 0, orderBy } = args;
2451
+ const threadIds = (Array.isArray(threadId) ? threadId : [threadId]).filter(
2452
+ (id) => typeof id === "string"
2453
+ );
2454
+ if (threadIds.length === 0 || threadIds.some((id) => !id.trim())) {
2455
+ throw new error.MastraError(
2456
+ {
2457
+ id: storage.createStorageErrorId("DSQL", "LIST_MESSAGES", "INVALID_THREAD_ID"),
2458
+ domain: error.ErrorDomain.STORAGE,
2459
+ category: error.ErrorCategory.USER,
2460
+ details: { threadId: Array.isArray(threadId) ? String(threadId) : String(threadId) }
2461
+ },
2462
+ new Error("threadId must be a non-empty string or array of non-empty strings")
2463
+ );
2464
+ }
2465
+ if (page < 0) {
2466
+ throw new error.MastraError({
2467
+ id: storage.createStorageErrorId("DSQL", "LIST_MESSAGES", "INVALID_PAGE"),
2468
+ domain: error.ErrorDomain.STORAGE,
2469
+ category: error.ErrorCategory.USER,
2470
+ text: "Page number must be non-negative",
2471
+ details: {
2472
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
2473
+ page
2474
+ }
2475
+ });
2476
+ }
2477
+ const perPage = storage.normalizePerPage(perPageInput, 40);
2478
+ const { offset, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
2479
+ try {
2480
+ const { field, direction } = this.parseOrderBy(orderBy, "ASC");
2481
+ const orderByStatement = `ORDER BY "${field}" ${direction}`;
2482
+ const selectStatement = `SELECT id, content, role, type, "createdAt", "createdAtZ", thread_id AS "threadId", "resourceId"`;
2483
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) });
2484
+ const conditions = [`thread_id IN (${inPlaceholders(threadIds.length)})`];
2485
+ const queryParams = [...threadIds];
2486
+ let paramIndex = threadIds.length + 1;
2487
+ if (resourceId) {
2488
+ conditions.push(`"resourceId" = $${paramIndex++}`);
2489
+ queryParams.push(resourceId);
2490
+ }
2491
+ if (filter?.dateRange?.start) {
2492
+ conditions.push(`"createdAtZ" >= $${paramIndex++}::timestamptz`);
2493
+ queryParams.push(filter.dateRange.start);
2494
+ }
2495
+ if (filter?.dateRange?.end) {
2496
+ conditions.push(`"createdAtZ" <= $${paramIndex++}::timestamptz`);
2497
+ queryParams.push(filter.dateRange.end);
2498
+ }
2499
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
2500
+ const countQuery = `SELECT COUNT(*) FROM ${tableName} ${whereClause}`;
2501
+ const countResult = await this.#db.client.one(countQuery, queryParams);
2502
+ const total = parseInt(countResult.count, 10);
2503
+ const limitValue = perPageInput === false ? total : perPage;
2504
+ const dataQuery = `${selectStatement} FROM ${tableName} ${whereClause} ${orderByStatement} LIMIT $${paramIndex++} OFFSET $${paramIndex++}`;
2505
+ const rows = await this.#db.client.manyOrNone(dataQuery, [...queryParams, limitValue, offset]);
2506
+ const messages = [...rows || []];
2507
+ if (total === 0 && messages.length === 0 && (!include || include.length === 0)) {
2508
+ return {
2509
+ messages: [],
2510
+ total: 0,
2511
+ page,
2512
+ perPage: perPageForResponse,
2513
+ hasMore: false
2514
+ };
2515
+ }
2516
+ const messageIds = new Set(messages.map((m) => m.id));
2517
+ if (include && include.length > 0) {
2518
+ const includeMessages = await this._getIncludedMessages({ include });
2519
+ if (includeMessages) {
2520
+ for (const includeMsg of includeMessages) {
2521
+ if (!messageIds.has(includeMsg.id)) {
2522
+ messages.push(includeMsg);
2523
+ messageIds.add(includeMsg.id);
2524
+ }
2525
+ }
2526
+ }
2527
+ }
2528
+ const messagesWithParsedContent = messages.map((row) => this.parseRow(row));
2529
+ const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
2530
+ let finalMessages = list.get.all.db();
2531
+ finalMessages = finalMessages.sort((a, b) => {
2532
+ const aValue = field === "createdAt" ? new Date(a.createdAt).getTime() : a[field];
2533
+ const bValue = field === "createdAt" ? new Date(b.createdAt).getTime() : b[field];
2534
+ if (aValue == null && bValue == null) return a.id.localeCompare(b.id);
2535
+ if (aValue == null) return 1;
2536
+ if (bValue == null) return -1;
2537
+ if (aValue === bValue) {
2538
+ return a.id.localeCompare(b.id);
2539
+ }
2540
+ if (typeof aValue === "number" && typeof bValue === "number") {
2541
+ return direction === "ASC" ? aValue - bValue : bValue - aValue;
2542
+ }
2543
+ return direction === "ASC" ? String(aValue).localeCompare(String(bValue)) : String(bValue).localeCompare(String(aValue));
2544
+ });
2545
+ const threadIdSet = new Set(threadIds);
2546
+ const returnedThreadMessageIds = new Set(
2547
+ finalMessages.filter((m) => m.threadId && threadIdSet.has(m.threadId)).map((m) => m.id)
2548
+ );
2549
+ const allThreadMessagesReturned = returnedThreadMessageIds.size >= total;
2550
+ const hasMore = perPageInput !== false && !allThreadMessagesReturned && offset + perPage < total;
2551
+ return {
2552
+ messages: finalMessages,
2553
+ total,
2554
+ page,
2555
+ perPage: perPageForResponse,
2556
+ hasMore
2557
+ };
2558
+ } catch (error$1) {
2559
+ const mastraError = new error.MastraError(
2560
+ {
2561
+ id: storage.createStorageErrorId("DSQL", "LIST_MESSAGES", "FAILED"),
2562
+ domain: error.ErrorDomain.STORAGE,
2563
+ category: error.ErrorCategory.THIRD_PARTY,
2564
+ details: {
2565
+ threadId: Array.isArray(threadId) ? threadId.join(",") : threadId,
2566
+ resourceId: resourceId ?? ""
2567
+ }
2568
+ },
2569
+ error$1
2570
+ );
2571
+ this.logger?.error?.(mastraError.toString());
2572
+ this.logger?.trackException(mastraError);
2573
+ return {
2574
+ messages: [],
2575
+ total: 0,
2576
+ page,
2577
+ perPage: perPageForResponse,
2578
+ hasMore: false
2579
+ };
2580
+ }
2581
+ }
2582
+ async saveMessages({ messages }) {
2583
+ if (messages.length === 0) return { messages: [] };
2584
+ const threadId = messages[0]?.threadId;
2585
+ if (!threadId) {
2586
+ throw new error.MastraError({
2587
+ id: storage.createStorageErrorId("DSQL", "SAVE_MESSAGES", "FAILED"),
2588
+ domain: error.ErrorDomain.STORAGE,
2589
+ category: error.ErrorCategory.USER,
2590
+ text: `Thread ID is required`
2591
+ });
2592
+ }
2593
+ const thread = await this.getThreadById({ threadId });
2594
+ if (!thread) {
2595
+ throw new error.MastraError({
2596
+ id: storage.createStorageErrorId("DSQL", "SAVE_MESSAGES", "FAILED"),
2597
+ domain: error.ErrorDomain.STORAGE,
2598
+ category: error.ErrorCategory.USER,
2599
+ text: `Thread ${threadId} not found`,
2600
+ details: {
2601
+ threadId
2602
+ }
2603
+ });
2604
+ }
2605
+ const tableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) });
2606
+ const threadTableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2607
+ await withRetry(
2608
+ async () => {
2609
+ await this.#db.client.tx(async (t) => {
2610
+ const messageInserts = messages.map((message) => {
2611
+ if (!message.threadId) {
2612
+ throw new Error(
2613
+ `Expected to find a threadId for message, but couldn't find one. An unexpected error has occurred.`
2614
+ );
2615
+ }
2616
+ if (!message.resourceId) {
2617
+ throw new Error(
2618
+ `Expected to find a resourceId for message, but couldn't find one. An unexpected error has occurred.`
2619
+ );
2620
+ }
2621
+ const createdAtIso = message.createdAt ? new Date(message.createdAt).toISOString() : (/* @__PURE__ */ new Date()).toISOString();
2622
+ return t.none(
2623
+ `INSERT INTO ${tableName} (id, thread_id, content, "createdAt", "createdAtZ", role, type, "resourceId")
2624
+ VALUES ($1, $2, $3, $4::timestamp, $5::timestamptz, $6, $7, $8)
2625
+ ON CONFLICT (id) DO UPDATE SET
2626
+ thread_id = EXCLUDED.thread_id,
2627
+ content = EXCLUDED.content,
2628
+ role = EXCLUDED.role,
2629
+ type = EXCLUDED.type,
2630
+ "resourceId" = EXCLUDED."resourceId"`,
2631
+ [
2632
+ message.id,
2633
+ message.threadId,
2634
+ typeof message.content === "string" ? message.content : JSON.stringify(message.content),
2635
+ createdAtIso,
2636
+ createdAtIso,
2637
+ message.role,
2638
+ message.type || "v2",
2639
+ message.resourceId
2640
+ ]
2641
+ );
2642
+ });
2643
+ const nowIso = (/* @__PURE__ */ new Date()).toISOString();
2644
+ const threadUpdate = t.none(
2645
+ `UPDATE ${threadTableName}
2646
+ SET
2647
+ "updatedAt" = $1::timestamp,
2648
+ "updatedAtZ" = $2::timestamptz
2649
+ WHERE id = $3
2650
+ `,
2651
+ [nowIso, nowIso, threadId]
2652
+ );
2653
+ await Promise.all([...messageInserts, threadUpdate]);
2654
+ });
2655
+ },
2656
+ {
2657
+ onRetry: (error, attempt, delay) => {
2658
+ this.logger?.warn?.(
2659
+ `saveMessages retry ${attempt} for thread ${threadId} after ${delay}ms: ${error.message}`
2660
+ );
2661
+ }
2662
+ }
2663
+ ).catch((error$1) => {
2664
+ throw new error.MastraError(
2665
+ {
2666
+ id: storage.createStorageErrorId("DSQL", "SAVE_MESSAGES", "FAILED"),
2667
+ domain: error.ErrorDomain.STORAGE,
2668
+ category: error.ErrorCategory.THIRD_PARTY,
2669
+ details: {
2670
+ threadId
2671
+ }
2672
+ },
2673
+ error$1
2674
+ );
2675
+ });
2676
+ const messagesWithParsedContent = messages.map((message) => {
2677
+ if (typeof message.content === "string") {
2678
+ try {
2679
+ return { ...message, content: JSON.parse(message.content) };
2680
+ } catch {
2681
+ return message;
2682
+ }
2683
+ }
2684
+ return message;
2685
+ });
2686
+ const list = new agent.MessageList().add(messagesWithParsedContent, "memory");
2687
+ return { messages: list.get.all.db() };
2688
+ }
2689
+ async updateMessages({
2690
+ messages
2691
+ }) {
2692
+ if (messages.length === 0) {
2693
+ return [];
2694
+ }
2695
+ const messageIds = messages.map((m) => m.id);
2696
+ const selectQuery = `SELECT id, content, role, type, "createdAt", "createdAtZ", thread_id AS "threadId", "resourceId" FROM ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) })} WHERE id IN (${inPlaceholders(messageIds.length)})`;
2697
+ const existingMessagesDb = await this.#db.client.manyOrNone(selectQuery, messageIds);
2698
+ if (existingMessagesDb.length === 0) {
2699
+ return [];
2700
+ }
2701
+ const existingMessages = existingMessagesDb.map((msg) => {
2702
+ if (typeof msg.content === "string") {
2703
+ try {
2704
+ msg.content = JSON.parse(msg.content);
2705
+ } catch {
2706
+ }
2707
+ }
2708
+ return msg;
2709
+ });
2710
+ const threadIdsToUpdate = /* @__PURE__ */ new Set();
2711
+ await withRetry(
2712
+ async () => {
2713
+ await this.#db.client.tx(async (t) => {
2714
+ const queries = [];
2715
+ const columnMapping = {
2716
+ threadId: "thread_id"
2717
+ };
2718
+ for (const existingMessage of existingMessages) {
2719
+ const updatePayload = messages.find((m) => m.id === existingMessage.id);
2720
+ if (!updatePayload) continue;
2721
+ const { id, ...fieldsToUpdate } = updatePayload;
2722
+ if (Object.keys(fieldsToUpdate).length === 0) continue;
2723
+ threadIdsToUpdate.add(existingMessage.threadId);
2724
+ if (updatePayload.threadId && updatePayload.threadId !== existingMessage.threadId) {
2725
+ threadIdsToUpdate.add(updatePayload.threadId);
2726
+ }
2727
+ const setClauses = [];
2728
+ const values = [];
2729
+ let paramIndex = 1;
2730
+ const updatableFields = { ...fieldsToUpdate };
2731
+ if (updatableFields.content) {
2732
+ const newContent = {
2733
+ ...existingMessage.content,
2734
+ ...updatableFields.content,
2735
+ ...existingMessage.content?.metadata && updatableFields.content.metadata ? {
2736
+ metadata: {
2737
+ ...existingMessage.content.metadata,
2738
+ ...updatableFields.content.metadata
2739
+ }
2740
+ } : {}
2741
+ };
2742
+ setClauses.push(`content = $${paramIndex++}`);
2743
+ values.push(newContent);
2744
+ delete updatableFields.content;
2745
+ }
2746
+ for (const key in updatableFields) {
2747
+ if (Object.prototype.hasOwnProperty.call(updatableFields, key)) {
2748
+ const dbColumn = columnMapping[key] || key;
2749
+ setClauses.push(`"${dbColumn}" = $${paramIndex++}`);
2750
+ values.push(updatableFields[key]);
2751
+ }
2752
+ }
2753
+ if (setClauses.length > 0) {
2754
+ values.push(id);
2755
+ const sql = `UPDATE ${getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) })} SET ${setClauses.join(", ")} WHERE id = $${paramIndex}`;
2756
+ queries.push(t.none(sql, values));
2757
+ }
2758
+ }
2759
+ if (threadIdsToUpdate.size > 0) {
2760
+ const threadIds = Array.from(threadIdsToUpdate);
2761
+ queries.push(
2762
+ t.none(
2763
+ `UPDATE ${getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) })} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id IN (${inPlaceholders(threadIds.length)})`,
2764
+ threadIds
2765
+ )
2766
+ );
2767
+ }
2768
+ if (queries.length > 0) {
2769
+ await t.batch(queries);
2770
+ }
2771
+ });
2772
+ },
2773
+ {
2774
+ onRetry: (error, attempt, delay) => {
2775
+ this.logger?.warn?.(
2776
+ `updateMessages retry ${attempt} for ${messageIds.length} messages after ${delay}ms: ${error.message}`
2777
+ );
2778
+ }
2779
+ }
2780
+ ).catch((error$1) => {
2781
+ throw new error.MastraError(
2782
+ {
2783
+ id: storage.createStorageErrorId("DSQL", "UPDATE_MESSAGES", "FAILED"),
2784
+ domain: error.ErrorDomain.STORAGE,
2785
+ category: error.ErrorCategory.THIRD_PARTY,
2786
+ details: {
2787
+ messageIdsLength: messageIds.length
2788
+ }
2789
+ },
2790
+ error$1
2791
+ );
2792
+ });
2793
+ const updatedMessages = await this.#db.client.manyOrNone(selectQuery, messageIds);
2794
+ return (updatedMessages || []).map((row) => {
2795
+ const message = this.normalizeMessageRow(row);
2796
+ if (typeof message.content === "string") {
2797
+ try {
2798
+ return { ...message, content: JSON.parse(message.content) };
2799
+ } catch {
2800
+ }
2801
+ }
2802
+ return message;
2803
+ });
2804
+ }
2805
+ async deleteMessages(messageIds) {
2806
+ if (!messageIds || messageIds.length === 0) {
2807
+ return;
2808
+ }
2809
+ const messageTableName = getTableName2({ indexName: storage.TABLE_MESSAGES, schemaName: getSchemaName2(this.#schema) });
2810
+ const threadTableName = getTableName2({ indexName: storage.TABLE_THREADS, schemaName: getSchemaName2(this.#schema) });
2811
+ await withRetry(
2812
+ async () => {
2813
+ await this.#db.client.tx(async (t) => {
2814
+ const placeholders = messageIds.map((_, idx) => `$${idx + 1}`).join(",");
2815
+ const messages = await t.manyOrNone(
2816
+ `SELECT DISTINCT thread_id FROM ${messageTableName} WHERE id IN (${placeholders})`,
2817
+ messageIds
2818
+ );
2819
+ const threadIds = messages?.map((msg) => msg.thread_id).filter(Boolean) || [];
2820
+ await t.none(`DELETE FROM ${messageTableName} WHERE id IN (${placeholders})`, messageIds);
2821
+ if (threadIds.length > 0) {
2822
+ const updatePromises = threadIds.map(
2823
+ (threadId) => t.none(`UPDATE ${threadTableName} SET "updatedAt" = NOW(), "updatedAtZ" = NOW() WHERE id = $1`, [
2824
+ threadId
2825
+ ])
2826
+ );
2827
+ await Promise.all(updatePromises);
2828
+ }
2829
+ });
2830
+ },
2831
+ {
2832
+ onRetry: (error, attempt, delay) => {
2833
+ this.logger?.warn?.(
2834
+ `deleteMessages retry ${attempt} for ${messageIds.length} messages after ${delay}ms: ${error.message}`
2835
+ );
2836
+ }
2837
+ }
2838
+ ).catch((error$1) => {
2839
+ throw new error.MastraError(
2840
+ {
2841
+ id: storage.createStorageErrorId("DSQL", "DELETE_MESSAGES", "FAILED"),
2842
+ domain: error.ErrorDomain.STORAGE,
2843
+ category: error.ErrorCategory.THIRD_PARTY,
2844
+ details: { messageIds: messageIds.join(", ") }
2845
+ },
2846
+ error$1
2847
+ );
2848
+ });
2849
+ }
2850
+ async getResourceById({ resourceId }) {
2851
+ try {
2852
+ const tableName = getTableName2({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName2(this.#schema) });
2853
+ const result = await this.#db.client.oneOrNone(
2854
+ `SELECT * FROM ${tableName} WHERE id = $1`,
2855
+ [resourceId]
2856
+ );
2857
+ if (!result) {
2858
+ return null;
2859
+ }
2860
+ return {
2861
+ id: result.id,
2862
+ createdAt: result.createdAtZ || result.createdAt,
2863
+ updatedAt: result.updatedAtZ || result.updatedAt,
2864
+ workingMemory: result.workingMemory,
2865
+ metadata: typeof result.metadata === "string" ? JSON.parse(result.metadata) : result.metadata
2866
+ };
2867
+ } catch (error$1) {
2868
+ throw new error.MastraError(
2869
+ {
2870
+ id: storage.createStorageErrorId("DSQL", "GET_RESOURCE_BY_ID", "FAILED"),
2871
+ domain: error.ErrorDomain.STORAGE,
2872
+ category: error.ErrorCategory.THIRD_PARTY,
2873
+ details: { resourceId }
2874
+ },
2875
+ error$1
2876
+ );
2877
+ }
2878
+ }
2879
+ async saveResource({ resource }) {
2880
+ await this.#db.insert({
2881
+ tableName: storage.TABLE_RESOURCES,
2882
+ record: {
2883
+ ...resource,
2884
+ metadata: JSON.stringify(resource.metadata)
2885
+ }
2886
+ });
2887
+ return resource;
2888
+ }
2889
+ async updateResource({
2890
+ resourceId,
2891
+ workingMemory,
2892
+ metadata
2893
+ }) {
2894
+ const tableName = getTableName2({ indexName: storage.TABLE_RESOURCES, schemaName: getSchemaName2(this.#schema) });
2895
+ const { result } = await withRetry(
2896
+ async () => {
2897
+ const existingResource = await this.getResourceById({ resourceId });
2898
+ if (!existingResource) {
2899
+ const newResource = {
2900
+ id: resourceId,
2901
+ workingMemory,
2902
+ metadata: metadata || {},
2903
+ createdAt: /* @__PURE__ */ new Date(),
2904
+ updatedAt: /* @__PURE__ */ new Date()
2905
+ };
2906
+ return this.saveResource({ resource: newResource });
2907
+ }
2908
+ const updatedResource = {
2909
+ ...existingResource,
2910
+ workingMemory: workingMemory !== void 0 ? workingMemory : existingResource.workingMemory,
2911
+ metadata: {
2912
+ ...existingResource.metadata,
2913
+ ...metadata
2914
+ },
2915
+ updatedAt: /* @__PURE__ */ new Date()
2916
+ };
2917
+ const updates = [];
2918
+ const values = [];
2919
+ let paramIndex = 1;
2920
+ if (workingMemory !== void 0) {
2921
+ updates.push(`"workingMemory" = $${paramIndex}`);
2922
+ values.push(workingMemory);
2923
+ paramIndex++;
2924
+ }
2925
+ if (metadata) {
2926
+ updates.push(`metadata = $${paramIndex}`);
2927
+ values.push(JSON.stringify(updatedResource.metadata));
2928
+ paramIndex++;
2929
+ }
2930
+ updates.push(`"updatedAt" = $${paramIndex}`);
2931
+ values.push(updatedResource.updatedAt.toISOString());
2932
+ paramIndex++;
2933
+ updates.push(`"updatedAtZ" = $${paramIndex}`);
2934
+ values.push(updatedResource.updatedAt.toISOString());
2935
+ paramIndex++;
2936
+ values.push(resourceId);
2937
+ await this.#db.client.none(`UPDATE ${tableName} SET ${updates.join(", ")} WHERE id = $${paramIndex}`, values);
2938
+ return updatedResource;
2939
+ },
2940
+ {
2941
+ onRetry: (error, attempt, delay) => {
2942
+ this.logger?.warn?.(`updateResource retry ${attempt} for ${resourceId} after ${delay}ms: ${error.message}`);
2943
+ }
2944
+ }
2945
+ ).catch((error$1) => {
2946
+ if (error$1 instanceof error.MastraError) {
2947
+ throw error$1;
2948
+ }
2949
+ throw new error.MastraError(
2950
+ {
2951
+ id: storage.createStorageErrorId("DSQL", "UPDATE_RESOURCE", "FAILED"),
2952
+ domain: error.ErrorDomain.STORAGE,
2953
+ category: error.ErrorCategory.THIRD_PARTY,
2954
+ details: {
2955
+ resourceId
2956
+ }
2957
+ },
2958
+ error$1
2959
+ );
2960
+ });
2961
+ return result;
2962
+ }
2963
+ };
2964
+ var ObservabilityDSQL = class _ObservabilityDSQL extends storage.ObservabilityStorage {
2965
+ #db;
2966
+ #schema;
2967
+ #skipDefaultIndexes;
2968
+ #indexes;
2969
+ /** Tables managed by this domain */
2970
+ static MANAGED_TABLES = [storage.TABLE_SPANS];
2971
+ constructor(config) {
2972
+ super();
2973
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolveDsqlConfig(config);
2974
+ this.#db = new DsqlDB({ client, schemaName, skipDefaultIndexes });
2975
+ this.#schema = schemaName || "public";
2976
+ this.#skipDefaultIndexes = skipDefaultIndexes;
2977
+ this.#indexes = indexes?.filter((idx) => _ObservabilityDSQL.MANAGED_TABLES.includes(idx.table));
2978
+ }
2979
+ async init() {
2980
+ await this.#db.createTable({ tableName: storage.TABLE_SPANS, schema: storage.TABLE_SCHEMAS[storage.TABLE_SPANS] });
2981
+ await this.createDefaultIndexes();
2982
+ await this.createCustomIndexes();
2983
+ }
2984
+ /**
2985
+ * Returns default index definitions for the observability domain tables.
2986
+ */
2987
+ getDefaultIndexDefinitions() {
2988
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
2989
+ return [
2990
+ {
2991
+ name: `${schemaPrefix}mastra_ai_spans_traceid_startedat_idx`,
2992
+ table: storage.TABLE_SPANS,
2993
+ columns: ["traceId", "startedAt"]
2994
+ },
2995
+ {
2996
+ name: `${schemaPrefix}mastra_ai_spans_parentspanid_startedat_idx`,
2997
+ table: storage.TABLE_SPANS,
2998
+ columns: ["parentSpanId", "startedAt"]
2999
+ },
3000
+ {
3001
+ name: `${schemaPrefix}mastra_ai_spans_name_idx`,
3002
+ table: storage.TABLE_SPANS,
3003
+ columns: ["name"]
3004
+ },
3005
+ {
3006
+ name: `${schemaPrefix}mastra_ai_spans_spantype_startedat_idx`,
3007
+ table: storage.TABLE_SPANS,
3008
+ columns: ["spanType", "startedAt"]
3009
+ },
3010
+ // Entity identification indexes - common filtering patterns
3011
+ {
3012
+ name: `${schemaPrefix}mastra_ai_spans_entitytype_entityid_idx`,
3013
+ table: storage.TABLE_SPANS,
3014
+ columns: ["entityType", "entityId"]
3015
+ },
3016
+ {
3017
+ name: `${schemaPrefix}mastra_ai_spans_entitytype_entityname_idx`,
3018
+ table: storage.TABLE_SPANS,
3019
+ columns: ["entityType", "entityName"]
3020
+ },
3021
+ // Multi-tenant filtering - organizationId + userId
3022
+ {
3023
+ name: `${schemaPrefix}mastra_ai_spans_orgid_userid_idx`,
3024
+ table: storage.TABLE_SPANS,
3025
+ columns: ["organizationId", "userId"]
3026
+ }
3027
+ ];
3028
+ }
3029
+ /**
3030
+ * Creates default indexes for optimal query performance.
3031
+ */
3032
+ async createDefaultIndexes() {
3033
+ if (this.#skipDefaultIndexes) {
3034
+ return;
3035
+ }
3036
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
3037
+ try {
3038
+ await this.#db.createIndex(indexDef);
3039
+ } catch (error) {
3040
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
3041
+ }
3042
+ }
3043
+ }
3044
+ /**
3045
+ * Creates custom user-defined indexes for this domain's tables.
3046
+ */
3047
+ async createCustomIndexes() {
3048
+ if (!this.#indexes || this.#indexes.length === 0) {
3049
+ return;
3050
+ }
3051
+ for (const indexDef of this.#indexes) {
3052
+ try {
3053
+ await this.#db.createIndex(indexDef);
3054
+ } catch (error) {
3055
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
3056
+ }
3057
+ }
3058
+ }
3059
+ async dangerouslyClearAll() {
3060
+ await this.#db.clearTable({ tableName: storage.TABLE_SPANS });
3061
+ }
3062
+ get tracingStrategy() {
3063
+ return {
3064
+ preferred: "batch-with-updates",
3065
+ supported: ["batch-with-updates", "insert-only"]
3066
+ };
3067
+ }
3068
+ async createSpan(args) {
3069
+ const { span } = args;
3070
+ try {
3071
+ const startedAt = span.startedAt instanceof Date ? span.startedAt.toISOString() : span.startedAt;
3072
+ const endedAt = span.endedAt instanceof Date ? span.endedAt.toISOString() : span.endedAt;
3073
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3074
+ const record = {
3075
+ ...span,
3076
+ startedAt,
3077
+ endedAt,
3078
+ startedAtZ: startedAt,
3079
+ endedAtZ: endedAt,
3080
+ // Aurora DSQL doesn't support triggers, so we set timestamps explicitly
3081
+ createdAt: now,
3082
+ updatedAt: now
3083
+ };
3084
+ await this.#db.insert({ tableName: storage.TABLE_SPANS, record });
3085
+ } catch (error$1) {
3086
+ throw new error.MastraError(
3087
+ {
3088
+ id: storage.createStorageErrorId("DSQL", "CREATE_SPAN", "FAILED"),
3089
+ domain: error.ErrorDomain.STORAGE,
3090
+ category: error.ErrorCategory.USER,
3091
+ details: {
3092
+ spanId: span.spanId,
3093
+ traceId: span.traceId,
3094
+ spanType: span.spanType,
3095
+ spanName: span.name
3096
+ }
3097
+ },
3098
+ error$1
3099
+ );
3100
+ }
3101
+ }
3102
+ async getSpan(args) {
3103
+ const { traceId, spanId } = args;
3104
+ try {
3105
+ const tableName = getTableName2({
3106
+ indexName: storage.TABLE_SPANS,
3107
+ schemaName: getSchemaName2(this.#schema)
3108
+ });
3109
+ const row = await this.#db.client.oneOrNone(
3110
+ `SELECT
3111
+ "traceId", "spanId", "parentSpanId", "name",
3112
+ "entityType", "entityId", "entityName",
3113
+ "userId", "organizationId", "resourceId",
3114
+ "runId", "sessionId", "threadId", "requestId",
3115
+ "environment", "source", "serviceName", "scope",
3116
+ "spanType", "attributes", "metadata", "tags", "links",
3117
+ "input", "output", "error", "isEvent",
3118
+ "startedAtZ" as "startedAt", "endedAtZ" as "endedAt",
3119
+ "createdAtZ" as "createdAt", "updatedAtZ" as "updatedAt"
3120
+ FROM ${tableName}
3121
+ WHERE "traceId" = $1 AND "spanId" = $2`,
3122
+ [traceId, spanId]
3123
+ );
3124
+ if (!row) {
3125
+ return null;
3126
+ }
3127
+ return {
3128
+ span: transformFromSqlRow({
3129
+ tableName: storage.TABLE_SPANS,
3130
+ sqlRow: row
3131
+ })
3132
+ };
3133
+ } catch (error$1) {
3134
+ throw new error.MastraError(
3135
+ {
3136
+ id: storage.createStorageErrorId("DSQL", "GET_SPAN", "FAILED"),
3137
+ domain: error.ErrorDomain.STORAGE,
3138
+ category: error.ErrorCategory.USER,
3139
+ details: { traceId, spanId }
3140
+ },
3141
+ error$1
3142
+ );
3143
+ }
3144
+ }
3145
+ async getRootSpan(args) {
3146
+ const { traceId } = args;
3147
+ try {
3148
+ const tableName = getTableName2({
3149
+ indexName: storage.TABLE_SPANS,
3150
+ schemaName: getSchemaName2(this.#schema)
3151
+ });
3152
+ const row = await this.#db.client.oneOrNone(
3153
+ `SELECT
3154
+ "traceId", "spanId", "parentSpanId", "name",
3155
+ "entityType", "entityId", "entityName",
3156
+ "userId", "organizationId", "resourceId",
3157
+ "runId", "sessionId", "threadId", "requestId",
3158
+ "environment", "source", "serviceName", "scope",
3159
+ "spanType", "attributes", "metadata", "tags", "links",
3160
+ "input", "output", "error", "isEvent",
3161
+ "startedAtZ" as "startedAt", "endedAtZ" as "endedAt",
3162
+ "createdAtZ" as "createdAt", "updatedAtZ" as "updatedAt"
3163
+ FROM ${tableName}
3164
+ WHERE "traceId" = $1 AND "parentSpanId" IS NULL`,
3165
+ [traceId]
3166
+ );
3167
+ if (!row) {
3168
+ return null;
3169
+ }
3170
+ return {
3171
+ span: transformFromSqlRow({
3172
+ tableName: storage.TABLE_SPANS,
3173
+ sqlRow: row
3174
+ })
3175
+ };
3176
+ } catch (error$1) {
3177
+ throw new error.MastraError(
3178
+ {
3179
+ id: storage.createStorageErrorId("DSQL", "GET_ROOT_SPAN", "FAILED"),
3180
+ domain: error.ErrorDomain.STORAGE,
3181
+ category: error.ErrorCategory.USER,
3182
+ details: { traceId }
3183
+ },
3184
+ error$1
3185
+ );
3186
+ }
3187
+ }
3188
+ async getTrace(args) {
3189
+ const { traceId } = args;
3190
+ try {
3191
+ const tableName = getTableName2({
3192
+ indexName: storage.TABLE_SPANS,
3193
+ schemaName: getSchemaName2(this.#schema)
3194
+ });
3195
+ const spans = await this.#db.client.manyOrNone(
3196
+ `SELECT
3197
+ "traceId", "spanId", "parentSpanId", "name",
3198
+ "entityType", "entityId", "entityName",
3199
+ "userId", "organizationId", "resourceId",
3200
+ "runId", "sessionId", "threadId", "requestId",
3201
+ "environment", "source", "serviceName", "scope",
3202
+ "spanType", "attributes", "metadata", "tags", "links",
3203
+ "input", "output", "error", "isEvent",
3204
+ "startedAtZ" as "startedAt", "endedAtZ" as "endedAt",
3205
+ "createdAtZ" as "createdAt", "updatedAtZ" as "updatedAt"
3206
+ FROM ${tableName}
3207
+ WHERE "traceId" = $1
3208
+ ORDER BY "startedAtZ" ASC`,
3209
+ [traceId]
3210
+ );
3211
+ if (!spans || spans.length === 0) {
3212
+ return null;
3213
+ }
3214
+ return {
3215
+ traceId,
3216
+ spans: spans.map(
3217
+ (span) => transformFromSqlRow({
3218
+ tableName: storage.TABLE_SPANS,
3219
+ sqlRow: span
3220
+ })
3221
+ )
3222
+ };
3223
+ } catch (error$1) {
3224
+ throw new error.MastraError(
3225
+ {
3226
+ id: storage.createStorageErrorId("DSQL", "GET_TRACE", "FAILED"),
3227
+ domain: error.ErrorDomain.STORAGE,
3228
+ category: error.ErrorCategory.USER,
3229
+ details: {
3230
+ traceId
3231
+ }
3232
+ },
3233
+ error$1
3234
+ );
3235
+ }
3236
+ }
3237
+ async updateSpan(args) {
3238
+ const { traceId, spanId, updates } = args;
3239
+ try {
3240
+ const data = { ...updates };
3241
+ if (data.endedAt instanceof Date) {
3242
+ const endedAt = data.endedAt.toISOString();
3243
+ data.endedAt = endedAt;
3244
+ data.endedAtZ = endedAt;
3245
+ }
3246
+ if (data.startedAt instanceof Date) {
3247
+ const startedAt = data.startedAt.toISOString();
3248
+ data.startedAt = startedAt;
3249
+ data.startedAtZ = startedAt;
3250
+ }
3251
+ await this.#db.update({
3252
+ tableName: storage.TABLE_SPANS,
3253
+ keys: { spanId, traceId },
3254
+ data
3255
+ });
3256
+ } catch (error$1) {
3257
+ throw new error.MastraError(
3258
+ {
3259
+ id: storage.createStorageErrorId("DSQL", "UPDATE_SPAN", "FAILED"),
3260
+ domain: error.ErrorDomain.STORAGE,
3261
+ category: error.ErrorCategory.USER,
3262
+ details: {
3263
+ spanId,
3264
+ traceId
3265
+ }
3266
+ },
3267
+ error$1
3268
+ );
3269
+ }
3270
+ }
3271
+ async listTraces(args) {
3272
+ const { filters, pagination, orderBy } = storage.listTracesArgsSchema.parse(args);
3273
+ const page = pagination?.page ?? 0;
3274
+ const perPage = pagination?.perPage ?? 100;
3275
+ const tableName = getTableName2({
3276
+ indexName: storage.TABLE_SPANS,
3277
+ schemaName: getSchemaName2(this.#schema)
3278
+ });
3279
+ try {
3280
+ const conditions = ['r."parentSpanId" IS NULL'];
3281
+ const params = [];
3282
+ let paramIndex = 1;
3283
+ if (filters) {
3284
+ if (filters.startedAt?.start) {
3285
+ conditions.push(`r."startedAtZ" >= $${paramIndex++}`);
3286
+ params.push(filters.startedAt.start.toISOString());
3287
+ }
3288
+ if (filters.startedAt?.end) {
3289
+ conditions.push(`r."startedAtZ" <= $${paramIndex++}`);
3290
+ params.push(filters.startedAt.end.toISOString());
3291
+ }
3292
+ if (filters.endedAt?.start) {
3293
+ conditions.push(`r."endedAtZ" >= $${paramIndex++}`);
3294
+ params.push(filters.endedAt.start.toISOString());
3295
+ }
3296
+ if (filters.endedAt?.end) {
3297
+ conditions.push(`r."endedAtZ" <= $${paramIndex++}`);
3298
+ params.push(filters.endedAt.end.toISOString());
3299
+ }
3300
+ if (filters.spanType !== void 0) {
3301
+ conditions.push(`r."spanType" = $${paramIndex++}`);
3302
+ params.push(filters.spanType);
3303
+ }
3304
+ if (filters.entityType !== void 0) {
3305
+ conditions.push(`r."entityType" = $${paramIndex++}`);
3306
+ params.push(filters.entityType);
3307
+ }
3308
+ if (filters.entityId !== void 0) {
3309
+ conditions.push(`r."entityId" = $${paramIndex++}`);
3310
+ params.push(filters.entityId);
3311
+ }
3312
+ if (filters.entityName !== void 0) {
3313
+ conditions.push(`r."entityName" = $${paramIndex++}`);
3314
+ params.push(filters.entityName);
3315
+ }
3316
+ if (filters.userId !== void 0) {
3317
+ conditions.push(`r."userId" = $${paramIndex++}`);
3318
+ params.push(filters.userId);
3319
+ }
3320
+ if (filters.organizationId !== void 0) {
3321
+ conditions.push(`r."organizationId" = $${paramIndex++}`);
3322
+ params.push(filters.organizationId);
3323
+ }
3324
+ if (filters.resourceId !== void 0) {
3325
+ conditions.push(`r."resourceId" = $${paramIndex++}`);
3326
+ params.push(filters.resourceId);
3327
+ }
3328
+ if (filters.runId !== void 0) {
3329
+ conditions.push(`r."runId" = $${paramIndex++}`);
3330
+ params.push(filters.runId);
3331
+ }
3332
+ if (filters.sessionId !== void 0) {
3333
+ conditions.push(`r."sessionId" = $${paramIndex++}`);
3334
+ params.push(filters.sessionId);
3335
+ }
3336
+ if (filters.threadId !== void 0) {
3337
+ conditions.push(`r."threadId" = $${paramIndex++}`);
3338
+ params.push(filters.threadId);
3339
+ }
3340
+ if (filters.requestId !== void 0) {
3341
+ conditions.push(`r."requestId" = $${paramIndex++}`);
3342
+ params.push(filters.requestId);
3343
+ }
3344
+ if (filters.environment !== void 0) {
3345
+ conditions.push(`r."environment" = $${paramIndex++}`);
3346
+ params.push(filters.environment);
3347
+ }
3348
+ if (filters.source !== void 0) {
3349
+ conditions.push(`r."source" = $${paramIndex++}`);
3350
+ params.push(filters.source);
3351
+ }
3352
+ if (filters.serviceName !== void 0) {
3353
+ conditions.push(`r."serviceName" = $${paramIndex++}`);
3354
+ params.push(filters.serviceName);
3355
+ }
3356
+ if (filters.scope != null) {
3357
+ conditions.push(`r."scope"::text = $${paramIndex++}`);
3358
+ params.push(JSON.stringify(filters.scope));
3359
+ }
3360
+ if (filters.metadata != null) {
3361
+ conditions.push(`r."metadata"::text = $${paramIndex++}`);
3362
+ params.push(JSON.stringify(filters.metadata));
3363
+ }
3364
+ if (filters.tags != null && filters.tags.length > 0) {
3365
+ conditions.push(`r."tags"::text = $${paramIndex++}`);
3366
+ params.push(JSON.stringify(filters.tags));
3367
+ }
3368
+ if (filters.status !== void 0) {
3369
+ switch (filters.status) {
3370
+ case storage.TraceStatus.ERROR:
3371
+ conditions.push(`r."error" IS NOT NULL`);
3372
+ break;
3373
+ case storage.TraceStatus.RUNNING:
3374
+ conditions.push(`r."endedAtZ" IS NULL AND r."error" IS NULL`);
3375
+ break;
3376
+ case storage.TraceStatus.SUCCESS:
3377
+ conditions.push(`r."endedAtZ" IS NOT NULL AND r."error" IS NULL`);
3378
+ break;
3379
+ }
3380
+ }
3381
+ if (filters.hasChildError !== void 0) {
3382
+ if (filters.hasChildError) {
3383
+ conditions.push(`EXISTS (
3384
+ SELECT 1 FROM ${tableName} c
3385
+ WHERE c."traceId" = r."traceId" AND c."error" IS NOT NULL
3386
+ )`);
3387
+ } else {
3388
+ conditions.push(`NOT EXISTS (
3389
+ SELECT 1 FROM ${tableName} c
3390
+ WHERE c."traceId" = r."traceId" AND c."error" IS NOT NULL
3391
+ )`);
3392
+ }
3393
+ }
3394
+ }
3395
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
3396
+ const sortField = `${orderBy?.field ?? "startedAt"}Z`;
3397
+ const sortDirection = orderBy?.direction ?? "DESC";
3398
+ const orderClause = `ORDER BY r."${sortField}" ${sortDirection}`;
3399
+ const countResult = await this.#db.client.oneOrNone(
3400
+ `SELECT COUNT(*) FROM ${tableName} r ${whereClause}`,
3401
+ params
3402
+ );
3403
+ const count = Number(countResult?.count ?? 0);
3404
+ if (count === 0) {
3405
+ return {
3406
+ pagination: {
3407
+ total: 0,
3408
+ page,
3409
+ perPage,
3410
+ hasMore: false
3411
+ },
3412
+ spans: []
3413
+ };
3414
+ }
3415
+ const spans = await this.#db.client.manyOrNone(
3416
+ `SELECT
3417
+ r."traceId", r."spanId", r."parentSpanId", r."name",
3418
+ r."entityType", r."entityId", r."entityName",
3419
+ r."userId", r."organizationId", r."resourceId",
3420
+ r."runId", r."sessionId", r."threadId", r."requestId",
3421
+ r."environment", r."source", r."serviceName", r."scope",
3422
+ r."spanType", r."attributes", r."metadata", r."tags", r."links",
3423
+ r."input", r."output", r."error", r."isEvent",
3424
+ r."startedAtZ" as "startedAt", r."endedAtZ" as "endedAt",
3425
+ r."createdAtZ" as "createdAt", r."updatedAtZ" as "updatedAt"
3426
+ FROM ${tableName} r
3427
+ ${whereClause}
3428
+ ${orderClause}
3429
+ LIMIT $${paramIndex} OFFSET $${paramIndex + 1}`,
3430
+ [...params, perPage, page * perPage]
3431
+ );
3432
+ return {
3433
+ pagination: {
3434
+ total: count,
3435
+ page,
3436
+ perPage,
3437
+ hasMore: (page + 1) * perPage < count
3438
+ },
3439
+ spans: storage.toTraceSpans(
3440
+ spans.map(
3441
+ (span) => transformFromSqlRow({
3442
+ tableName: storage.TABLE_SPANS,
3443
+ sqlRow: span
3444
+ })
3445
+ )
3446
+ )
3447
+ };
3448
+ } catch (error$1) {
3449
+ throw new error.MastraError(
3450
+ {
3451
+ id: storage.createStorageErrorId("DSQL", "LIST_TRACES", "FAILED"),
3452
+ domain: error.ErrorDomain.STORAGE,
3453
+ category: error.ErrorCategory.USER
3454
+ },
3455
+ error$1
3456
+ );
3457
+ }
3458
+ }
3459
+ async batchCreateSpans(args) {
3460
+ try {
3461
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3462
+ const records = args.records.map((record) => {
3463
+ const startedAt = record.startedAt instanceof Date ? record.startedAt.toISOString() : record.startedAt;
3464
+ const endedAt = record.endedAt instanceof Date ? record.endedAt.toISOString() : record.endedAt;
3465
+ return {
3466
+ ...record,
3467
+ startedAt,
3468
+ endedAt,
3469
+ startedAtZ: startedAt,
3470
+ endedAtZ: endedAt,
3471
+ // Aurora DSQL doesn't support triggers, so we set timestamps explicitly
3472
+ createdAt: now,
3473
+ updatedAt: now
3474
+ };
3475
+ });
3476
+ await this.#db.batchInsert({
3477
+ tableName: storage.TABLE_SPANS,
3478
+ records
3479
+ });
3480
+ } catch (error$1) {
3481
+ throw new error.MastraError(
3482
+ {
3483
+ id: storage.createStorageErrorId("DSQL", "BATCH_CREATE_SPANS", "FAILED"),
3484
+ domain: error.ErrorDomain.STORAGE,
3485
+ category: error.ErrorCategory.USER
3486
+ },
3487
+ error$1
3488
+ );
3489
+ }
3490
+ }
3491
+ async batchUpdateSpans(args) {
3492
+ try {
3493
+ await this.#db.batchUpdate({
3494
+ tableName: storage.TABLE_SPANS,
3495
+ updates: args.records.map((record) => {
3496
+ const data = { ...record.updates };
3497
+ if (data.endedAt instanceof Date) {
3498
+ const endedAt = data.endedAt.toISOString();
3499
+ data.endedAt = endedAt;
3500
+ data.endedAtZ = endedAt;
3501
+ }
3502
+ if (data.startedAt instanceof Date) {
3503
+ const startedAt = data.startedAt.toISOString();
3504
+ data.startedAt = startedAt;
3505
+ data.startedAtZ = startedAt;
3506
+ }
3507
+ return {
3508
+ keys: { spanId: record.spanId, traceId: record.traceId },
3509
+ data
3510
+ };
3511
+ })
3512
+ });
3513
+ } catch (error$1) {
3514
+ throw new error.MastraError(
3515
+ {
3516
+ id: storage.createStorageErrorId("DSQL", "BATCH_UPDATE_SPANS", "FAILED"),
3517
+ domain: error.ErrorDomain.STORAGE,
3518
+ category: error.ErrorCategory.USER
3519
+ },
3520
+ error$1
3521
+ );
3522
+ }
3523
+ }
3524
+ async batchDeleteTraces(args) {
3525
+ const { batches } = splitIntoBatches(args.traceIds, { maxRows: DEFAULT_MAX_ROWS_PER_BATCH });
3526
+ const tableName = getTableName2({
3527
+ indexName: storage.TABLE_SPANS,
3528
+ schemaName: getSchemaName2(this.#schema)
3529
+ });
3530
+ for (const batchTraceIds of batches) {
3531
+ const placeholders = batchTraceIds.map((_, i) => `$${i + 1}`).join(", ");
3532
+ await withRetry(
3533
+ async () => {
3534
+ await this.#db.client.none(`DELETE FROM ${tableName} WHERE "traceId" IN (${placeholders})`, batchTraceIds);
3535
+ },
3536
+ {
3537
+ onRetry: (error, attempt, delay) => {
3538
+ this.logger?.warn?.(
3539
+ `batchDeleteTraces retry ${attempt} for ${batchTraceIds.length} traces after ${delay}ms: ${error.message}`
3540
+ );
3541
+ }
3542
+ }
3543
+ ).catch((error$1) => {
3544
+ throw new error.MastraError(
3545
+ {
3546
+ id: storage.createStorageErrorId("DSQL", "BATCH_DELETE_TRACES", "FAILED"),
3547
+ domain: error.ErrorDomain.STORAGE,
3548
+ category: error.ErrorCategory.USER
3549
+ },
3550
+ error$1
3551
+ );
3552
+ });
3553
+ }
3554
+ }
3555
+ };
3556
+ function transformScoreRow(row) {
3557
+ return storage.transformScoreRow(row, {
3558
+ preferredTimestampFields: {
3559
+ createdAt: "createdAtZ",
3560
+ updatedAt: "updatedAtZ"
3561
+ }
3562
+ });
3563
+ }
3564
+ var ScoresDSQL = class _ScoresDSQL extends storage.ScoresStorage {
3565
+ #db;
3566
+ #schema;
3567
+ #skipDefaultIndexes;
3568
+ #indexes;
3569
+ /** Tables managed by this domain */
3570
+ static MANAGED_TABLES = [storage.TABLE_SCORERS];
3571
+ constructor(config) {
3572
+ super();
3573
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolveDsqlConfig(config);
3574
+ this.#db = new DsqlDB({ client, schemaName, skipDefaultIndexes });
3575
+ this.#schema = schemaName || "public";
3576
+ this.#skipDefaultIndexes = skipDefaultIndexes;
3577
+ this.#indexes = indexes?.filter((idx) => _ScoresDSQL.MANAGED_TABLES.includes(idx.table));
3578
+ }
3579
+ async init() {
3580
+ await this.#db.createTable({ tableName: storage.TABLE_SCORERS, schema: storage.TABLE_SCHEMAS[storage.TABLE_SCORERS] });
3581
+ await this.createDefaultIndexes();
3582
+ await this.createCustomIndexes();
3583
+ }
3584
+ /**
3585
+ * Returns default index definitions for the scores domain tables.
3586
+ * Note: Aurora DSQL does not support ASC/DESC in index columns.
3587
+ */
3588
+ getDefaultIndexDefinitions() {
3589
+ const schemaPrefix = this.#schema !== "public" ? `${this.#schema}_` : "";
3590
+ return [
3591
+ {
3592
+ name: `${schemaPrefix}mastra_scores_trace_id_span_id_created_at_idx`,
3593
+ table: storage.TABLE_SCORERS,
3594
+ columns: ["traceId", "spanId", "createdAt"]
3595
+ }
3596
+ ];
3597
+ }
3598
+ /**
3599
+ * Creates default indexes for optimal query performance.
3600
+ */
3601
+ async createDefaultIndexes() {
3602
+ if (this.#skipDefaultIndexes) {
3603
+ return;
3604
+ }
3605
+ for (const indexDef of this.getDefaultIndexDefinitions()) {
3606
+ try {
3607
+ await this.#db.createIndex(indexDef);
3608
+ } catch (error) {
3609
+ this.logger?.warn?.(`Failed to create index ${indexDef.name}:`, error);
3610
+ }
3611
+ }
3612
+ }
3613
+ /**
3614
+ * Creates custom user-defined indexes for this domain's tables.
3615
+ */
3616
+ async createCustomIndexes() {
3617
+ if (!this.#indexes || this.#indexes.length === 0) {
3618
+ return;
3619
+ }
3620
+ for (const indexDef of this.#indexes) {
3621
+ try {
3622
+ await this.#db.createIndex(indexDef);
3623
+ } catch (error) {
3624
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
3625
+ }
3626
+ }
3627
+ }
3628
+ async dangerouslyClearAll() {
3629
+ await this.#db.clearTable({ tableName: storage.TABLE_SCORERS });
3630
+ }
3631
+ async getScoreById({ id }) {
3632
+ try {
3633
+ const result = await this.#db.client.oneOrNone(
3634
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE id = $1`,
3635
+ [id]
3636
+ );
3637
+ return result ? transformScoreRow(result) : null;
3638
+ } catch (error$1) {
3639
+ throw new error.MastraError(
3640
+ {
3641
+ id: storage.createStorageErrorId("DSQL", "GET_SCORE_BY_ID", "FAILED"),
3642
+ domain: error.ErrorDomain.STORAGE,
3643
+ category: error.ErrorCategory.THIRD_PARTY
3644
+ },
3645
+ error$1
3646
+ );
3647
+ }
3648
+ }
3649
+ async listScoresByScorerId({
3650
+ scorerId,
3651
+ pagination,
3652
+ entityId,
3653
+ entityType,
3654
+ source
3655
+ }) {
3656
+ try {
3657
+ const conditions = [`"scorerId" = $1`];
3658
+ const queryParams = [scorerId];
3659
+ let paramIndex = 2;
3660
+ if (entityId) {
3661
+ conditions.push(`"entityId" = $${paramIndex++}`);
3662
+ queryParams.push(entityId);
3663
+ }
3664
+ if (entityType) {
3665
+ conditions.push(`"entityType" = $${paramIndex++}`);
3666
+ queryParams.push(entityType);
3667
+ }
3668
+ if (source) {
3669
+ conditions.push(`"source" = $${paramIndex++}`);
3670
+ queryParams.push(source);
3671
+ }
3672
+ const whereClause = conditions.join(" AND ");
3673
+ const total = await this.#db.client.oneOrNone(
3674
+ `SELECT COUNT(*) FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE ${whereClause}`,
3675
+ queryParams
3676
+ );
3677
+ const { page, perPage: perPageInput } = pagination;
3678
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3679
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
3680
+ if (total?.count === "0" || !total?.count) {
3681
+ return {
3682
+ pagination: {
3683
+ total: 0,
3684
+ page,
3685
+ perPage: perPageForResponse,
3686
+ hasMore: false
3687
+ },
3688
+ scores: []
3689
+ };
3690
+ }
3691
+ const limitValue = perPageInput === false ? Number(total?.count) : perPage;
3692
+ const end = perPageInput === false ? Number(total?.count) : start + perPage;
3693
+ const result = await this.#db.client.manyOrNone(
3694
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE ${whereClause} ORDER BY "createdAt" DESC LIMIT $${paramIndex++} OFFSET $${paramIndex++}`,
3695
+ [...queryParams, limitValue, start]
3696
+ );
3697
+ return {
3698
+ pagination: {
3699
+ total: Number(total?.count) || 0,
3700
+ page,
3701
+ perPage: perPageForResponse,
3702
+ hasMore: end < Number(total?.count)
3703
+ },
3704
+ scores: result.map(transformScoreRow)
3705
+ };
3706
+ } catch (error$1) {
3707
+ throw new error.MastraError(
3708
+ {
3709
+ id: storage.createStorageErrorId("DSQL", "LIST_SCORES_BY_SCORER_ID", "FAILED"),
3710
+ domain: error.ErrorDomain.STORAGE,
3711
+ category: error.ErrorCategory.THIRD_PARTY
3712
+ },
3713
+ error$1
3714
+ );
3715
+ }
3716
+ }
3717
+ async saveScore(score) {
3718
+ let parsedScore;
3719
+ try {
3720
+ parsedScore = evals.saveScorePayloadSchema.parse(score);
3721
+ } catch (error$1) {
3722
+ throw new error.MastraError(
3723
+ {
3724
+ id: storage.createStorageErrorId("DSQL", "SAVE_SCORE", "VALIDATION_FAILED"),
3725
+ domain: error.ErrorDomain.STORAGE,
3726
+ category: error.ErrorCategory.USER,
3727
+ details: {
3728
+ scorer: typeof score.scorer?.id === "string" ? score.scorer.id : String(score.scorer?.id ?? "unknown"),
3729
+ entityId: score.entityId ?? "unknown",
3730
+ entityType: score.entityType ?? "unknown",
3731
+ traceId: score.traceId ?? "",
3732
+ spanId: score.spanId ?? ""
3733
+ }
3734
+ },
3735
+ error$1
3736
+ );
3737
+ }
3738
+ try {
3739
+ const id = crypto.randomUUID();
3740
+ const now = /* @__PURE__ */ new Date();
3741
+ const {
3742
+ scorer,
3743
+ preprocessStepResult,
3744
+ analyzeStepResult,
3745
+ metadata,
3746
+ input,
3747
+ output,
3748
+ additionalContext,
3749
+ requestContext,
3750
+ entity,
3751
+ ...rest
3752
+ } = parsedScore;
3753
+ await this.#db.insert({
3754
+ tableName: storage.TABLE_SCORERS,
3755
+ record: {
3756
+ id,
3757
+ ...rest,
3758
+ input: JSON.stringify(input) || "",
3759
+ output: JSON.stringify(output) || "",
3760
+ scorer: scorer ? JSON.stringify(scorer) : null,
3761
+ preprocessStepResult: preprocessStepResult ? JSON.stringify(preprocessStepResult) : null,
3762
+ analyzeStepResult: analyzeStepResult ? JSON.stringify(analyzeStepResult) : null,
3763
+ metadata: metadata ? JSON.stringify(metadata) : null,
3764
+ additionalContext: additionalContext ? JSON.stringify(additionalContext) : null,
3765
+ requestContext: requestContext ? JSON.stringify(requestContext) : null,
3766
+ entity: entity ? JSON.stringify(entity) : null,
3767
+ createdAt: now.toISOString(),
3768
+ updatedAt: now.toISOString()
3769
+ }
3770
+ });
3771
+ return { score: { ...parsedScore, id, createdAt: now, updatedAt: now } };
3772
+ } catch (error$1) {
3773
+ throw new error.MastraError(
3774
+ {
3775
+ id: storage.createStorageErrorId("DSQL", "SAVE_SCORE", "FAILED"),
3776
+ domain: error.ErrorDomain.STORAGE,
3777
+ category: error.ErrorCategory.THIRD_PARTY
3778
+ },
3779
+ error$1
3780
+ );
3781
+ }
3782
+ }
3783
+ async listScoresByRunId({
3784
+ runId,
3785
+ pagination
3786
+ }) {
3787
+ try {
3788
+ const total = await this.#db.client.oneOrNone(
3789
+ `SELECT COUNT(*) FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE "runId" = $1`,
3790
+ [runId]
3791
+ );
3792
+ const { page, perPage: perPageInput } = pagination;
3793
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3794
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
3795
+ if (total?.count === "0" || !total?.count) {
3796
+ return {
3797
+ pagination: {
3798
+ total: 0,
3799
+ page,
3800
+ perPage: perPageForResponse,
3801
+ hasMore: false
3802
+ },
3803
+ scores: []
3804
+ };
3805
+ }
3806
+ const limitValue = perPageInput === false ? Number(total?.count) : perPage;
3807
+ const end = perPageInput === false ? Number(total?.count) : start + perPage;
3808
+ const result = await this.#db.client.manyOrNone(
3809
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE "runId" = $1 ORDER BY "createdAt" DESC LIMIT $2 OFFSET $3`,
3810
+ [runId, limitValue, start]
3811
+ );
3812
+ return {
3813
+ pagination: {
3814
+ total: Number(total?.count) || 0,
3815
+ page,
3816
+ perPage: perPageForResponse,
3817
+ hasMore: end < Number(total?.count)
3818
+ },
3819
+ scores: result.map(transformScoreRow)
3820
+ };
3821
+ } catch (error$1) {
3822
+ throw new error.MastraError(
3823
+ {
3824
+ id: storage.createStorageErrorId("DSQL", "LIST_SCORES_BY_RUN_ID", "FAILED"),
3825
+ domain: error.ErrorDomain.STORAGE,
3826
+ category: error.ErrorCategory.THIRD_PARTY
3827
+ },
3828
+ error$1
3829
+ );
3830
+ }
3831
+ }
3832
+ async listScoresByEntityId({
3833
+ entityId,
3834
+ entityType,
3835
+ pagination
3836
+ }) {
3837
+ try {
3838
+ const total = await this.#db.client.oneOrNone(
3839
+ `SELECT COUNT(*) FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE "entityId" = $1 AND "entityType" = $2`,
3840
+ [entityId, entityType]
3841
+ );
3842
+ const { page, perPage: perPageInput } = pagination;
3843
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3844
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
3845
+ if (total?.count === "0" || !total?.count) {
3846
+ return {
3847
+ pagination: {
3848
+ total: 0,
3849
+ page,
3850
+ perPage: perPageForResponse,
3851
+ hasMore: false
3852
+ },
3853
+ scores: []
3854
+ };
3855
+ }
3856
+ const limitValue = perPageInput === false ? Number(total?.count) : perPage;
3857
+ const end = perPageInput === false ? Number(total?.count) : start + perPage;
3858
+ const result = await this.#db.client.manyOrNone(
3859
+ `SELECT * FROM ${getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) })} WHERE "entityId" = $1 AND "entityType" = $2 ORDER BY "createdAt" DESC LIMIT $3 OFFSET $4`,
3860
+ [entityId, entityType, limitValue, start]
3861
+ );
3862
+ return {
3863
+ pagination: {
3864
+ total: Number(total?.count) || 0,
3865
+ page,
3866
+ perPage: perPageForResponse,
3867
+ hasMore: end < Number(total?.count)
3868
+ },
3869
+ scores: result.map(transformScoreRow)
3870
+ };
3871
+ } catch (error$1) {
3872
+ throw new error.MastraError(
3873
+ {
3874
+ id: storage.createStorageErrorId("DSQL", "LIST_SCORES_BY_ENTITY_ID", "FAILED"),
3875
+ domain: error.ErrorDomain.STORAGE,
3876
+ category: error.ErrorCategory.THIRD_PARTY
3877
+ },
3878
+ error$1
3879
+ );
3880
+ }
3881
+ }
3882
+ async listScoresBySpan({
3883
+ traceId,
3884
+ spanId,
3885
+ pagination
3886
+ }) {
3887
+ try {
3888
+ const tableName = getTableName2({ indexName: storage.TABLE_SCORERS, schemaName: getSchemaName2(this.#schema) });
3889
+ const countSQLResult = await this.#db.client.oneOrNone(
3890
+ `SELECT COUNT(*) as count FROM ${tableName} WHERE "traceId" = $1 AND "spanId" = $2`,
3891
+ [traceId, spanId]
3892
+ );
3893
+ const total = Number(countSQLResult?.count ?? 0);
3894
+ const { page, perPage: perPageInput } = pagination;
3895
+ const perPage = storage.normalizePerPage(perPageInput, 100);
3896
+ const { offset: start, perPage: perPageForResponse } = storage.calculatePagination(page, perPageInput, perPage);
3897
+ const limitValue = perPageInput === false ? total : perPage;
3898
+ const end = perPageInput === false ? total : start + perPage;
3899
+ const result = await this.#db.client.manyOrNone(
3900
+ `SELECT * FROM ${tableName} WHERE "traceId" = $1 AND "spanId" = $2 ORDER BY "createdAt" DESC LIMIT $3 OFFSET $4`,
3901
+ [traceId, spanId, limitValue, start]
3902
+ );
3903
+ const hasMore = end < total;
3904
+ const scores = result.map((row) => transformScoreRow(row)) ?? [];
3905
+ return {
3906
+ scores,
3907
+ pagination: {
3908
+ total,
3909
+ page,
3910
+ perPage: perPageForResponse,
3911
+ hasMore
3912
+ }
3913
+ };
3914
+ } catch (error$1) {
3915
+ throw new error.MastraError(
3916
+ {
3917
+ id: storage.createStorageErrorId("DSQL", "LIST_SCORES_BY_SPAN", "FAILED"),
3918
+ domain: error.ErrorDomain.STORAGE,
3919
+ category: error.ErrorCategory.THIRD_PARTY
3920
+ },
3921
+ error$1
3922
+ );
3923
+ }
3924
+ }
3925
+ };
3926
+ function parseWorkflowRun(row) {
3927
+ let parsedSnapshot = row.snapshot;
3928
+ if (typeof parsedSnapshot === "string") {
3929
+ try {
3930
+ parsedSnapshot = JSON.parse(row.snapshot);
3931
+ } catch (e) {
3932
+ console.warn(`Failed to parse snapshot for workflow ${row.workflow_name}: ${e}`);
3933
+ }
3934
+ }
3935
+ return {
3936
+ workflowName: row.workflow_name,
3937
+ runId: row.run_id,
3938
+ snapshot: parsedSnapshot,
3939
+ resourceId: row.resourceId,
3940
+ createdAt: new Date(row.createdAtZ || row.createdAt),
3941
+ updatedAt: new Date(row.updatedAtZ || row.updatedAt)
3942
+ };
3943
+ }
3944
+ var WorkflowsDSQL = class _WorkflowsDSQL extends storage.WorkflowsStorage {
3945
+ #db;
3946
+ #schema;
3947
+ #skipDefaultIndexes;
3948
+ #indexes;
3949
+ /** Tables managed by this domain */
3950
+ static MANAGED_TABLES = [storage.TABLE_WORKFLOW_SNAPSHOT];
3951
+ constructor(config) {
3952
+ super();
3953
+ const { client, schemaName, skipDefaultIndexes, indexes } = resolveDsqlConfig(config);
3954
+ this.#db = new DsqlDB({ client, schemaName });
3955
+ this.#schema = schemaName || "public";
3956
+ this.#skipDefaultIndexes = skipDefaultIndexes;
3957
+ this.#indexes = indexes?.filter((idx) => _WorkflowsDSQL.MANAGED_TABLES.includes(idx.table));
3958
+ }
3959
+ supportsConcurrentUpdates() {
3960
+ return true;
3961
+ }
3962
+ /**
3963
+ * Returns default index definitions for the workflows domain tables.
3964
+ * Currently no default indexes are defined for workflows.
3965
+ */
3966
+ getDefaultIndexDefinitions() {
3967
+ return [];
3968
+ }
3969
+ /**
3970
+ * Creates default indexes for optimal query performance.
3971
+ * Currently no default indexes are defined for workflows.
3972
+ */
3973
+ async createDefaultIndexes() {
3974
+ if (this.#skipDefaultIndexes) {
3975
+ return;
3976
+ }
3977
+ }
3978
+ async init() {
3979
+ await this.#db.createTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT, schema: storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT] });
3980
+ await this.#db.alterTable({
3981
+ tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
3982
+ schema: storage.TABLE_SCHEMAS[storage.TABLE_WORKFLOW_SNAPSHOT],
3983
+ ifNotExists: ["resourceId"]
3984
+ });
3985
+ await this.createDefaultIndexes();
3986
+ await this.createCustomIndexes();
3987
+ }
3988
+ /**
3989
+ * Creates custom user-defined indexes for this domain's tables.
3990
+ */
3991
+ async createCustomIndexes() {
3992
+ if (!this.#indexes || this.#indexes.length === 0) {
3993
+ return;
3994
+ }
3995
+ for (const indexDef of this.#indexes) {
3996
+ try {
3997
+ await this.#db.createIndex(indexDef);
3998
+ } catch (error) {
3999
+ this.logger?.warn?.(`Failed to create custom index ${indexDef.name}:`, error);
4000
+ }
4001
+ }
4002
+ }
4003
+ async dangerouslyClearAll() {
4004
+ await this.#db.clearTable({ tableName: storage.TABLE_WORKFLOW_SNAPSHOT });
4005
+ }
4006
+ async updateWorkflowResults({
4007
+ workflowName,
4008
+ runId,
4009
+ stepId,
4010
+ result,
4011
+ requestContext
4012
+ }) {
4013
+ try {
4014
+ const { result: context } = await withRetry(
4015
+ async () => {
4016
+ return this.#db.client.tx(async (t) => {
4017
+ const tableName = getTableName2({
4018
+ indexName: storage.TABLE_WORKFLOW_SNAPSHOT,
4019
+ schemaName: getSchemaName2(this.#schema)
4020
+ });
4021
+ const existingSnapshotResult = await t.oneOrNone(
4022
+ `SELECT snapshot FROM ${tableName} WHERE workflow_name = $1 AND run_id = $2`,
4023
+ [workflowName, runId]
4024
+ );
4025
+ let snapshot;
4026
+ if (!existingSnapshotResult) {
4027
+ snapshot = {
4028
+ context: {},
4029
+ activePaths: [],
4030
+ timestamp: Date.now(),
4031
+ suspendedPaths: {},
4032
+ activeStepsPath: {},
4033
+ resumeLabels: {},
4034
+ serializedStepGraph: [],
4035
+ status: "pending",
4036
+ value: {},
4037
+ waitingPaths: {},
4038
+ runId,
4039
+ requestContext: {}
4040
+ };
4041
+ } else {
4042
+ const existingSnapshot = existingSnapshotResult.snapshot;
4043
+ snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
4044
+ }
4045
+ snapshot.context[stepId] = result;
4046
+ snapshot.requestContext = { ...snapshot.requestContext, ...requestContext };
4047
+ const now = /* @__PURE__ */ new Date();
4048
+ await t.none(
4049
+ `INSERT INTO ${tableName} (workflow_name, run_id, snapshot, "createdAt", "updatedAt")
4050
+ VALUES ($1, $2, $3, $4, $5)
4051
+ ON CONFLICT (workflow_name, run_id) DO UPDATE
4052
+ SET snapshot = $3, "updatedAt" = $5`,
4053
+ [workflowName, runId, JSON.stringify(snapshot), now, now]
4054
+ );
4055
+ return snapshot.context;
4056
+ });
4057
+ },
4058
+ {
4059
+ onRetry: (error, attempt, delay) => {
4060
+ this.logger?.warn?.(
4061
+ `updateWorkflowResults retry ${attempt} for workflow ${workflowName}/${runId} after ${delay}ms: ${error.message}`
4062
+ );
4063
+ }
4064
+ }
4065
+ );
4066
+ return context;
4067
+ } catch (error$1) {
4068
+ throw new error.MastraError(
4069
+ {
4070
+ id: storage.createStorageErrorId("DSQL", "UPDATE_WORKFLOW_RESULTS", "FAILED"),
4071
+ domain: error.ErrorDomain.STORAGE,
4072
+ category: error.ErrorCategory.THIRD_PARTY,
4073
+ details: {
4074
+ workflowName,
4075
+ runId,
4076
+ stepId
4077
+ }
4078
+ },
4079
+ error$1
4080
+ );
4081
+ }
4082
+ }
4083
+ async updateWorkflowState({
4084
+ workflowName,
4085
+ runId,
4086
+ opts
4087
+ }) {
4088
+ try {
4089
+ const { result } = await withRetry(
4090
+ async () => {
4091
+ return this.#db.client.tx(async (t) => {
4092
+ const tableName = getTableName2({
4093
+ indexName: storage.TABLE_WORKFLOW_SNAPSHOT,
4094
+ schemaName: getSchemaName2(this.#schema)
4095
+ });
4096
+ const existingSnapshotResult = await t.oneOrNone(
4097
+ `SELECT snapshot FROM ${tableName} WHERE workflow_name = $1 AND run_id = $2`,
4098
+ [workflowName, runId]
4099
+ );
4100
+ if (!existingSnapshotResult) {
4101
+ return void 0;
4102
+ }
4103
+ const existingSnapshot = existingSnapshotResult.snapshot;
4104
+ const snapshot = typeof existingSnapshot === "string" ? JSON.parse(existingSnapshot) : existingSnapshot;
4105
+ if (!snapshot || !snapshot?.context) {
4106
+ throw new Error(`Snapshot not found for runId ${runId}`);
4107
+ }
4108
+ const updatedSnapshot = { ...snapshot, ...opts };
4109
+ await t.none(
4110
+ `UPDATE ${tableName} SET snapshot = $1, "updatedAt" = $2 WHERE workflow_name = $3 AND run_id = $4`,
4111
+ [JSON.stringify(updatedSnapshot), /* @__PURE__ */ new Date(), workflowName, runId]
4112
+ );
4113
+ return updatedSnapshot;
4114
+ });
4115
+ },
4116
+ {
4117
+ onRetry: (error, attempt, delay) => {
4118
+ this.logger?.warn?.(
4119
+ `updateWorkflowState retry ${attempt} for workflow ${workflowName}/${runId} after ${delay}ms: ${error.message}`
4120
+ );
4121
+ }
4122
+ }
4123
+ );
4124
+ return result;
4125
+ } catch (error$1) {
4126
+ throw new error.MastraError(
4127
+ {
4128
+ id: storage.createStorageErrorId("DSQL", "UPDATE_WORKFLOW_STATE", "FAILED"),
4129
+ domain: error.ErrorDomain.STORAGE,
4130
+ category: error.ErrorCategory.THIRD_PARTY,
4131
+ details: {
4132
+ workflowName,
4133
+ runId
4134
+ }
4135
+ },
4136
+ error$1
4137
+ );
4138
+ }
4139
+ }
4140
+ async persistWorkflowSnapshot({
4141
+ workflowName,
4142
+ runId,
4143
+ resourceId,
4144
+ snapshot,
4145
+ createdAt,
4146
+ updatedAt
4147
+ }) {
4148
+ try {
4149
+ const now = /* @__PURE__ */ new Date();
4150
+ const createdAtValue = createdAt ? createdAt : now;
4151
+ const updatedAtValue = updatedAt ? updatedAt : now;
4152
+ await this.#db.client.none(
4153
+ `INSERT INTO ${getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.#schema) })} (workflow_name, run_id, "resourceId", snapshot, "createdAt", "updatedAt")
4154
+ VALUES ($1, $2, $3, $4, $5, $6)
4155
+ ON CONFLICT (workflow_name, run_id) DO UPDATE
4156
+ SET "resourceId" = $3, snapshot = $4, "updatedAt" = $6`,
4157
+ [
4158
+ workflowName,
4159
+ runId,
4160
+ resourceId,
4161
+ JSON.stringify(snapshot),
4162
+ createdAtValue.toISOString(),
4163
+ updatedAtValue.toISOString()
4164
+ ]
4165
+ );
4166
+ } catch (error$1) {
4167
+ throw new error.MastraError(
4168
+ {
4169
+ id: storage.createStorageErrorId("DSQL", "PERSIST_WORKFLOW_SNAPSHOT", "FAILED"),
4170
+ domain: error.ErrorDomain.STORAGE,
4171
+ category: error.ErrorCategory.THIRD_PARTY
4172
+ },
4173
+ error$1
4174
+ );
4175
+ }
4176
+ }
4177
+ async loadWorkflowSnapshot({
4178
+ workflowName,
4179
+ runId
4180
+ }) {
4181
+ try {
4182
+ const result = await this.#db.load({
4183
+ tableName: storage.TABLE_WORKFLOW_SNAPSHOT,
4184
+ keys: { workflow_name: workflowName, run_id: runId }
4185
+ });
4186
+ return result ? result.snapshot : null;
4187
+ } catch (error$1) {
4188
+ throw new error.MastraError(
4189
+ {
4190
+ id: storage.createStorageErrorId("DSQL", "LOAD_WORKFLOW_SNAPSHOT", "FAILED"),
4191
+ domain: error.ErrorDomain.STORAGE,
4192
+ category: error.ErrorCategory.THIRD_PARTY
4193
+ },
4194
+ error$1
4195
+ );
4196
+ }
4197
+ }
4198
+ async getWorkflowRunById({
4199
+ runId,
4200
+ workflowName
4201
+ }) {
4202
+ try {
4203
+ const conditions = [];
4204
+ const values = [];
4205
+ let paramIndex = 1;
4206
+ if (runId) {
4207
+ conditions.push(`run_id = $${paramIndex}`);
4208
+ values.push(runId);
4209
+ paramIndex++;
4210
+ }
4211
+ if (workflowName) {
4212
+ conditions.push(`workflow_name = $${paramIndex}`);
4213
+ values.push(workflowName);
4214
+ paramIndex++;
4215
+ }
4216
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4217
+ const query = `
4218
+ SELECT * FROM ${getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.#schema) })}
4219
+ ${whereClause}
4220
+ ORDER BY "createdAt" DESC LIMIT 1
4221
+ `;
4222
+ const queryValues = values;
4223
+ const result = await this.#db.client.oneOrNone(query, queryValues);
4224
+ if (!result) {
4225
+ return null;
4226
+ }
4227
+ return parseWorkflowRun(result);
4228
+ } catch (error$1) {
4229
+ throw new error.MastraError(
4230
+ {
4231
+ id: storage.createStorageErrorId("DSQL", "GET_WORKFLOW_RUN_BY_ID", "FAILED"),
4232
+ domain: error.ErrorDomain.STORAGE,
4233
+ category: error.ErrorCategory.THIRD_PARTY,
4234
+ details: {
4235
+ runId,
4236
+ workflowName: workflowName || ""
4237
+ }
4238
+ },
4239
+ error$1
4240
+ );
4241
+ }
4242
+ }
4243
+ async deleteWorkflowRunById({ runId, workflowName }) {
4244
+ try {
4245
+ await this.#db.client.none(
4246
+ `DELETE FROM ${getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.#schema) })} WHERE run_id = $1 AND workflow_name = $2`,
4247
+ [runId, workflowName]
4248
+ );
4249
+ } catch (error$1) {
4250
+ throw new error.MastraError(
4251
+ {
4252
+ id: storage.createStorageErrorId("DSQL", "DELETE_WORKFLOW_RUN_BY_ID", "FAILED"),
4253
+ domain: error.ErrorDomain.STORAGE,
4254
+ category: error.ErrorCategory.THIRD_PARTY,
4255
+ details: {
4256
+ runId,
4257
+ workflowName
4258
+ }
4259
+ },
4260
+ error$1
4261
+ );
4262
+ }
4263
+ }
4264
+ async listWorkflowRuns({
4265
+ workflowName,
4266
+ fromDate,
4267
+ toDate,
4268
+ perPage,
4269
+ page,
4270
+ resourceId,
4271
+ status
4272
+ } = {}) {
4273
+ try {
4274
+ const conditions = [];
4275
+ const values = [];
4276
+ let paramIndex = 1;
4277
+ if (workflowName) {
4278
+ conditions.push(`workflow_name = $${paramIndex}`);
4279
+ values.push(workflowName);
4280
+ paramIndex++;
4281
+ }
4282
+ if (status) {
4283
+ conditions.push(`snapshot::jsonb ->> 'status' = $${paramIndex}`);
4284
+ values.push(status);
4285
+ paramIndex++;
4286
+ }
4287
+ if (resourceId) {
4288
+ const hasResourceId = await this.#db.hasColumn(storage.TABLE_WORKFLOW_SNAPSHOT, "resourceId");
4289
+ if (hasResourceId) {
4290
+ conditions.push(`"resourceId" = $${paramIndex}`);
4291
+ values.push(resourceId);
4292
+ paramIndex++;
4293
+ } else {
4294
+ console.warn(`[${storage.TABLE_WORKFLOW_SNAPSHOT}] resourceId column not found. Skipping resourceId filter.`);
4295
+ }
4296
+ }
4297
+ if (fromDate) {
4298
+ conditions.push(`"createdAt" >= $${paramIndex}`);
4299
+ values.push(fromDate instanceof Date ? fromDate.toISOString() : fromDate);
4300
+ paramIndex++;
4301
+ }
4302
+ if (toDate) {
4303
+ conditions.push(`"createdAt" <= $${paramIndex}`);
4304
+ values.push(toDate instanceof Date ? toDate.toISOString() : toDate);
4305
+ paramIndex++;
4306
+ }
4307
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
4308
+ let total = 0;
4309
+ const usePagination = typeof perPage === "number" && typeof page === "number";
4310
+ if (usePagination) {
4311
+ const countResult = await this.#db.client.one(
4312
+ `SELECT COUNT(*) as count FROM ${getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.#schema) })} ${whereClause}`,
4313
+ values
4314
+ );
4315
+ total = Number(countResult.count);
4316
+ }
4317
+ const normalizedPerPage = usePagination ? storage.normalizePerPage(perPage, Number.MAX_SAFE_INTEGER) : 0;
4318
+ const offset = usePagination ? page * normalizedPerPage : void 0;
4319
+ const query = `
4320
+ SELECT * FROM ${getTableName2({ indexName: storage.TABLE_WORKFLOW_SNAPSHOT, schemaName: getSchemaName2(this.#schema) })}
4321
+ ${whereClause}
4322
+ ORDER BY "createdAt" DESC
4323
+ ${usePagination ? ` LIMIT $${paramIndex} OFFSET $${paramIndex + 1}` : ""}
4324
+ `;
4325
+ const queryValues = usePagination ? [...values, normalizedPerPage, offset] : values;
4326
+ const result = await this.#db.client.manyOrNone(query, queryValues);
4327
+ const runs = (result || []).map((row) => {
4328
+ return parseWorkflowRun(row);
4329
+ });
4330
+ return { runs, total: total || runs.length };
4331
+ } catch (error$1) {
4332
+ throw new error.MastraError(
4333
+ {
4334
+ id: storage.createStorageErrorId("DSQL", "LIST_WORKFLOW_RUNS", "FAILED"),
4335
+ domain: error.ErrorDomain.STORAGE,
4336
+ category: error.ErrorCategory.THIRD_PARTY,
4337
+ details: {
4338
+ workflowName: workflowName || "all"
4339
+ }
4340
+ },
4341
+ error$1
4342
+ );
4343
+ }
4344
+ }
4345
+ };
4346
+
4347
+ // src/storage/index.ts
4348
+ var DSQLStore = class extends storage.MastraStorage {
4349
+ #pool;
4350
+ #db;
4351
+ #ownsPool;
4352
+ schema;
4353
+ isInitialized = false;
4354
+ stores;
4355
+ constructor(config) {
4356
+ try {
4357
+ validateConfig(config);
4358
+ super({ id: config.id, name: "DSQLStore", disableInit: config.disableInit });
4359
+ this.schema = config.schemaName || "public";
4360
+ if (isPoolConfig(config)) {
4361
+ this.#pool = config.pool;
4362
+ this.#ownsPool = false;
4363
+ } else {
4364
+ this.#pool = this.createPool(config);
4365
+ this.#ownsPool = true;
4366
+ }
4367
+ this.#db = new PoolAdapter(this.#pool);
4368
+ const domainConfig = {
4369
+ client: this.#db,
4370
+ schemaName: this.schema,
4371
+ skipDefaultIndexes: config.skipDefaultIndexes,
4372
+ indexes: config.indexes
4373
+ };
4374
+ this.stores = {
4375
+ scores: new ScoresDSQL(domainConfig),
4376
+ workflows: new WorkflowsDSQL(domainConfig),
4377
+ memory: new MemoryDSQL(domainConfig),
4378
+ observability: new ObservabilityDSQL(domainConfig),
4379
+ agents: new AgentsDSQL(domainConfig)
4380
+ };
4381
+ } catch (e) {
4382
+ throw new error.MastraError(
4383
+ {
4384
+ id: storage.createStorageErrorId("DSQL", "INITIALIZATION", "FAILED"),
4385
+ domain: error.ErrorDomain.STORAGE,
4386
+ category: error.ErrorCategory.USER
4387
+ },
4388
+ e
4389
+ );
4390
+ }
4391
+ }
4392
+ /**
4393
+ * Creates a connection pool with AuroraDSQLClient for IAM authentication.
4394
+ */
4395
+ createPool(config) {
4396
+ if (!isHostConfig(config)) {
4397
+ throw new Error("DSQLStore: Invalid configuration for creating pool.");
4398
+ }
4399
+ const region = getEffectiveRegion(config);
4400
+ const poolConfig = {
4401
+ host: config.host,
4402
+ user: config.user ?? "admin",
4403
+ database: config.database ?? "postgres",
4404
+ // Use AuroraDSQLClient for automatic IAM token generation
4405
+ Client: auroraDsqlNodePostgresConnector.AuroraDSQLClient,
4406
+ // Pass region for IAM token generation
4407
+ region,
4408
+ // Custom credentials provider (optional)
4409
+ customCredentialsProvider: config.customCredentialsProvider,
4410
+ // Pool settings optimized for Aurora DSQL
4411
+ max: config.max ?? DSQL_POOL_DEFAULTS.max,
4412
+ min: config.min ?? DSQL_POOL_DEFAULTS.min,
4413
+ idleTimeoutMillis: config.idleTimeoutMillis ?? DSQL_POOL_DEFAULTS.idleTimeoutMillis,
4414
+ maxLifetimeSeconds: config.maxLifetimeSeconds ?? DSQL_POOL_DEFAULTS.maxLifetimeSeconds,
4415
+ connectionTimeoutMillis: config.connectionTimeoutMillis ?? DSQL_POOL_DEFAULTS.connectionTimeoutMillis,
4416
+ allowExitOnIdle: config.allowExitOnIdle ?? DSQL_POOL_DEFAULTS.allowExitOnIdle
4417
+ };
4418
+ return new pg.Pool(poolConfig);
4419
+ }
4420
+ async init() {
4421
+ if (this.isInitialized) {
4422
+ return;
4423
+ }
4424
+ try {
4425
+ this.isInitialized = true;
4426
+ await super.init();
4427
+ } catch (error$1) {
4428
+ this.isInitialized = false;
4429
+ throw new error.MastraError(
4430
+ {
4431
+ id: storage.createStorageErrorId("DSQL", "INIT", "FAILED"),
4432
+ domain: error.ErrorDomain.STORAGE,
4433
+ category: error.ErrorCategory.THIRD_PARTY
4434
+ },
4435
+ error$1
4436
+ );
4437
+ }
4438
+ }
4439
+ /**
4440
+ * Database client for executing queries.
4441
+ *
4442
+ * @example
4443
+ * ```typescript
4444
+ * const rows = await store.db.any('SELECT * FROM users WHERE active = $1', [true]);
4445
+ * const user = await store.db.one('SELECT * FROM users WHERE id = $1', [userId]);
4446
+ * ```
4447
+ */
4448
+ get db() {
4449
+ return this.#db;
4450
+ }
4451
+ /**
4452
+ * The underlying pg.Pool for direct database access or ORM integration.
4453
+ */
4454
+ get pool() {
4455
+ return this.#pool;
4456
+ }
4457
+ /**
4458
+ * Closes the connection pool if it was created by this store.
4459
+ * If a pool was passed in via config, it will not be closed.
4460
+ */
4461
+ async close() {
4462
+ if (this.#ownsPool) {
4463
+ await this.#pool.end();
4464
+ }
4465
+ this.isInitialized = false;
4466
+ }
4467
+ };
4468
+
4469
+ exports.AgentsDSQL = AgentsDSQL;
4470
+ exports.DSQLStore = DSQLStore;
4471
+ exports.DSQL_POOL_DEFAULTS = DSQL_POOL_DEFAULTS;
4472
+ exports.MemoryDSQL = MemoryDSQL;
4473
+ exports.ObservabilityDSQL = ObservabilityDSQL;
4474
+ exports.PoolAdapter = PoolAdapter;
4475
+ exports.ScoresDSQL = ScoresDSQL;
4476
+ exports.WorkflowsDSQL = WorkflowsDSQL;
4477
+ //# sourceMappingURL=index.cjs.map
4478
+ //# sourceMappingURL=index.cjs.map