@mindstudio-ai/agent 0.1.34 → 0.1.35
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/dist/cli.js +144 -31
- package/dist/index.d.ts +40 -1
- package/dist/index.js +136 -25
- package/dist/index.js.map +1 -1
- package/dist/postinstall.js +144 -31
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -37,13 +37,23 @@ async function requestWithRetry(config, method, url, body, attempt) {
|
|
|
37
37
|
return requestWithRetry(config, method, url, body, attempt + 1);
|
|
38
38
|
}
|
|
39
39
|
if (!res.ok) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
res.
|
|
45
|
-
|
|
46
|
-
|
|
40
|
+
let message = `${res.status} ${res.statusText}`;
|
|
41
|
+
let code = "api_error";
|
|
42
|
+
let details;
|
|
43
|
+
try {
|
|
44
|
+
const text = await res.text();
|
|
45
|
+
try {
|
|
46
|
+
const body2 = JSON.parse(text);
|
|
47
|
+
details = body2;
|
|
48
|
+
const errMsg = body2.error ?? body2.message ?? body2.details;
|
|
49
|
+
if (errMsg) message = errMsg;
|
|
50
|
+
if (body2.code) code = body2.code;
|
|
51
|
+
} catch {
|
|
52
|
+
if (text && text.length < 500) message = text;
|
|
53
|
+
}
|
|
54
|
+
} catch {
|
|
55
|
+
}
|
|
56
|
+
throw new MindStudioError(message, code, res.status, details);
|
|
47
57
|
}
|
|
48
58
|
const data = await res.json();
|
|
49
59
|
return { data, headers: res.headers };
|
|
@@ -1248,6 +1258,9 @@ var Table = class {
|
|
|
1248
1258
|
const items = (isArray ? data : [data]).map(
|
|
1249
1259
|
(item) => this._config.defaults ? { ...this._config.defaults, ...item } : item
|
|
1250
1260
|
);
|
|
1261
|
+
for (const item of items) {
|
|
1262
|
+
this._checkManagedColumns(item);
|
|
1263
|
+
}
|
|
1251
1264
|
const queries = items.map(
|
|
1252
1265
|
(item) => buildInsert(
|
|
1253
1266
|
this._config.tableName,
|
|
@@ -1265,7 +1278,13 @@ var Table = class {
|
|
|
1265
1278
|
}
|
|
1266
1279
|
return void 0;
|
|
1267
1280
|
});
|
|
1268
|
-
|
|
1281
|
+
const result = isArray ? rows : rows[0];
|
|
1282
|
+
this._syncRolesIfNeeded(
|
|
1283
|
+
items,
|
|
1284
|
+
result,
|
|
1285
|
+
isArray
|
|
1286
|
+
);
|
|
1287
|
+
return result;
|
|
1269
1288
|
});
|
|
1270
1289
|
}
|
|
1271
1290
|
/**
|
|
@@ -1273,20 +1292,25 @@ var Table = class {
|
|
|
1273
1292
|
* Returns the updated row via `UPDATE ... RETURNING *`.
|
|
1274
1293
|
*/
|
|
1275
1294
|
update(id, data) {
|
|
1295
|
+
this._checkManagedColumns(data);
|
|
1276
1296
|
const query = buildUpdate(
|
|
1277
1297
|
this._config.tableName,
|
|
1278
1298
|
id,
|
|
1279
1299
|
data,
|
|
1280
1300
|
this._config.columns
|
|
1281
1301
|
);
|
|
1282
|
-
return new Mutation(
|
|
1283
|
-
|
|
1284
|
-
[query],
|
|
1285
|
-
(results) => deserializeRow(
|
|
1302
|
+
return new Mutation(this._config, [query], (results) => {
|
|
1303
|
+
const result = deserializeRow(
|
|
1286
1304
|
results[0].rows[0],
|
|
1287
1305
|
this._config.columns
|
|
1288
|
-
)
|
|
1289
|
-
|
|
1306
|
+
);
|
|
1307
|
+
this._syncRolesIfNeeded(
|
|
1308
|
+
[data],
|
|
1309
|
+
result,
|
|
1310
|
+
false
|
|
1311
|
+
);
|
|
1312
|
+
return result;
|
|
1313
|
+
});
|
|
1290
1314
|
}
|
|
1291
1315
|
remove(id) {
|
|
1292
1316
|
const query = buildDelete(this._config.tableName, `id = ?`, [id]);
|
|
@@ -1341,24 +1365,65 @@ var Table = class {
|
|
|
1341
1365
|
const conflictColumns = Array.isArray(conflictKey) ? conflictKey : [conflictKey];
|
|
1342
1366
|
this._validateUniqueConstraint(conflictColumns);
|
|
1343
1367
|
const withDefaults = this._config.defaults ? { ...this._config.defaults, ...data } : data;
|
|
1368
|
+
this._checkManagedColumns(withDefaults);
|
|
1344
1369
|
const query = buildUpsert(
|
|
1345
1370
|
this._config.tableName,
|
|
1346
1371
|
withDefaults,
|
|
1347
1372
|
conflictColumns,
|
|
1348
1373
|
this._config.columns
|
|
1349
1374
|
);
|
|
1350
|
-
return new Mutation(
|
|
1351
|
-
|
|
1352
|
-
[query],
|
|
1353
|
-
(results) => deserializeRow(
|
|
1375
|
+
return new Mutation(this._config, [query], (results) => {
|
|
1376
|
+
const result = deserializeRow(
|
|
1354
1377
|
results[0].rows[0],
|
|
1355
1378
|
this._config.columns
|
|
1356
|
-
)
|
|
1357
|
-
|
|
1379
|
+
);
|
|
1380
|
+
this._syncRolesIfNeeded([withDefaults], result, false);
|
|
1381
|
+
return result;
|
|
1382
|
+
});
|
|
1358
1383
|
}
|
|
1359
1384
|
// -------------------------------------------------------------------------
|
|
1360
1385
|
// Internal helpers
|
|
1361
1386
|
// -------------------------------------------------------------------------
|
|
1387
|
+
/** @internal Throw if data includes a platform-managed email/phone column. */
|
|
1388
|
+
_checkManagedColumns(data) {
|
|
1389
|
+
const mc = this._config.managedColumns;
|
|
1390
|
+
if (!mc) return;
|
|
1391
|
+
const keys = Object.keys(data);
|
|
1392
|
+
for (const key of keys) {
|
|
1393
|
+
if (mc.email && key === mc.email || mc.phone && key === mc.phone) {
|
|
1394
|
+
throw new MindStudioError(
|
|
1395
|
+
`Cannot write to "${key}" \u2014 this column is managed by auth. Use the auth API to change a user's ${key === mc.email ? "email" : "phone"}.`,
|
|
1396
|
+
"managed_column_write",
|
|
1397
|
+
400
|
|
1398
|
+
);
|
|
1399
|
+
}
|
|
1400
|
+
}
|
|
1401
|
+
}
|
|
1402
|
+
/**
|
|
1403
|
+
* @internal Fire role sync for rows that wrote to the roles column.
|
|
1404
|
+
* Called inside processResult (runs after SQL execution in both
|
|
1405
|
+
* standalone and batch paths). Fire-and-forget.
|
|
1406
|
+
*/
|
|
1407
|
+
_syncRolesIfNeeded(inputItems, result, isArray) {
|
|
1408
|
+
const rolesCol = this._config.managedColumns?.roles;
|
|
1409
|
+
const syncRoles = this._config.syncRoles;
|
|
1410
|
+
if (!rolesCol || !syncRoles) return;
|
|
1411
|
+
if (!inputItems.some((item) => rolesCol in item)) return;
|
|
1412
|
+
if (isArray) {
|
|
1413
|
+
for (const row of result) {
|
|
1414
|
+
if (row?.id) {
|
|
1415
|
+
syncRoles(row.id, row[rolesCol]).catch(() => {
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
} else {
|
|
1420
|
+
const row = result;
|
|
1421
|
+
if (row?.id) {
|
|
1422
|
+
syncRoles(row.id, row[rolesCol]).catch(() => {
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1362
1427
|
/** @internal Validate that the given columns match a declared unique constraint. */
|
|
1363
1428
|
_validateUniqueConstraint(columns) {
|
|
1364
1429
|
if (!this._config.unique?.length) {
|
|
@@ -1383,7 +1448,7 @@ var Table = class {
|
|
|
1383
1448
|
};
|
|
1384
1449
|
|
|
1385
1450
|
// src/db/index.ts
|
|
1386
|
-
function createDb(databases, executeBatch) {
|
|
1451
|
+
function createDb(databases, executeBatch, authConfig, syncRoles) {
|
|
1387
1452
|
return {
|
|
1388
1453
|
defineTable(name, options) {
|
|
1389
1454
|
const resolved = resolveTable(databases, name, options?.database);
|
|
@@ -1393,6 +1458,8 @@ function createDb(databases, executeBatch) {
|
|
|
1393
1458
|
columns: resolved.columns,
|
|
1394
1459
|
unique: options?.unique,
|
|
1395
1460
|
defaults: options?.defaults,
|
|
1461
|
+
managedColumns: authConfig?.table === name ? authConfig.columns : void 0,
|
|
1462
|
+
syncRoles: authConfig?.table === name && authConfig.columns.roles ? syncRoles : void 0,
|
|
1396
1463
|
executeBatch: (queries) => executeBatch(resolved.databaseId, queries)
|
|
1397
1464
|
};
|
|
1398
1465
|
return new Table(config);
|
|
@@ -3847,7 +3914,9 @@ var MindStudioAgent = class {
|
|
|
3847
3914
|
this._auth = new AuthContext(context.auth);
|
|
3848
3915
|
this._db = createDb(
|
|
3849
3916
|
context.databases,
|
|
3850
|
-
this._executeDbBatch.bind(this)
|
|
3917
|
+
this._executeDbBatch.bind(this),
|
|
3918
|
+
context.authConfig,
|
|
3919
|
+
this._syncRoles.bind(this)
|
|
3851
3920
|
);
|
|
3852
3921
|
}
|
|
3853
3922
|
/**
|
|
@@ -3863,7 +3932,8 @@ var MindStudioAgent = class {
|
|
|
3863
3932
|
if (ai?.auth && ai?.databases) {
|
|
3864
3933
|
this._applyContext({
|
|
3865
3934
|
auth: ai.auth,
|
|
3866
|
-
databases: ai.databases
|
|
3935
|
+
databases: ai.databases,
|
|
3936
|
+
authConfig: ai.authConfig
|
|
3867
3937
|
});
|
|
3868
3938
|
}
|
|
3869
3939
|
}
|
|
@@ -3909,6 +3979,39 @@ var MindStudioAgent = class {
|
|
|
3909
3979
|
const data = await res.json();
|
|
3910
3980
|
return data.results;
|
|
3911
3981
|
}
|
|
3982
|
+
/**
|
|
3983
|
+
* @internal Sync a user's roles to the platform after a successful
|
|
3984
|
+
* auth table write. Calls POST /_internal/v2/auth/sync-user.
|
|
3985
|
+
* Fire-and-forget: errors are caught and logged, never propagated.
|
|
3986
|
+
*/
|
|
3987
|
+
async _syncRoles(userId, roles) {
|
|
3988
|
+
try {
|
|
3989
|
+
const url = `${this._httpConfig.baseUrl}/_internal/v2/auth/sync-user`;
|
|
3990
|
+
const res = await fetch(url, {
|
|
3991
|
+
method: "POST",
|
|
3992
|
+
headers: {
|
|
3993
|
+
"Content-Type": "application/json",
|
|
3994
|
+
Authorization: this._token
|
|
3995
|
+
},
|
|
3996
|
+
body: JSON.stringify({
|
|
3997
|
+
appId: this._appId,
|
|
3998
|
+
userId,
|
|
3999
|
+
roles
|
|
4000
|
+
})
|
|
4001
|
+
});
|
|
4002
|
+
if (!res.ok) {
|
|
4003
|
+
const text = await res.text().catch(() => "");
|
|
4004
|
+
console.warn(
|
|
4005
|
+
`[mindstudio] Failed to sync roles for user ${userId}: ${res.status} ${text}`
|
|
4006
|
+
);
|
|
4007
|
+
}
|
|
4008
|
+
} catch (err) {
|
|
4009
|
+
console.warn(
|
|
4010
|
+
`[mindstudio] Failed to sync roles for user ${userId}:`,
|
|
4011
|
+
err
|
|
4012
|
+
);
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
3912
4015
|
/**
|
|
3913
4016
|
* @internal Create a lazy Db proxy that auto-hydrates context.
|
|
3914
4017
|
*
|
|
@@ -3921,7 +4024,7 @@ var MindStudioAgent = class {
|
|
|
3921
4024
|
return {
|
|
3922
4025
|
defineTable(name, options) {
|
|
3923
4026
|
const databaseHint = options?.database;
|
|
3924
|
-
|
|
4027
|
+
const tableConfig = {
|
|
3925
4028
|
databaseId: "",
|
|
3926
4029
|
tableName: name,
|
|
3927
4030
|
columns: [],
|
|
@@ -3929,6 +4032,13 @@ var MindStudioAgent = class {
|
|
|
3929
4032
|
defaults: options?.defaults,
|
|
3930
4033
|
executeBatch: async (queries) => {
|
|
3931
4034
|
await agent.ensureContext();
|
|
4035
|
+
const ac = agent._context.authConfig;
|
|
4036
|
+
if (ac && ac.table === name && !tableConfig.managedColumns) {
|
|
4037
|
+
tableConfig.managedColumns = ac.columns;
|
|
4038
|
+
if (ac.columns.roles) {
|
|
4039
|
+
tableConfig.syncRoles = agent._syncRoles.bind(agent);
|
|
4040
|
+
}
|
|
4041
|
+
}
|
|
3932
4042
|
const databases = agent._context.databases;
|
|
3933
4043
|
let targetDb;
|
|
3934
4044
|
if (databaseHint) {
|
|
@@ -3943,7 +4053,8 @@ var MindStudioAgent = class {
|
|
|
3943
4053
|
const databaseId = targetDb?.id ?? databases[0]?.id ?? "";
|
|
3944
4054
|
return agent._executeDbBatch(databaseId, queries);
|
|
3945
4055
|
}
|
|
3946
|
-
}
|
|
4056
|
+
};
|
|
4057
|
+
return new Table(tableConfig);
|
|
3947
4058
|
},
|
|
3948
4059
|
// Time helpers work without context
|
|
3949
4060
|
now: () => Date.now(),
|