@mastra/mysql 0.7.1-alpha.0 → 0.7.1-alpha.2
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.
- package/CHANGELOG.md +30 -0
- package/dist/index.cjs +129 -27
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +129 -27
- package/dist/index.js.map +1 -1
- package/dist/storage/db/schema-snapshot.d.ts +55 -0
- package/dist/storage/db/schema-snapshot.d.ts.map +1 -0
- package/dist/storage/domains/agents/index.d.ts.map +1 -1
- package/dist/storage/domains/memory/index.d.ts.map +1 -1
- package/dist/storage/domains/operations/index.d.ts +16 -0
- package/dist/storage/domains/operations/index.d.ts.map +1 -1
- package/dist/storage/index.d.ts +1 -0
- package/dist/storage/index.d.ts.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
# @mastra/mysql
|
|
2
2
|
|
|
3
|
+
## 0.7.1-alpha.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- Cut warm initialization from around 110 client-server round trips to single digits with an init-scoped schema snapshot, on top of the column-probe casing fix that removed the ALTER TABLE storm. Three information_schema reads at the start of init() now answer table, column, and index existence locally; createTable, alterTable, createIndex, and hasColumn consult the snapshot and maintain it as objects are created, and the memory domain's raw CREATE INDEX for idx_om_lookup_key consults it too instead of raising and swallowing ER_DUP_KEYNAME on every boot. The snapshot lives for exactly the init window and is cleared in a finally, so runtime callers keep querying the live catalog. Measured on docker mysql:9.7: warm init 109 to 111 round trips down to 7 (6 excluding measurement scaffolding), cold init 253 down to 153 or 154 across runs, with an identical cold-init table and index census before and after. ([#21634](https://github.com/mastra-ai/mastra/pull/21634))
|
|
8
|
+
|
|
9
|
+
- Updated dependencies [[`6db7a5d`](https://github.com/mastra-ai/mastra/commit/6db7a5dd3dd2b6f7ef75dcd804fcffef5fa83963), [`0cdc5dc`](https://github.com/mastra-ai/mastra/commit/0cdc5dc69024957815da4f51acc4119eb4f447d7)]:
|
|
10
|
+
- @mastra/core@1.60.0-alpha.12
|
|
11
|
+
|
|
12
|
+
## 0.7.1-alpha.1
|
|
13
|
+
|
|
14
|
+
### Patch Changes
|
|
15
|
+
|
|
16
|
+
- Added a `durable` option to stored agents so agents created through the Agents API can run with durable execution — no code deployment required. ([#21715](https://github.com/mastra-ai/mastra/pull/21715))
|
|
17
|
+
|
|
18
|
+
```typescript
|
|
19
|
+
await mastraClient.createStoredAgent({
|
|
20
|
+
id: 'helper',
|
|
21
|
+
name: 'Helper',
|
|
22
|
+
instructions: 'You are a helpful assistant.',
|
|
23
|
+
model: { provider: 'openai', name: 'gpt-5' },
|
|
24
|
+
durable: true,
|
|
25
|
+
});
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Pass `true` for defaults, or `{ maxSteps, cleanupTimeoutMs }` to tune the durable loop. Cache and pubsub are inherited from the server's Mastra instance, so configure distributed backends there for durability across replicas. Automatic recovery is still configured in code via `recovery.durableAgents`.
|
|
29
|
+
|
|
30
|
+
- Updated dependencies [[`6223446`](https://github.com/mastra-ai/mastra/commit/6223446ddce6166e96e0ba5e00d628b615dee8ca), [`583e235`](https://github.com/mastra-ai/mastra/commit/583e23519c13af16c1746f9c49722d011216611b), [`a77f8d4`](https://github.com/mastra-ai/mastra/commit/a77f8d4740d2178a74c41e4bf678b4fcd8fa0bb2), [`40d358e`](https://github.com/mastra-ai/mastra/commit/40d358e29d55543803e64b49241122f598ffabc7), [`e80cd7e`](https://github.com/mastra-ai/mastra/commit/e80cd7e7683e7d732e1cc6784bcac1d2640d2ce3), [`20504b2`](https://github.com/mastra-ai/mastra/commit/20504b2ecebd0e077acda3d457ab57480a98ed3e)]:
|
|
31
|
+
- @mastra/core@1.60.0-alpha.11
|
|
32
|
+
|
|
3
33
|
## 0.7.1-alpha.0
|
|
4
34
|
|
|
5
35
|
### Patch Changes
|
package/dist/index.cjs
CHANGED
|
@@ -6,6 +6,46 @@ let _mastra_core_utils = require("@mastra/core/utils");
|
|
|
6
6
|
let crypto$1 = require("crypto");
|
|
7
7
|
let _mastra_core_agent = require("@mastra/core/agent");
|
|
8
8
|
let _mastra_core_storage_domains_skills = require("@mastra/core/storage/domains/skills");
|
|
9
|
+
//#region src/storage/db/schema-snapshot.ts
|
|
10
|
+
/** Builds the `table.index` presence key the snapshot uses. */
|
|
11
|
+
function indexKey(table, index) {
|
|
12
|
+
return `${table.toLowerCase()}.${index.toLowerCase()}`;
|
|
13
|
+
}
|
|
14
|
+
const lower = (value) => String(value).toLowerCase();
|
|
15
|
+
/**
|
|
16
|
+
* Reads the catalog for `schemaName` in three queries. Returns null when no
|
|
17
|
+
* schema name is available (a pool with no default database): correctness over
|
|
18
|
+
* optimization, callers fall back to today's per-probe behavior.
|
|
19
|
+
*/
|
|
20
|
+
async function loadSchemaSnapshot(pool, schemaName) {
|
|
21
|
+
if (!schemaName) return null;
|
|
22
|
+
const [[tableRows], [columnRows], [indexRows]] = await Promise.all([
|
|
23
|
+
pool.execute(`SELECT table_name FROM information_schema.tables WHERE table_schema = ?`, [schemaName]),
|
|
24
|
+
pool.execute(`SELECT table_name, column_name FROM information_schema.columns WHERE table_schema = ?`, [schemaName]),
|
|
25
|
+
pool.execute(`SELECT DISTINCT table_name, index_name FROM information_schema.statistics WHERE table_schema = ?`, [schemaName])
|
|
26
|
+
]);
|
|
27
|
+
const tables = /* @__PURE__ */ new Set();
|
|
28
|
+
for (const row of tableRows ?? []) tables.add(lower(row.table_name ?? row.TABLE_NAME));
|
|
29
|
+
const columns = /* @__PURE__ */ new Map();
|
|
30
|
+
for (const row of columnRows ?? []) {
|
|
31
|
+
const table = lower(row.table_name ?? row.TABLE_NAME);
|
|
32
|
+
let set = columns.get(table);
|
|
33
|
+
if (!set) {
|
|
34
|
+
set = /* @__PURE__ */ new Set();
|
|
35
|
+
columns.set(table, set);
|
|
36
|
+
}
|
|
37
|
+
set.add(lower(row.column_name ?? row.COLUMN_NAME));
|
|
38
|
+
}
|
|
39
|
+
const indexes = /* @__PURE__ */ new Set();
|
|
40
|
+
for (const row of indexRows ?? []) indexes.add(indexKey(lower(row.table_name ?? row.TABLE_NAME), lower(row.index_name ?? row.INDEX_NAME)));
|
|
41
|
+
return {
|
|
42
|
+
schemaName,
|
|
43
|
+
tables,
|
|
44
|
+
columns,
|
|
45
|
+
indexes
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
9
49
|
//#region src/storage/domains/utils.ts
|
|
10
50
|
function quoteIdentifier(value, context) {
|
|
11
51
|
return `\`${(0, _mastra_core_utils.parseSqlIdentifier)(value, context)}\``;
|
|
@@ -145,12 +185,38 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
145
185
|
pool;
|
|
146
186
|
database;
|
|
147
187
|
resolvedDatabase;
|
|
188
|
+
/**
|
|
189
|
+
* Init-scoped catalog snapshot (see db/schema-snapshot.ts). Installed by
|
|
190
|
+
* MySQLStore.init() for exactly the init window and cleared in its finally;
|
|
191
|
+
* null at runtime so non-init callers keep probing the live catalog.
|
|
192
|
+
*/
|
|
193
|
+
schemaSnapshot = null;
|
|
148
194
|
constructor({ pool, database }) {
|
|
149
195
|
super();
|
|
150
196
|
this.pool = pool;
|
|
151
197
|
this.database = database;
|
|
152
198
|
this.resolvedDatabase = database ?? null;
|
|
153
199
|
}
|
|
200
|
+
/**
|
|
201
|
+
* Loads and installs the init-scoped snapshot. A null load (no default
|
|
202
|
+
* database) or a failed load leaves the snapshot uninstalled, so init
|
|
203
|
+
* proceeds with today's per-probe behavior: correctness over optimization.
|
|
204
|
+
*/
|
|
205
|
+
async loadInitSchemaSnapshot() {
|
|
206
|
+
try {
|
|
207
|
+
this.schemaSnapshot = await loadSchemaSnapshot(this.pool, await this.getDatabase());
|
|
208
|
+
} catch (error) {
|
|
209
|
+
console.warn("Failed to load init schema snapshot, falling back to per-object probing:", error);
|
|
210
|
+
this.schemaSnapshot = null;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
clearInitSchemaSnapshot() {
|
|
214
|
+
this.schemaSnapshot = null;
|
|
215
|
+
}
|
|
216
|
+
/** Read by sibling domains (memory's raw index DDL) so snapshot state lives in exactly one place. */
|
|
217
|
+
getInitSchemaSnapshot() {
|
|
218
|
+
return this.schemaSnapshot;
|
|
219
|
+
}
|
|
154
220
|
getPool() {
|
|
155
221
|
return this.pool;
|
|
156
222
|
}
|
|
@@ -166,6 +232,8 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
166
232
|
return this.resolvedDatabase ?? void 0;
|
|
167
233
|
}
|
|
168
234
|
async hasColumn(table, column) {
|
|
235
|
+
const snapshotColumns = this.schemaSnapshot?.columns.get(table.toLowerCase());
|
|
236
|
+
if (snapshotColumns) return snapshotColumns.has(column.toLowerCase());
|
|
169
237
|
const db = await this.getDatabase();
|
|
170
238
|
const params = [table, column];
|
|
171
239
|
let sql = "SELECT COUNT(*) as count FROM information_schema.columns WHERE table_name = ? AND (column_name = ? OR column_name = ? )";
|
|
@@ -243,13 +311,23 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
243
311
|
return false;
|
|
244
312
|
}
|
|
245
313
|
async createTable({ tableName, schema }) {
|
|
314
|
+
const snapshot = this.schemaSnapshot;
|
|
315
|
+
if (snapshot?.tables.has(tableName.toLowerCase())) return;
|
|
246
316
|
const connection = await this.pool.getConnection();
|
|
247
317
|
try {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
318
|
+
if (!snapshot) {
|
|
319
|
+
const db = await this.getDatabase();
|
|
320
|
+
const [t_rows] = await connection.query("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ? AND table_name = ?", [db ?? "", tableName]);
|
|
321
|
+
if (Array.isArray(t_rows) && t_rows.length > 0 && t_rows[0].count > 0) return;
|
|
322
|
+
}
|
|
251
323
|
const sql = this.getCreateTableSQL(tableName, schema);
|
|
252
|
-
await connection.execute(sql);
|
|
324
|
+
const [result] = await connection.execute(sql);
|
|
325
|
+
const created = result?.warningStatus === 0;
|
|
326
|
+
if (snapshot && created) {
|
|
327
|
+
const table = tableName.toLowerCase();
|
|
328
|
+
snapshot.tables.add(table);
|
|
329
|
+
snapshot.columns.set(table, new Set(Object.keys(schema).map((column) => column.toLowerCase())));
|
|
330
|
+
}
|
|
253
331
|
} catch (error) {
|
|
254
332
|
throw new _mastra_core_error.MastraError({
|
|
255
333
|
id: "MYSQL_STORE_CREATE_TABLE_FAILED",
|
|
@@ -305,17 +383,22 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
305
383
|
const tableName = formatTableName(table, this.database);
|
|
306
384
|
const indexName = quoteIdentifier(name, "index name");
|
|
307
385
|
try {
|
|
308
|
-
const
|
|
309
|
-
|
|
386
|
+
const snapshot = this.schemaSnapshot;
|
|
387
|
+
if (snapshot) {
|
|
388
|
+
if (snapshot.indexes.has(indexKey(table, name))) return;
|
|
389
|
+
} else {
|
|
390
|
+
const db = await this.getDatabase() ?? "";
|
|
391
|
+
const [existing] = await this.pool.execute(`SELECT 1 FROM information_schema.STATISTICS
|
|
310
392
|
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ? AND INDEX_NAME = ?
|
|
311
393
|
LIMIT 1`, [
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
394
|
+
db,
|
|
395
|
+
table,
|
|
396
|
+
name
|
|
397
|
+
]);
|
|
398
|
+
if (existing.length > 0) return;
|
|
399
|
+
}
|
|
317
400
|
const [columnMeta] = await this.pool.execute(`SELECT COLUMN_NAME, DATA_TYPE FROM information_schema.COLUMNS
|
|
318
|
-
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`, [
|
|
401
|
+
WHERE TABLE_SCHEMA = ? AND TABLE_NAME = ?`, [await this.getDatabase() ?? "", table]);
|
|
319
402
|
const dataTypeByColumn = new Map(columnMeta.map((row) => [String(row.COLUMN_NAME).toLowerCase(), String(row.DATA_TYPE).toLowerCase()]));
|
|
320
403
|
const PREFIX_TYPES = /* @__PURE__ */ new Set([
|
|
321
404
|
"tinytext",
|
|
@@ -341,6 +424,7 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
341
424
|
}).join(", ");
|
|
342
425
|
const sql = `CREATE ${unique ? "UNIQUE " : ""}INDEX ${indexName} ON ${tableName} (${columnsStr})`;
|
|
343
426
|
await this.pool.execute(sql);
|
|
427
|
+
this.schemaSnapshot?.indexes.add(indexKey(table, name));
|
|
344
428
|
} catch (error) {
|
|
345
429
|
console.warn(`Failed to create index ${name}:`, error);
|
|
346
430
|
}
|
|
@@ -572,17 +656,22 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
572
656
|
}
|
|
573
657
|
async alterTable({ tableName, schema, ifNotExists }) {
|
|
574
658
|
if (!ifNotExists.length) return;
|
|
575
|
-
const
|
|
576
|
-
|
|
577
|
-
if (
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
params
|
|
659
|
+
const snapshotColumns = this.schemaSnapshot?.columns.get(tableName.toLowerCase());
|
|
660
|
+
let existing;
|
|
661
|
+
if (snapshotColumns) existing = snapshotColumns;
|
|
662
|
+
else {
|
|
663
|
+
const db = await this.getDatabase();
|
|
664
|
+
const [tableRows] = await this.pool.execute("SELECT COUNT(*) AS count FROM information_schema.tables WHERE table_schema = ? AND table_name = ?", [db ?? "", tableName]);
|
|
665
|
+
if (!(Array.isArray(tableRows) && tableRows.length > 0 && tableRows[0].count > 0)) return;
|
|
666
|
+
const params = [tableName];
|
|
667
|
+
let sql = "SELECT column_name FROM information_schema.columns WHERE table_name = ?";
|
|
668
|
+
if (db) {
|
|
669
|
+
sql += " AND table_schema = ?";
|
|
670
|
+
params.push(db);
|
|
671
|
+
}
|
|
672
|
+
const [rows] = await this.pool.execute(sql, params);
|
|
673
|
+
existing = new Set((rows || []).map((row) => String(row.column_name ?? row.COLUMN_NAME).toLowerCase()));
|
|
583
674
|
}
|
|
584
|
-
const [rows] = await this.pool.execute(sql, params);
|
|
585
|
-
const existing = new Set((rows || []).map((row) => String(row.column_name ?? row.COLUMN_NAME).toLowerCase()));
|
|
586
675
|
for (const columnName of ifNotExists) {
|
|
587
676
|
if (existing.has(columnName.toLowerCase())) continue;
|
|
588
677
|
const column = schema[columnName];
|
|
@@ -604,6 +693,7 @@ var StoreOperationsMySQL = class extends _mastra_core_storage.StoreOperations {
|
|
|
604
693
|
const alterSql = `ALTER TABLE ${formatTableName(tableName, this.database)} ADD COLUMN ${parts.join(" ")}`;
|
|
605
694
|
try {
|
|
606
695
|
await this.pool.execute(alterSql);
|
|
696
|
+
existing.add(columnName.toLowerCase());
|
|
607
697
|
} catch (error) {
|
|
608
698
|
if (error?.code === "ER_DUP_FIELDNAME") continue;
|
|
609
699
|
throw new _mastra_core_error.MastraError({
|
|
@@ -760,7 +850,8 @@ var AgentsMySQL = class AgentsMySQL extends _mastra_core_storage.AgentsStorage {
|
|
|
760
850
|
"requestContextSchema",
|
|
761
851
|
"workspace",
|
|
762
852
|
"skills",
|
|
763
|
-
"skillsFormat"
|
|
853
|
+
"skillsFormat",
|
|
854
|
+
"durable"
|
|
764
855
|
]
|
|
765
856
|
});
|
|
766
857
|
await this.createDefaultIndexes();
|
|
@@ -1052,6 +1143,7 @@ var AgentsMySQL = class AgentsMySQL extends _mastra_core_storage.AgentsStorage {
|
|
|
1052
1143
|
workspace: input.workspace ?? null,
|
|
1053
1144
|
skills: input.skills ?? null,
|
|
1054
1145
|
skillsFormat: input.skillsFormat ?? null,
|
|
1146
|
+
durable: input.durable ?? null,
|
|
1055
1147
|
changedFields: input.changedFields ?? null,
|
|
1056
1148
|
changeMessage: input.changeMessage ?? null,
|
|
1057
1149
|
createdAt: now
|
|
@@ -1267,6 +1359,7 @@ var AgentsMySQL = class AgentsMySQL extends _mastra_core_storage.AgentsStorage {
|
|
|
1267
1359
|
workspace: this.safeParseJSON(row.workspace),
|
|
1268
1360
|
skills: this.safeParseJSON(row.skills),
|
|
1269
1361
|
skillsFormat: row.skillsFormat,
|
|
1362
|
+
durable: this.safeParseJSON(row.durable),
|
|
1270
1363
|
changedFields: this.safeParseJSON(row.changedFields),
|
|
1271
1364
|
changeMessage: row.changeMessage ?? void 0,
|
|
1272
1365
|
createdAt: row.createdAt instanceof Date ? row.createdAt : new Date(row.createdAt)
|
|
@@ -4833,10 +4926,14 @@ var MemoryMySQL = class MemoryMySQL extends _mastra_core_storage.MemoryStorage {
|
|
|
4833
4926
|
schema: _mastra_core_storage.TABLE_SCHEMAS[_mastra_core_storage.TABLE_MESSAGES],
|
|
4834
4927
|
ifNotExists: ["resourceId"]
|
|
4835
4928
|
});
|
|
4836
|
-
if (omSchema)
|
|
4837
|
-
|
|
4838
|
-
|
|
4839
|
-
|
|
4929
|
+
if (omSchema) {
|
|
4930
|
+
const snapshot = this.operations.getInitSchemaSnapshot();
|
|
4931
|
+
if (!snapshot?.indexes.has(indexKey(OM_TABLE, "idx_om_lookup_key"))) try {
|
|
4932
|
+
await this.pool.execute(`CREATE INDEX idx_om_lookup_key ON ${OM_TABLE_QUOTED} (${quoteIdentifier("lookupKey", "column name")}(191))`);
|
|
4933
|
+
snapshot?.indexes.add(indexKey(OM_TABLE, "idx_om_lookup_key"));
|
|
4934
|
+
} catch (err) {
|
|
4935
|
+
if (err?.errno !== 1061) throw err;
|
|
4936
|
+
}
|
|
4840
4937
|
}
|
|
4841
4938
|
await this.createDefaultIndexes();
|
|
4842
4939
|
await this.createCustomIndexes();
|
|
@@ -10355,6 +10452,7 @@ function parseConnectionString(connectionString, overrides) {
|
|
|
10355
10452
|
}
|
|
10356
10453
|
var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
10357
10454
|
pool;
|
|
10455
|
+
operations;
|
|
10358
10456
|
stores;
|
|
10359
10457
|
constructor(config) {
|
|
10360
10458
|
super({
|
|
@@ -10369,6 +10467,7 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
|
10369
10467
|
pool: this.pool,
|
|
10370
10468
|
database
|
|
10371
10469
|
});
|
|
10470
|
+
this.operations = operations;
|
|
10372
10471
|
const memory = new MemoryMySQL({
|
|
10373
10472
|
pool: this.pool,
|
|
10374
10473
|
operations,
|
|
@@ -10511,6 +10610,7 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
|
10511
10610
|
async init() {
|
|
10512
10611
|
try {
|
|
10513
10612
|
(await this.pool.getConnection()).release();
|
|
10613
|
+
await this.operations.loadInitSchemaSnapshot();
|
|
10514
10614
|
await super.init();
|
|
10515
10615
|
} catch (error) {
|
|
10516
10616
|
throw new _mastra_core_error.MastraError({
|
|
@@ -10518,6 +10618,8 @@ var MySQLStore = class extends _mastra_core_storage.MastraCompositeStore {
|
|
|
10518
10618
|
domain: _mastra_core_error.ErrorDomain.STORAGE,
|
|
10519
10619
|
category: _mastra_core_error.ErrorCategory.THIRD_PARTY
|
|
10520
10620
|
}, error);
|
|
10621
|
+
} finally {
|
|
10622
|
+
this.operations.clearInitSchemaSnapshot();
|
|
10521
10623
|
}
|
|
10522
10624
|
}
|
|
10523
10625
|
async close() {
|