@mindstudio-ai/agent 0.1.9 → 0.1.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +8 -2
- package/dist/cli.js +164 -374
- package/dist/index.d.ts +35 -343
- package/dist/index.js +157 -370
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +164 -374
- package/package.json +1 -1
package/dist/postinstall.js
CHANGED
|
@@ -1419,6 +1419,19 @@ var init_auth = __esm({
|
|
|
1419
1419
|
});
|
|
1420
1420
|
|
|
1421
1421
|
// src/db/sql.ts
|
|
1422
|
+
function serializeParam(val) {
|
|
1423
|
+
if (val === null || val === void 0) return null;
|
|
1424
|
+
if (typeof val === "boolean") return val ? 1 : 0;
|
|
1425
|
+
if (typeof val === "number" || typeof val === "string") return val;
|
|
1426
|
+
return JSON.stringify(val);
|
|
1427
|
+
}
|
|
1428
|
+
function serializeColumnParam(val, columnName, columns) {
|
|
1429
|
+
const col = columns.find((c) => c.name === columnName);
|
|
1430
|
+
if (col?.type === "user" && typeof val === "string") {
|
|
1431
|
+
return `@@user@@${val}`;
|
|
1432
|
+
}
|
|
1433
|
+
return serializeParam(val);
|
|
1434
|
+
}
|
|
1422
1435
|
function escapeValue(val) {
|
|
1423
1436
|
if (val === null || val === void 0) return "NULL";
|
|
1424
1437
|
if (typeof val === "boolean") return val ? "1" : "0";
|
|
@@ -1427,13 +1440,6 @@ function escapeValue(val) {
|
|
|
1427
1440
|
const json = JSON.stringify(val);
|
|
1428
1441
|
return `'${json.replace(/'/g, "''")}'`;
|
|
1429
1442
|
}
|
|
1430
|
-
function serializeValue(val, columnName, columns) {
|
|
1431
|
-
const col = columns.find((c) => c.name === columnName);
|
|
1432
|
-
if (col?.type === "user" && typeof val === "string") {
|
|
1433
|
-
return escapeValue(`@@user@@${val}`);
|
|
1434
|
-
}
|
|
1435
|
-
return escapeValue(val);
|
|
1436
|
-
}
|
|
1437
1443
|
function deserializeRow(row, columns) {
|
|
1438
1444
|
const result = {};
|
|
1439
1445
|
for (const [key, value] of Object.entries(row)) {
|
|
@@ -1454,37 +1460,54 @@ function deserializeRow(row, columns) {
|
|
|
1454
1460
|
}
|
|
1455
1461
|
function buildSelect(table, options = {}) {
|
|
1456
1462
|
let sql = `SELECT * FROM ${table}`;
|
|
1457
|
-
|
|
1463
|
+
const params = [];
|
|
1464
|
+
if (options.where) {
|
|
1465
|
+
sql += ` WHERE ${options.where}`;
|
|
1466
|
+
if (options.whereParams) params.push(...options.whereParams);
|
|
1467
|
+
}
|
|
1458
1468
|
if (options.orderBy) sql += ` ORDER BY ${options.orderBy}${options.desc ? " DESC" : " ASC"}`;
|
|
1459
1469
|
if (options.limit != null) sql += ` LIMIT ${options.limit}`;
|
|
1460
1470
|
if (options.offset != null) sql += ` OFFSET ${options.offset}`;
|
|
1461
|
-
return sql;
|
|
1471
|
+
return { sql, params: params.length > 0 ? params : void 0 };
|
|
1462
1472
|
}
|
|
1463
|
-
function buildCount(table, where) {
|
|
1473
|
+
function buildCount(table, where, whereParams) {
|
|
1464
1474
|
let sql = `SELECT COUNT(*) as count FROM ${table}`;
|
|
1465
1475
|
if (where) sql += ` WHERE ${where}`;
|
|
1466
|
-
return sql;
|
|
1476
|
+
return { sql, params: whereParams?.length ? whereParams : void 0 };
|
|
1467
1477
|
}
|
|
1468
|
-
function buildExists(table, where, negate) {
|
|
1478
|
+
function buildExists(table, where, whereParams, negate) {
|
|
1469
1479
|
const inner = where ? `SELECT 1 FROM ${table} WHERE ${where}` : `SELECT 1 FROM ${table}`;
|
|
1470
1480
|
const fn = negate ? "NOT EXISTS" : "EXISTS";
|
|
1471
|
-
return `SELECT ${fn}(${inner}) as result
|
|
1481
|
+
return { sql: `SELECT ${fn}(${inner}) as result`, params: whereParams?.length ? whereParams : void 0 };
|
|
1472
1482
|
}
|
|
1473
1483
|
function buildInsert(table, data, columns) {
|
|
1474
1484
|
const filtered = stripSystemColumns(data);
|
|
1475
1485
|
const keys = Object.keys(filtered);
|
|
1476
|
-
const
|
|
1477
|
-
|
|
1486
|
+
const placeholders = keys.map(() => "?").join(", ");
|
|
1487
|
+
const params = keys.map((k) => serializeColumnParam(filtered[k], k, columns));
|
|
1488
|
+
return {
|
|
1489
|
+
sql: `INSERT INTO ${table} (${keys.join(", ")}) VALUES (${placeholders}) RETURNING *`,
|
|
1490
|
+
params
|
|
1491
|
+
};
|
|
1478
1492
|
}
|
|
1479
1493
|
function buildUpdate(table, id, data, columns) {
|
|
1480
1494
|
const filtered = stripSystemColumns(data);
|
|
1481
|
-
const
|
|
1482
|
-
|
|
1495
|
+
const keys = Object.keys(filtered);
|
|
1496
|
+
const assignments = keys.map((k) => `${k} = ?`).join(", ");
|
|
1497
|
+
const params = [
|
|
1498
|
+
...keys.map((k) => serializeColumnParam(filtered[k], k, columns)),
|
|
1499
|
+
id
|
|
1500
|
+
// for WHERE id = ?
|
|
1501
|
+
];
|
|
1502
|
+
return {
|
|
1503
|
+
sql: `UPDATE ${table} SET ${assignments} WHERE id = ? RETURNING *`,
|
|
1504
|
+
params
|
|
1505
|
+
};
|
|
1483
1506
|
}
|
|
1484
|
-
function buildDelete(table, where) {
|
|
1507
|
+
function buildDelete(table, where, whereParams) {
|
|
1485
1508
|
let sql = `DELETE FROM ${table}`;
|
|
1486
1509
|
if (where) sql += ` WHERE ${where}`;
|
|
1487
|
-
return sql;
|
|
1510
|
+
return { sql, params: whereParams?.length ? whereParams : void 0 };
|
|
1488
1511
|
}
|
|
1489
1512
|
function stripSystemColumns(data) {
|
|
1490
1513
|
const result = {};
|
|
@@ -2026,17 +2049,11 @@ var init_query = __esm({
|
|
|
2026
2049
|
init_predicate();
|
|
2027
2050
|
init_sql();
|
|
2028
2051
|
Query = class _Query {
|
|
2029
|
-
/** @internal Accumulated predicate functions to filter by. */
|
|
2030
2052
|
_predicates;
|
|
2031
|
-
/** @internal The field accessor for sorting, if set. */
|
|
2032
2053
|
_sortAccessor;
|
|
2033
|
-
/** @internal Whether the sort order is reversed (DESC). */
|
|
2034
2054
|
_reversed;
|
|
2035
|
-
/** @internal Maximum number of results (SQL LIMIT). */
|
|
2036
2055
|
_limit;
|
|
2037
|
-
/** @internal Number of results to skip (SQL OFFSET). */
|
|
2038
2056
|
_offset;
|
|
2039
|
-
/** @internal Binding to the database execution layer. */
|
|
2040
2057
|
_config;
|
|
2041
2058
|
constructor(config, options) {
|
|
2042
2059
|
this._config = config;
|
|
@@ -2046,10 +2063,6 @@ var init_query = __esm({
|
|
|
2046
2063
|
this._limit = options?.limit;
|
|
2047
2064
|
this._offset = options?.offset;
|
|
2048
2065
|
}
|
|
2049
|
-
/**
|
|
2050
|
-
* Create a clone of this query with some options overridden.
|
|
2051
|
-
* Used internally by chain methods to maintain immutability.
|
|
2052
|
-
*/
|
|
2053
2066
|
_clone(overrides) {
|
|
2054
2067
|
return new _Query(this._config, {
|
|
2055
2068
|
predicates: overrides.predicates ?? this._predicates,
|
|
@@ -2060,126 +2073,73 @@ var init_query = __esm({
|
|
|
2060
2073
|
});
|
|
2061
2074
|
}
|
|
2062
2075
|
// -------------------------------------------------------------------------
|
|
2063
|
-
// Chain methods
|
|
2076
|
+
// Chain methods
|
|
2064
2077
|
// -------------------------------------------------------------------------
|
|
2065
|
-
/**
|
|
2066
|
-
* Add a filter predicate. Multiple filters are ANDed together.
|
|
2067
|
-
*
|
|
2068
|
-
* @example
|
|
2069
|
-
* ```ts
|
|
2070
|
-
* const active = Orders.filter(o => o.status === 'active');
|
|
2071
|
-
* const expensive = active.filter(o => o.amount > 5000);
|
|
2072
|
-
* // WHERE status = 'active' AND amount > 5000
|
|
2073
|
-
* ```
|
|
2074
|
-
*/
|
|
2075
2078
|
filter(predicate) {
|
|
2076
|
-
return this._clone({
|
|
2077
|
-
predicates: [...this._predicates, predicate]
|
|
2078
|
-
});
|
|
2079
|
+
return this._clone({ predicates: [...this._predicates, predicate] });
|
|
2079
2080
|
}
|
|
2080
|
-
/**
|
|
2081
|
-
* Sort results by a field (ascending by default).
|
|
2082
|
-
* Use `.reverse()` after `.sortBy()` for descending order.
|
|
2083
|
-
*
|
|
2084
|
-
* @example
|
|
2085
|
-
* ```ts
|
|
2086
|
-
* const newest = Orders.sortBy(o => o.createdAt).reverse();
|
|
2087
|
-
* ```
|
|
2088
|
-
*/
|
|
2089
2081
|
sortBy(accessor) {
|
|
2090
2082
|
return this._clone({ sortAccessor: accessor });
|
|
2091
2083
|
}
|
|
2092
|
-
/**
|
|
2093
|
-
* Reverse the current sort order. If no sort is set, this has no effect.
|
|
2094
|
-
*/
|
|
2095
2084
|
reverse() {
|
|
2096
2085
|
return this._clone({ reversed: !this._reversed });
|
|
2097
2086
|
}
|
|
2098
|
-
/**
|
|
2099
|
-
* Limit the number of results returned.
|
|
2100
|
-
*
|
|
2101
|
-
* @example
|
|
2102
|
-
* ```ts
|
|
2103
|
-
* const top10 = Orders.sortBy(o => o.amount).reverse().take(10);
|
|
2104
|
-
* ```
|
|
2105
|
-
*/
|
|
2106
2087
|
take(n) {
|
|
2107
2088
|
return this._clone({ limit: n });
|
|
2108
2089
|
}
|
|
2109
|
-
/**
|
|
2110
|
-
* Skip the first n results. Use with `.take()` for pagination.
|
|
2111
|
-
*
|
|
2112
|
-
* @example
|
|
2113
|
-
* ```ts
|
|
2114
|
-
* const page2 = Orders.sortBy(o => o.createdAt).skip(50).take(50);
|
|
2115
|
-
* ```
|
|
2116
|
-
*/
|
|
2117
2090
|
skip(n) {
|
|
2118
2091
|
return this._clone({ offset: n });
|
|
2119
2092
|
}
|
|
2120
2093
|
// -------------------------------------------------------------------------
|
|
2121
|
-
// Terminal methods
|
|
2094
|
+
// Terminal methods
|
|
2122
2095
|
// -------------------------------------------------------------------------
|
|
2123
|
-
/**
|
|
2124
|
-
* Return the first matching row, or null if no rows match.
|
|
2125
|
-
* Applies the current sort order before taking the first result.
|
|
2126
|
-
*/
|
|
2127
2096
|
async first() {
|
|
2128
2097
|
const rows = await this._clone({ limit: 1 })._execute();
|
|
2129
2098
|
return rows[0] ?? null;
|
|
2130
2099
|
}
|
|
2131
|
-
/**
|
|
2132
|
-
* Return the last matching row (per current sort), or null.
|
|
2133
|
-
* Flips the sort direction and takes 1 row.
|
|
2134
|
-
*/
|
|
2135
2100
|
async last() {
|
|
2136
2101
|
const rows = await this._clone({ limit: 1, reversed: !this._reversed })._execute();
|
|
2137
2102
|
return rows[0] ?? null;
|
|
2138
2103
|
}
|
|
2139
|
-
/**
|
|
2140
|
-
* Count matching rows. Returns a number, not the rows themselves.
|
|
2141
|
-
* Executes as `SELECT COUNT(*)` when predicates compile to SQL.
|
|
2142
|
-
*/
|
|
2143
2104
|
async count() {
|
|
2144
2105
|
const compiled = this._compilePredicates();
|
|
2145
2106
|
if (compiled.allSql) {
|
|
2146
|
-
const
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2107
|
+
const query = buildCount(
|
|
2108
|
+
this._config.tableName,
|
|
2109
|
+
compiled.sqlWhere || void 0
|
|
2110
|
+
);
|
|
2111
|
+
const results = await this._config.executeBatch([query]);
|
|
2112
|
+
const row = results[0]?.rows[0];
|
|
2150
2113
|
return row?.count ?? 0;
|
|
2151
2114
|
}
|
|
2152
2115
|
const rows = await this._fetchAndFilterInJs(compiled);
|
|
2153
2116
|
return rows.length;
|
|
2154
2117
|
}
|
|
2155
|
-
/**
|
|
2156
|
-
* Check if any row matches the current filters. Short-circuits —
|
|
2157
|
-
* doesn't load all rows when using SQL.
|
|
2158
|
-
*/
|
|
2159
2118
|
async some() {
|
|
2160
2119
|
const compiled = this._compilePredicates();
|
|
2161
2120
|
if (compiled.allSql) {
|
|
2162
|
-
const
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2121
|
+
const query = buildExists(
|
|
2122
|
+
this._config.tableName,
|
|
2123
|
+
compiled.sqlWhere || void 0
|
|
2124
|
+
);
|
|
2125
|
+
const results = await this._config.executeBatch([query]);
|
|
2126
|
+
const row = results[0]?.rows[0];
|
|
2166
2127
|
return row?.result === 1;
|
|
2167
2128
|
}
|
|
2168
2129
|
const rows = await this._fetchAndFilterInJs(compiled);
|
|
2169
2130
|
return rows.length > 0;
|
|
2170
2131
|
}
|
|
2171
|
-
/**
|
|
2172
|
-
* Check if all rows match the current filters. Short-circuits on false.
|
|
2173
|
-
*
|
|
2174
|
-
* Implemented as NOT EXISTS(... WHERE NOT predicate) — returns true
|
|
2175
|
-
* if no rows fail the predicate.
|
|
2176
|
-
*/
|
|
2177
2132
|
async every() {
|
|
2178
2133
|
const compiled = this._compilePredicates();
|
|
2179
2134
|
if (compiled.allSql && compiled.sqlWhere) {
|
|
2180
|
-
const
|
|
2181
|
-
|
|
2182
|
-
|
|
2135
|
+
const query = buildExists(
|
|
2136
|
+
this._config.tableName,
|
|
2137
|
+
`NOT (${compiled.sqlWhere})`,
|
|
2138
|
+
void 0,
|
|
2139
|
+
true
|
|
2140
|
+
);
|
|
2141
|
+
const results = await this._config.executeBatch([query]);
|
|
2142
|
+
const row = results[0]?.rows[0];
|
|
2183
2143
|
return row?.result === 1;
|
|
2184
2144
|
}
|
|
2185
2145
|
if (this._predicates.length === 0) return true;
|
|
@@ -2188,24 +2148,12 @@ var init_query = __esm({
|
|
|
2188
2148
|
(row) => this._predicates.every((pred) => pred(row))
|
|
2189
2149
|
);
|
|
2190
2150
|
}
|
|
2191
|
-
/**
|
|
2192
|
-
* Return the row with the minimum value for the given field.
|
|
2193
|
-
* Executes as `ORDER BY field ASC LIMIT 1` in SQL.
|
|
2194
|
-
*/
|
|
2195
2151
|
async min(accessor) {
|
|
2196
2152
|
return this.sortBy(accessor).first();
|
|
2197
2153
|
}
|
|
2198
|
-
/**
|
|
2199
|
-
* Return the row with the maximum value for the given field.
|
|
2200
|
-
* Executes as `ORDER BY field DESC LIMIT 1` in SQL.
|
|
2201
|
-
*/
|
|
2202
2154
|
async max(accessor) {
|
|
2203
2155
|
return this.sortBy(accessor).reverse().first();
|
|
2204
2156
|
}
|
|
2205
|
-
/**
|
|
2206
|
-
* Group rows by a field value. Returns a Map.
|
|
2207
|
-
* Always executes in JS (no SQL equivalent for grouping into a Map).
|
|
2208
|
-
*/
|
|
2209
2157
|
async groupBy(accessor) {
|
|
2210
2158
|
const rows = await this._execute();
|
|
2211
2159
|
const map = /* @__PURE__ */ new Map();
|
|
@@ -2221,40 +2169,27 @@ var init_query = __esm({
|
|
|
2221
2169
|
return map;
|
|
2222
2170
|
}
|
|
2223
2171
|
// -------------------------------------------------------------------------
|
|
2224
|
-
// PromiseLike
|
|
2172
|
+
// PromiseLike
|
|
2225
2173
|
// -------------------------------------------------------------------------
|
|
2226
|
-
/**
|
|
2227
|
-
* PromiseLike.then() — executes the query and pipes the result.
|
|
2228
|
-
* This is what makes `const rows = await query` work.
|
|
2229
|
-
*/
|
|
2230
2174
|
then(onfulfilled, onrejected) {
|
|
2231
2175
|
return this._execute().then(onfulfilled, onrejected);
|
|
2232
2176
|
}
|
|
2233
2177
|
// -------------------------------------------------------------------------
|
|
2234
2178
|
// Execution internals
|
|
2235
2179
|
// -------------------------------------------------------------------------
|
|
2236
|
-
/**
|
|
2237
|
-
* Execute the query and return typed result rows.
|
|
2238
|
-
*
|
|
2239
|
-
* This is the core execution method. It:
|
|
2240
|
-
* 1. Tries to compile all predicates to SQL
|
|
2241
|
-
* 2. If all compile → builds and executes a single SQL query
|
|
2242
|
-
* 3. If any fail → fetches all rows and processes in JS
|
|
2243
|
-
* 4. Deserializes rows (user prefix stripping, JSON parsing)
|
|
2244
|
-
*/
|
|
2245
2180
|
async _execute() {
|
|
2246
2181
|
const compiled = this._compilePredicates();
|
|
2247
2182
|
if (compiled.allSql) {
|
|
2248
2183
|
const sortField = this._sortAccessor ? extractFieldName(this._sortAccessor) : void 0;
|
|
2249
|
-
const
|
|
2184
|
+
const query = buildSelect(this._config.tableName, {
|
|
2250
2185
|
where: compiled.sqlWhere || void 0,
|
|
2251
2186
|
orderBy: sortField ?? void 0,
|
|
2252
2187
|
desc: this._reversed,
|
|
2253
2188
|
limit: this._limit,
|
|
2254
2189
|
offset: this._offset
|
|
2255
2190
|
});
|
|
2256
|
-
const
|
|
2257
|
-
return
|
|
2191
|
+
const results = await this._config.executeBatch([query]);
|
|
2192
|
+
return results[0].rows.map(
|
|
2258
2193
|
(row) => deserializeRow(
|
|
2259
2194
|
row,
|
|
2260
2195
|
this._config.columns
|
|
@@ -2279,14 +2214,6 @@ var init_query = __esm({
|
|
|
2279
2214
|
}
|
|
2280
2215
|
return rows;
|
|
2281
2216
|
}
|
|
2282
|
-
/**
|
|
2283
|
-
* Compile all accumulated predicates and determine the execution strategy.
|
|
2284
|
-
*
|
|
2285
|
-
* Returns an object with:
|
|
2286
|
-
* - `allSql`: whether all predicates compiled to SQL
|
|
2287
|
-
* - `sqlWhere`: combined WHERE clause (ANDed) if all compiled
|
|
2288
|
-
* - `compiled`: individual compilation results
|
|
2289
|
-
*/
|
|
2290
2217
|
_compilePredicates() {
|
|
2291
2218
|
if (this._predicates.length === 0) {
|
|
2292
2219
|
return { allSql: true, sqlWhere: "", compiled: [] };
|
|
@@ -2299,12 +2226,6 @@ var init_query = __esm({
|
|
|
2299
2226
|
}
|
|
2300
2227
|
return { allSql, sqlWhere, compiled };
|
|
2301
2228
|
}
|
|
2302
|
-
/**
|
|
2303
|
-
* Fetch all rows from the table and apply JS predicates.
|
|
2304
|
-
* This is the fallback path when SQL compilation fails.
|
|
2305
|
-
*
|
|
2306
|
-
* Logs a warning to stderr so developers know they're on the slow path.
|
|
2307
|
-
*/
|
|
2308
2229
|
async _fetchAndFilterInJs(compiled) {
|
|
2309
2230
|
const allRows = await this._fetchAllRows();
|
|
2310
2231
|
if (compiled.compiled.some((c) => c.type === "js")) {
|
|
@@ -2316,14 +2237,10 @@ var init_query = __esm({
|
|
|
2316
2237
|
(row) => this._predicates.every((pred) => pred(row))
|
|
2317
2238
|
);
|
|
2318
2239
|
}
|
|
2319
|
-
/**
|
|
2320
|
-
* Fetch all rows from the table (SELECT * with no WHERE).
|
|
2321
|
-
* Used by the JS fallback path.
|
|
2322
|
-
*/
|
|
2323
2240
|
async _fetchAllRows() {
|
|
2324
|
-
const
|
|
2325
|
-
const
|
|
2326
|
-
return
|
|
2241
|
+
const query = buildSelect(this._config.tableName);
|
|
2242
|
+
const results = await this._config.executeBatch([query]);
|
|
2243
|
+
return results[0].rows.map(
|
|
2327
2244
|
(row) => deserializeRow(row, this._config.columns)
|
|
2328
2245
|
);
|
|
2329
2246
|
}
|
|
@@ -2340,300 +2257,149 @@ var init_table = __esm({
|
|
|
2340
2257
|
init_predicate();
|
|
2341
2258
|
init_sql();
|
|
2342
2259
|
Table = class {
|
|
2343
|
-
/** @internal
|
|
2260
|
+
/** @internal */
|
|
2344
2261
|
_config;
|
|
2345
2262
|
constructor(config) {
|
|
2346
2263
|
this._config = config;
|
|
2347
2264
|
}
|
|
2348
2265
|
// -------------------------------------------------------------------------
|
|
2349
|
-
// Reads — direct
|
|
2266
|
+
// Reads — direct
|
|
2350
2267
|
// -------------------------------------------------------------------------
|
|
2351
|
-
/**
|
|
2352
|
-
* Get a single row by ID. Returns null if not found.
|
|
2353
|
-
*
|
|
2354
|
-
* @example
|
|
2355
|
-
* ```ts
|
|
2356
|
-
* const order = await Orders.get('abc-123');
|
|
2357
|
-
* if (order) console.log(order.status);
|
|
2358
|
-
* ```
|
|
2359
|
-
*/
|
|
2360
2268
|
async get(id) {
|
|
2361
|
-
const
|
|
2362
|
-
where: `id =
|
|
2269
|
+
const query = buildSelect(this._config.tableName, {
|
|
2270
|
+
where: `id = ?`,
|
|
2271
|
+
whereParams: [id],
|
|
2363
2272
|
limit: 1
|
|
2364
2273
|
});
|
|
2365
|
-
const
|
|
2366
|
-
if (
|
|
2274
|
+
const results = await this._config.executeBatch([query]);
|
|
2275
|
+
if (results[0].rows.length === 0) return null;
|
|
2367
2276
|
return deserializeRow(
|
|
2368
|
-
|
|
2277
|
+
results[0].rows[0],
|
|
2369
2278
|
this._config.columns
|
|
2370
2279
|
);
|
|
2371
2280
|
}
|
|
2372
|
-
/**
|
|
2373
|
-
* Find the first row matching a predicate. Returns null if none match.
|
|
2374
|
-
*
|
|
2375
|
-
* @example
|
|
2376
|
-
* ```ts
|
|
2377
|
-
* const activeOrder = await Orders.findOne(o => o.status === 'active');
|
|
2378
|
-
* ```
|
|
2379
|
-
*/
|
|
2380
2281
|
async findOne(predicate) {
|
|
2381
2282
|
return this.filter(predicate).first();
|
|
2382
2283
|
}
|
|
2383
|
-
/**
|
|
2384
|
-
* Count rows, optionally filtered by a predicate.
|
|
2385
|
-
*
|
|
2386
|
-
* @example
|
|
2387
|
-
* ```ts
|
|
2388
|
-
* const total = await Orders.count();
|
|
2389
|
-
* const pending = await Orders.count(o => o.status === 'pending');
|
|
2390
|
-
* ```
|
|
2391
|
-
*/
|
|
2392
2284
|
async count(predicate) {
|
|
2393
|
-
if (predicate)
|
|
2394
|
-
|
|
2395
|
-
|
|
2396
|
-
const
|
|
2397
|
-
const result = await this._config.executeQuery(sql);
|
|
2398
|
-
const row = result.rows[0];
|
|
2285
|
+
if (predicate) return this.filter(predicate).count();
|
|
2286
|
+
const query = buildCount(this._config.tableName);
|
|
2287
|
+
const results = await this._config.executeBatch([query]);
|
|
2288
|
+
const row = results[0]?.rows[0];
|
|
2399
2289
|
return row?.count ?? 0;
|
|
2400
2290
|
}
|
|
2401
|
-
/**
|
|
2402
|
-
* Check if any row matches a predicate. Short-circuits.
|
|
2403
|
-
*
|
|
2404
|
-
* @example
|
|
2405
|
-
* ```ts
|
|
2406
|
-
* const hasActive = await Orders.some(o => o.status === 'active');
|
|
2407
|
-
* ```
|
|
2408
|
-
*/
|
|
2409
2291
|
async some(predicate) {
|
|
2410
2292
|
return this.filter(predicate).some();
|
|
2411
2293
|
}
|
|
2412
|
-
/**
|
|
2413
|
-
* Check if all rows match a predicate.
|
|
2414
|
-
*
|
|
2415
|
-
* @example
|
|
2416
|
-
* ```ts
|
|
2417
|
-
* const allComplete = await Orders.every(o => o.status === 'completed');
|
|
2418
|
-
* ```
|
|
2419
|
-
*/
|
|
2420
2294
|
async every(predicate) {
|
|
2421
2295
|
return this.filter(predicate).every();
|
|
2422
2296
|
}
|
|
2423
|
-
/**
|
|
2424
|
-
* Check if the table has zero rows.
|
|
2425
|
-
*
|
|
2426
|
-
* @example
|
|
2427
|
-
* ```ts
|
|
2428
|
-
* if (await Orders.isEmpty()) console.log('No orders yet');
|
|
2429
|
-
* ```
|
|
2430
|
-
*/
|
|
2431
2297
|
async isEmpty() {
|
|
2432
|
-
const
|
|
2433
|
-
const
|
|
2434
|
-
const row =
|
|
2298
|
+
const query = buildExists(this._config.tableName, void 0, void 0, true);
|
|
2299
|
+
const results = await this._config.executeBatch([query]);
|
|
2300
|
+
const row = results[0]?.rows[0];
|
|
2435
2301
|
return row?.result === 1;
|
|
2436
2302
|
}
|
|
2437
|
-
/**
|
|
2438
|
-
* Return the row with the minimum value for a field.
|
|
2439
|
-
* Executes as `ORDER BY field ASC LIMIT 1`.
|
|
2440
|
-
*
|
|
2441
|
-
* @example
|
|
2442
|
-
* ```ts
|
|
2443
|
-
* const cheapest = await Orders.min(o => o.amount);
|
|
2444
|
-
* ```
|
|
2445
|
-
*/
|
|
2446
2303
|
async min(accessor) {
|
|
2447
2304
|
return this.sortBy(accessor).first();
|
|
2448
2305
|
}
|
|
2449
|
-
/**
|
|
2450
|
-
* Return the row with the maximum value for a field.
|
|
2451
|
-
* Executes as `ORDER BY field DESC LIMIT 1`.
|
|
2452
|
-
*
|
|
2453
|
-
* @example
|
|
2454
|
-
* ```ts
|
|
2455
|
-
* const mostExpensive = await Orders.max(o => o.amount);
|
|
2456
|
-
* ```
|
|
2457
|
-
*/
|
|
2458
2306
|
async max(accessor) {
|
|
2459
2307
|
return this.sortBy(accessor).reverse().first();
|
|
2460
2308
|
}
|
|
2461
|
-
/**
|
|
2462
|
-
* Group all rows by a field value. Returns a Map.
|
|
2463
|
-
*
|
|
2464
|
-
* @example
|
|
2465
|
-
* ```ts
|
|
2466
|
-
* const byStatus = await Orders.groupBy(o => o.status);
|
|
2467
|
-
* // Map { 'pending' => [...], 'approved' => [...] }
|
|
2468
|
-
* ```
|
|
2469
|
-
*/
|
|
2470
2309
|
async groupBy(accessor) {
|
|
2471
2310
|
return new Query(this._config).groupBy(accessor);
|
|
2472
2311
|
}
|
|
2473
2312
|
// -------------------------------------------------------------------------
|
|
2474
|
-
// Reads — chainable
|
|
2313
|
+
// Reads — chainable
|
|
2475
2314
|
// -------------------------------------------------------------------------
|
|
2476
|
-
/**
|
|
2477
|
-
* Filter rows by a predicate. Returns a chainable Query.
|
|
2478
|
-
*
|
|
2479
|
-
* The predicate is compiled to SQL when possible. If compilation fails,
|
|
2480
|
-
* the query falls back to fetching all rows and filtering in JS.
|
|
2481
|
-
*
|
|
2482
|
-
* @example
|
|
2483
|
-
* ```ts
|
|
2484
|
-
* const active = await Orders.filter(o => o.status === 'active');
|
|
2485
|
-
* const recentActive = await Orders
|
|
2486
|
-
* .filter(o => o.status === 'active')
|
|
2487
|
-
* .sortBy(o => o.createdAt)
|
|
2488
|
-
* .reverse()
|
|
2489
|
-
* .take(10);
|
|
2490
|
-
* ```
|
|
2491
|
-
*/
|
|
2492
2315
|
filter(predicate) {
|
|
2493
2316
|
return new Query(this._config).filter(predicate);
|
|
2494
2317
|
}
|
|
2495
|
-
/**
|
|
2496
|
-
* Sort all rows by a field. Returns a chainable Query.
|
|
2497
|
-
*
|
|
2498
|
-
* @example
|
|
2499
|
-
* ```ts
|
|
2500
|
-
* const newest = await Orders.sortBy(o => o.createdAt).reverse().take(5);
|
|
2501
|
-
* ```
|
|
2502
|
-
*/
|
|
2503
2318
|
sortBy(accessor) {
|
|
2504
2319
|
return new Query(this._config).sortBy(accessor);
|
|
2505
2320
|
}
|
|
2506
2321
|
async push(data) {
|
|
2507
2322
|
const isArray = Array.isArray(data);
|
|
2508
2323
|
const items = isArray ? data : [data];
|
|
2509
|
-
const
|
|
2510
|
-
|
|
2511
|
-
const insertSql = buildInsert(
|
|
2324
|
+
const queries = items.map(
|
|
2325
|
+
(item) => buildInsert(
|
|
2512
2326
|
this._config.tableName,
|
|
2513
2327
|
item,
|
|
2514
2328
|
this._config.columns
|
|
2515
|
-
)
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
if (
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
this._config.columns
|
|
2524
|
-
)
|
|
2329
|
+
)
|
|
2330
|
+
);
|
|
2331
|
+
const results = await this._config.executeBatch(queries);
|
|
2332
|
+
const rows = results.map((r) => {
|
|
2333
|
+
if (r.rows.length > 0) {
|
|
2334
|
+
return deserializeRow(
|
|
2335
|
+
r.rows[0],
|
|
2336
|
+
this._config.columns
|
|
2525
2337
|
);
|
|
2526
2338
|
}
|
|
2527
|
-
|
|
2528
|
-
|
|
2339
|
+
return void 0;
|
|
2340
|
+
});
|
|
2341
|
+
return isArray ? rows : rows[0];
|
|
2529
2342
|
}
|
|
2530
2343
|
/**
|
|
2531
2344
|
* Update a row by ID. Only the provided fields are changed.
|
|
2532
|
-
* Returns the updated row
|
|
2533
|
-
*
|
|
2534
|
-
* System columns cannot be updated — they're stripped automatically.
|
|
2535
|
-
* `updatedAt` and `lastUpdatedBy` are set by the platform.
|
|
2536
|
-
*
|
|
2537
|
-
* @example
|
|
2538
|
-
* ```ts
|
|
2539
|
-
* const updated = await Orders.update(order.id, { status: 'approved' });
|
|
2540
|
-
* console.log(updated.updatedAt); // freshly updated
|
|
2541
|
-
* ```
|
|
2345
|
+
* Returns the updated row via `UPDATE ... RETURNING *`.
|
|
2542
2346
|
*/
|
|
2543
2347
|
async update(id, data) {
|
|
2544
|
-
const
|
|
2348
|
+
const query = buildUpdate(
|
|
2545
2349
|
this._config.tableName,
|
|
2546
2350
|
id,
|
|
2547
2351
|
data,
|
|
2548
2352
|
this._config.columns
|
|
2549
2353
|
);
|
|
2550
|
-
await this._config.
|
|
2551
|
-
const fetchSql = buildSelect(this._config.tableName, {
|
|
2552
|
-
where: `id = ${escapeValue(id)}`,
|
|
2553
|
-
limit: 1
|
|
2554
|
-
});
|
|
2555
|
-
const result = await this._config.executeQuery(fetchSql);
|
|
2354
|
+
const results = await this._config.executeBatch([query]);
|
|
2556
2355
|
return deserializeRow(
|
|
2557
|
-
|
|
2356
|
+
results[0].rows[0],
|
|
2558
2357
|
this._config.columns
|
|
2559
2358
|
);
|
|
2560
2359
|
}
|
|
2561
|
-
/**
|
|
2562
|
-
* Remove a row by ID.
|
|
2563
|
-
*
|
|
2564
|
-
* @example
|
|
2565
|
-
* ```ts
|
|
2566
|
-
* await Orders.remove('abc-123');
|
|
2567
|
-
* ```
|
|
2568
|
-
*/
|
|
2569
2360
|
async remove(id) {
|
|
2570
|
-
const
|
|
2571
|
-
|
|
2572
|
-
`id = ${escapeValue(id)}`
|
|
2573
|
-
);
|
|
2574
|
-
await this._config.executeQuery(sql);
|
|
2361
|
+
const query = buildDelete(this._config.tableName, `id = ?`, [id]);
|
|
2362
|
+
await this._config.executeBatch([query]);
|
|
2575
2363
|
}
|
|
2576
2364
|
/**
|
|
2577
2365
|
* Remove all rows matching a predicate. Returns the count removed.
|
|
2578
|
-
*
|
|
2579
|
-
* The predicate is compiled to SQL when possible. If compilation fails,
|
|
2580
|
-
* the function fetches all matching rows, collects their IDs, and
|
|
2581
|
-
* deletes them individually.
|
|
2582
|
-
*
|
|
2583
|
-
* @example
|
|
2584
|
-
* ```ts
|
|
2585
|
-
* const removed = await Orders.removeAll(o => o.status === 'rejected');
|
|
2586
|
-
* console.log(`Removed ${removed} orders`);
|
|
2587
|
-
* ```
|
|
2588
2366
|
*/
|
|
2589
2367
|
async removeAll(predicate) {
|
|
2590
2368
|
const compiled = compilePredicate(predicate);
|
|
2591
2369
|
if (compiled.type === "sql") {
|
|
2592
|
-
const
|
|
2593
|
-
const
|
|
2594
|
-
return
|
|
2370
|
+
const query = buildDelete(this._config.tableName, compiled.where);
|
|
2371
|
+
const results = await this._config.executeBatch([query]);
|
|
2372
|
+
return results[0].changes;
|
|
2595
2373
|
}
|
|
2596
2374
|
console.warn(
|
|
2597
2375
|
`[mindstudio] removeAll predicate on ${this._config.tableName} could not be compiled to SQL \u2014 fetching all rows first`
|
|
2598
2376
|
);
|
|
2599
|
-
const
|
|
2600
|
-
const
|
|
2601
|
-
const allRows =
|
|
2377
|
+
const allQuery = buildSelect(this._config.tableName);
|
|
2378
|
+
const allResults = await this._config.executeBatch([allQuery]);
|
|
2379
|
+
const allRows = allResults[0].rows.map(
|
|
2602
2380
|
(r) => deserializeRow(
|
|
2603
2381
|
r,
|
|
2604
2382
|
this._config.columns
|
|
2605
2383
|
)
|
|
2606
2384
|
);
|
|
2607
2385
|
const matching = allRows.filter((row) => predicate(row));
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
const sql = buildDelete(this._config.tableName, `id = ${escapeValue(id)}`);
|
|
2613
|
-
await this._config.executeQuery(sql);
|
|
2614
|
-
count++;
|
|
2615
|
-
}
|
|
2386
|
+
if (matching.length === 0) return 0;
|
|
2387
|
+
const deleteQueries = matching.filter((row) => row.id).map((row) => buildDelete(this._config.tableName, `id = ?`, [row.id]));
|
|
2388
|
+
if (deleteQueries.length > 0) {
|
|
2389
|
+
await this._config.executeBatch(deleteQueries);
|
|
2616
2390
|
}
|
|
2617
|
-
return
|
|
2391
|
+
return matching.length;
|
|
2618
2392
|
}
|
|
2619
|
-
/**
|
|
2620
|
-
* Remove all rows from the table.
|
|
2621
|
-
*
|
|
2622
|
-
* @example
|
|
2623
|
-
* ```ts
|
|
2624
|
-
* await Orders.clear();
|
|
2625
|
-
* ```
|
|
2626
|
-
*/
|
|
2627
2393
|
async clear() {
|
|
2628
|
-
const
|
|
2629
|
-
await this._config.
|
|
2394
|
+
const query = buildDelete(this._config.tableName);
|
|
2395
|
+
await this._config.executeBatch([query]);
|
|
2630
2396
|
}
|
|
2631
2397
|
};
|
|
2632
2398
|
}
|
|
2633
2399
|
});
|
|
2634
2400
|
|
|
2635
2401
|
// src/db/index.ts
|
|
2636
|
-
function createDb(databases,
|
|
2402
|
+
function createDb(databases, executeBatch) {
|
|
2637
2403
|
return {
|
|
2638
2404
|
defineTable(name, options) {
|
|
2639
2405
|
const resolved = resolveTable(databases, name, options?.database);
|
|
@@ -2641,7 +2407,7 @@ function createDb(databases, executeQuery) {
|
|
|
2641
2407
|
databaseId: resolved.databaseId,
|
|
2642
2408
|
tableName: name,
|
|
2643
2409
|
columns: resolved.columns,
|
|
2644
|
-
|
|
2410
|
+
executeBatch: (queries) => executeBatch(resolved.databaseId, queries)
|
|
2645
2411
|
};
|
|
2646
2412
|
return new Table(config);
|
|
2647
2413
|
},
|
|
@@ -3612,6 +3378,9 @@ var init_client = __esm({
|
|
|
3612
3378
|
* ```
|
|
3613
3379
|
*/
|
|
3614
3380
|
get auth() {
|
|
3381
|
+
if (!this._auth) {
|
|
3382
|
+
this._trySandboxHydration();
|
|
3383
|
+
}
|
|
3615
3384
|
if (!this._auth) {
|
|
3616
3385
|
throw new MindStudioError(
|
|
3617
3386
|
"Auth context not yet loaded. Call `await agent.ensureContext()` or perform any db operation first (which auto-hydrates context). Inside the MindStudio sandbox, context is loaded automatically.",
|
|
@@ -3637,6 +3406,9 @@ var init_client = __esm({
|
|
|
3637
3406
|
* ```
|
|
3638
3407
|
*/
|
|
3639
3408
|
get db() {
|
|
3409
|
+
if (!this._db) {
|
|
3410
|
+
this._trySandboxHydration();
|
|
3411
|
+
}
|
|
3640
3412
|
if (this._db) return this._db;
|
|
3641
3413
|
return this._createLazyDb();
|
|
3642
3414
|
}
|
|
@@ -3694,7 +3466,7 @@ var init_client = __esm({
|
|
|
3694
3466
|
this._auth = new AuthContext(context.auth);
|
|
3695
3467
|
this._db = createDb(
|
|
3696
3468
|
context.databases,
|
|
3697
|
-
this.
|
|
3469
|
+
this._executeDbBatch.bind(this)
|
|
3698
3470
|
);
|
|
3699
3471
|
}
|
|
3700
3472
|
/**
|
|
@@ -3715,25 +3487,40 @@ var init_client = __esm({
|
|
|
3715
3487
|
}
|
|
3716
3488
|
}
|
|
3717
3489
|
/**
|
|
3718
|
-
* @internal Execute a SQL
|
|
3719
|
-
* Used as the `
|
|
3490
|
+
* @internal Execute a batch of SQL queries against a managed database.
|
|
3491
|
+
* Used as the `executeBatch` callback for Table/Query instances.
|
|
3720
3492
|
*
|
|
3721
|
-
* Calls
|
|
3722
|
-
* (
|
|
3493
|
+
* Calls `POST /_internal/v2/db/query` directly with the hook token
|
|
3494
|
+
* (raw, no Bearer prefix). All queries run on a single SQLite connection,
|
|
3495
|
+
* enabling RETURNING clauses and multi-statement batches.
|
|
3723
3496
|
*/
|
|
3724
|
-
async
|
|
3725
|
-
const
|
|
3726
|
-
|
|
3727
|
-
|
|
3728
|
-
|
|
3497
|
+
async _executeDbBatch(databaseId, queries) {
|
|
3498
|
+
const url = `${this._httpConfig.baseUrl}/_internal/v2/db/query`;
|
|
3499
|
+
const res = await fetch(url, {
|
|
3500
|
+
method: "POST",
|
|
3501
|
+
headers: {
|
|
3502
|
+
"Content-Type": "application/json",
|
|
3503
|
+
Authorization: this._httpConfig.token
|
|
3504
|
+
},
|
|
3505
|
+
body: JSON.stringify({ databaseId, queries })
|
|
3729
3506
|
});
|
|
3730
|
-
|
|
3507
|
+
if (!res.ok) {
|
|
3508
|
+
let message = `Database query failed: ${res.status} ${res.statusText}`;
|
|
3509
|
+
try {
|
|
3510
|
+
const body = await res.json();
|
|
3511
|
+
if (body.error) message = body.error;
|
|
3512
|
+
} catch {
|
|
3513
|
+
}
|
|
3514
|
+
throw new MindStudioError(message, "db_query_error", res.status);
|
|
3515
|
+
}
|
|
3516
|
+
const data = await res.json();
|
|
3517
|
+
return data.results;
|
|
3731
3518
|
}
|
|
3732
3519
|
/**
|
|
3733
3520
|
* @internal Create a lazy Db proxy that auto-hydrates context.
|
|
3734
3521
|
*
|
|
3735
3522
|
* defineTable() returns Table instances immediately (no async needed).
|
|
3736
|
-
* But the Table's
|
|
3523
|
+
* But the Table's executeBatch callback is wrapped to call ensureContext()
|
|
3737
3524
|
* before the first query, so context is fetched lazily.
|
|
3738
3525
|
*/
|
|
3739
3526
|
_createLazyDb() {
|
|
@@ -3745,7 +3532,7 @@ var init_client = __esm({
|
|
|
3745
3532
|
databaseId: "",
|
|
3746
3533
|
tableName: name,
|
|
3747
3534
|
columns: [],
|
|
3748
|
-
|
|
3535
|
+
executeBatch: async (queries) => {
|
|
3749
3536
|
await agent.ensureContext();
|
|
3750
3537
|
const databases = agent._context.databases;
|
|
3751
3538
|
let targetDb;
|
|
@@ -3759,7 +3546,7 @@ var init_client = __esm({
|
|
|
3759
3546
|
);
|
|
3760
3547
|
}
|
|
3761
3548
|
const databaseId = targetDb?.id ?? databases[0]?.id ?? "";
|
|
3762
|
-
return agent.
|
|
3549
|
+
return agent._executeDbBatch(databaseId, queries);
|
|
3763
3550
|
}
|
|
3764
3551
|
});
|
|
3765
3552
|
},
|
|
@@ -3974,7 +3761,7 @@ async function startMcpServer(options) {
|
|
|
3974
3761
|
capabilities: { tools: {} },
|
|
3975
3762
|
serverInfo: {
|
|
3976
3763
|
name: "mindstudio-agent",
|
|
3977
|
-
version: "0.1.
|
|
3764
|
+
version: "0.1.10"
|
|
3978
3765
|
},
|
|
3979
3766
|
instructions: "Welcome to MindStudio \u2014 a platform with 200+ AI models, 850+ third-party integrations, and pre-built agents.\n\nGetting started:\n1. Call `listAgents` to verify your connection and see available agents.\n2. Call `changeName` to set your display name \u2014 use your name or whatever your user calls you. This is how you'll appear in MindStudio request logs.\n3. If you have a profile picture or icon, call `uploadFile` to upload it, then `changeProfilePicture` with the returned URL. This helps users identify your requests in their logs.\n4. Call `listActions` to discover all available actions.\n\nThen use the tools to generate text, images, video, audio, search the web, work with data sources, run agents, and more.\n\nImportant:\n- AI-powered actions (text generation, image generation, video, audio, etc.) cost money. Before running these, call `estimateActionCost` and confirm with the user before proceeding \u2014 unless they've explicitly told you to go ahead.\n- Not all agents from `listAgents` are configured for API use. Do not try to run an agent just because it appears in the list \u2014 it will likely fail. Only run agents the user specifically asks you to run."
|
|
3980
3767
|
});
|
|
@@ -4794,7 +4581,7 @@ function isNewerVersion(current, latest) {
|
|
|
4794
4581
|
return false;
|
|
4795
4582
|
}
|
|
4796
4583
|
async function checkForUpdate() {
|
|
4797
|
-
const currentVersion = "0.1.
|
|
4584
|
+
const currentVersion = "0.1.10";
|
|
4798
4585
|
if (!currentVersion) return null;
|
|
4799
4586
|
try {
|
|
4800
4587
|
const { loadConfig: loadConfig2, saveConfig: saveConfig2 } = await Promise.resolve().then(() => (init_config(), config_exports));
|
|
@@ -4823,7 +4610,7 @@ async function checkForUpdate() {
|
|
|
4823
4610
|
}
|
|
4824
4611
|
}
|
|
4825
4612
|
function printUpdateNotice(latestVersion) {
|
|
4826
|
-
const currentVersion = "0.1.
|
|
4613
|
+
const currentVersion = "0.1.10";
|
|
4827
4614
|
process.stderr.write(
|
|
4828
4615
|
`
|
|
4829
4616
|
${ansi.cyanBright("Update available")} ${ansi.gray(currentVersion + " \u2192")} ${ansi.cyanBold(latestVersion)}
|
|
@@ -4878,7 +4665,7 @@ async function cmdLogin(options) {
|
|
|
4878
4665
|
process.stderr.write("\n");
|
|
4879
4666
|
printLogo();
|
|
4880
4667
|
process.stderr.write("\n");
|
|
4881
|
-
const ver = "0.1.
|
|
4668
|
+
const ver = "0.1.10";
|
|
4882
4669
|
process.stderr.write(
|
|
4883
4670
|
` ${ansi.bold("MindStudio Agent")} ${ver ? " " + ansi.gray("v" + ver) : ""}
|
|
4884
4671
|
`
|
|
@@ -4961,6 +4748,9 @@ async function cmdLogin(options) {
|
|
|
4961
4748
|
` ${ansi.greenBold("\u2714")} Authenticated successfully!
|
|
4962
4749
|
${ansi.gray("Credentials saved to")} ${getConfigPath2()}
|
|
4963
4750
|
|
|
4751
|
+
${ansi.bold("Using with Claude Code?")} Run once to enable the MCP server:
|
|
4752
|
+
${ansi.cyan("claude mcp add mindstudio -- mindstudio mcp")}
|
|
4753
|
+
|
|
4964
4754
|
`
|
|
4965
4755
|
);
|
|
4966
4756
|
return;
|