deepspace 0.22.0 → 0.23.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/dist/build.d.ts +115 -0
- package/dist/build.js +66 -0
- package/dist/build.js.map +1 -0
- package/dist/{chunk-7TDBFEB7.js → chunk-A7VKZRCB.js} +2 -2
- package/dist/{chunk-7TDBFEB7.js.map → chunk-A7VKZRCB.js.map} +1 -1
- package/dist/cli.js +272 -52
- package/dist/cli.js.map +1 -1
- package/dist/documentation-client-core.js +1 -1
- package/dist/documentation-default-renderer.cjs +1 -1
- package/dist/documentation-react.js +1 -1
- package/dist/documentation-runtime.js +1 -1
- package/dist/documentation-server-core.js +1 -1
- package/dist/documentation.js +1 -1
- package/dist/documentation.js.map +1 -1
- package/dist/index.d.ts +22 -6
- package/dist/index.js +23 -29
- package/dist/index.js.map +1 -1
- package/dist/schema.js +6 -0
- package/dist/schema.js.map +1 -1
- package/dist/server.d.ts +51 -12
- package/dist/server.js +193 -150
- package/dist/server.js.map +1 -1
- package/dist/testing.d.ts +2 -0
- package/dist/testing.js +21 -9
- package/dist/testing.js.map +1 -1
- package/dist/worker.d.ts +54 -12
- package/dist/worker.js +119 -75
- package/dist/worker.js.map +1 -1
- package/package.json +5 -1
package/dist/worker.js
CHANGED
|
@@ -379,6 +379,7 @@ var MSG_YJS_AWARENESS = 23;
|
|
|
379
379
|
var ROLE_ANONYMOUS = "viewer";
|
|
380
380
|
var ROLE_DEFAULT = "member";
|
|
381
381
|
var ROLE_ADMIN = "admin";
|
|
382
|
+
var RECORD_NOT_FOUND = "Record not found";
|
|
382
383
|
|
|
383
384
|
// src/server/schemas/registry.ts
|
|
384
385
|
function collectionTableName(name) {
|
|
@@ -581,13 +582,11 @@ function checkUnclaimedOwnerTransition(schema, role, nextData, userId) {
|
|
|
581
582
|
}
|
|
582
583
|
return `Role '${role}' can set '${schema.ownerField}' only to their own user id or leave it unclaimed`;
|
|
583
584
|
}
|
|
585
|
+
var SYSTEM_ASSIGNED_COLUMNS = /* @__PURE__ */ new Set(["email", "name", "imageUrl", "role"]);
|
|
586
|
+
var SYSTEM_MAINTAINED_COLUMNS = /* @__PURE__ */ new Set(["createdAt", "lastSeenAt"]);
|
|
584
587
|
var SYSTEM_MANAGED_COLUMNS = /* @__PURE__ */ new Set([
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
"imageUrl",
|
|
588
|
-
"role",
|
|
589
|
-
"createdAt",
|
|
590
|
-
"lastSeenAt"
|
|
588
|
+
...SYSTEM_ASSIGNED_COLUMNS,
|
|
589
|
+
...SYSTEM_MAINTAINED_COLUMNS
|
|
591
590
|
]);
|
|
592
591
|
var USERS_COLUMNS = [
|
|
593
592
|
{ name: "email", storage: "text", interpretation: "plain" },
|
|
@@ -1180,6 +1179,11 @@ function encode(message) {
|
|
|
1180
1179
|
function getResolvedColumns(schema) {
|
|
1181
1180
|
return (schema.columns ?? []).map(resolveColumn);
|
|
1182
1181
|
}
|
|
1182
|
+
function systemManagedColumnError(column, isUpdate) {
|
|
1183
|
+
const roleHint = column === "role" ? ", or the admin-gated useUsers().setRole() to change a role" : "";
|
|
1184
|
+
const remedy = isUpdate ? `Re-sending the current value of '${column}' unchanged is accepted and ignored.` : `A users row is created by registration, so no value for '${column}' is accepted here \u2014 omit it.`;
|
|
1185
|
+
return `FIELD ERROR: '${column}' is system-managed and cannot be set by a record write \u2014 nothing was written. Use tools.registerUser({ userId, isAdmin })${roleHint}. ${remedy}`;
|
|
1186
|
+
}
|
|
1183
1187
|
function notifyTeamMembershipChange(ctx, collection, record) {
|
|
1184
1188
|
if (collection !== "team_members") return;
|
|
1185
1189
|
const affectedUserId = record.data.UserId;
|
|
@@ -1250,11 +1254,9 @@ function handleDelete(ctx, ws, attachment, payload) {
|
|
|
1250
1254
|
}
|
|
1251
1255
|
}
|
|
1252
1256
|
function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRbac = false, systemUpdate = false) {
|
|
1253
|
-
const
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
return { success: false, error: `Schema not registered for collection: ${collection}` };
|
|
1257
|
-
}
|
|
1257
|
+
const resolved = resolveCollection(ctx, collection);
|
|
1258
|
+
if (!resolved.ok) return { success: false, error: resolved.error };
|
|
1259
|
+
const schema = resolved.schema;
|
|
1258
1260
|
if (!schema) {
|
|
1259
1261
|
return { success: false, error: `Schema not registered for collection: ${collection}` };
|
|
1260
1262
|
}
|
|
@@ -1309,17 +1311,7 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
1309
1311
|
}
|
|
1310
1312
|
}
|
|
1311
1313
|
}
|
|
1312
|
-
|
|
1313
|
-
if (!systemUpdate && schema.name === "users") {
|
|
1314
|
-
finalData = { ...mergedData };
|
|
1315
|
-
for (const key of SYSTEM_MANAGED_COLUMNS) {
|
|
1316
|
-
if (existing?.data[key] !== void 0) {
|
|
1317
|
-
finalData[key] = existing.data[key];
|
|
1318
|
-
} else {
|
|
1319
|
-
delete finalData[key];
|
|
1320
|
-
}
|
|
1321
|
-
}
|
|
1322
|
-
}
|
|
1314
|
+
const finalData = { ...mergedData };
|
|
1323
1315
|
if (!skipUserRbac) {
|
|
1324
1316
|
const permCtx = ctx.getPermissionContext();
|
|
1325
1317
|
if (isUpdate) {
|
|
@@ -1351,6 +1343,17 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
1351
1343
|
return { success: false, error: `FIELD ERROR: ${ownerError}` };
|
|
1352
1344
|
}
|
|
1353
1345
|
}
|
|
1346
|
+
if (!systemUpdate && schema.name === "users") {
|
|
1347
|
+
for (const col of columns) {
|
|
1348
|
+
if (!SYSTEM_MANAGED_COLUMNS.has(col.name)) continue;
|
|
1349
|
+
const current = existing?.data[col.name];
|
|
1350
|
+
if (SYSTEM_ASSIGNED_COLUMNS.has(col.name) && Object.hasOwn(data, col.name) && coerceValue(data[col.name], col.storage, col.interpretation) !== coerceValue(current, col.storage, col.interpretation)) {
|
|
1351
|
+
return { success: false, error: systemManagedColumnError(col.name, isUpdate) };
|
|
1352
|
+
}
|
|
1353
|
+
if (current !== void 0) finalData[col.name] = current;
|
|
1354
|
+
else delete finalData[col.name];
|
|
1355
|
+
}
|
|
1356
|
+
}
|
|
1354
1357
|
const colValues = dataToColumnValues(finalData, columns);
|
|
1355
1358
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1356
1359
|
const tbl = collectionTableName(collection);
|
|
@@ -1410,14 +1413,12 @@ function putRecord(ctx, collection, recordId, data, userId, userRole, skipUserRb
|
|
|
1410
1413
|
return { success: true, data: { recordId, record } };
|
|
1411
1414
|
}
|
|
1412
1415
|
function deleteRecord(ctx, collection, recordId, userId, userRole, skipUserRbac = false) {
|
|
1413
|
-
const
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
return { success: false, error: `Schema not registered for collection: ${collection}` };
|
|
1417
|
-
}
|
|
1416
|
+
const resolved = resolveCollection(ctx, collection);
|
|
1417
|
+
if (!resolved.ok) return { success: false, error: resolved.error };
|
|
1418
|
+
const schema = resolved.schema;
|
|
1418
1419
|
const existing = getRecord(ctx.sql, collection, recordId, schema);
|
|
1419
1420
|
if (!existing) {
|
|
1420
|
-
return { success: false, error:
|
|
1421
|
+
return { success: false, error: RECORD_NOT_FOUND };
|
|
1421
1422
|
}
|
|
1422
1423
|
if (!skipUserRbac && schema && !canDelete(schema, userRole, { ...existing, recordId }, userId, ctx.getPermissionContext())) {
|
|
1423
1424
|
return { success: false, error: `DELETE DENIED: role=${userRole}, collection=${collection}` };
|
|
@@ -1436,14 +1437,12 @@ function deleteRecord(ctx, collection, recordId, userId, userRole, skipUserRbac
|
|
|
1436
1437
|
return { success: true, data: { deleted: true } };
|
|
1437
1438
|
}
|
|
1438
1439
|
function readRecord(ctx, collection, recordId, userId, userRole, skipUserRbac = false) {
|
|
1439
|
-
const
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
return { success: false, error: `Schema not registered for collection: ${collection}` };
|
|
1443
|
-
}
|
|
1440
|
+
const resolved = resolveCollection(ctx, collection);
|
|
1441
|
+
if (!resolved.ok) return { success: false, error: resolved.error };
|
|
1442
|
+
const schema = resolved.schema;
|
|
1444
1443
|
const existing = getRecord(ctx.sql, collection, recordId, schema);
|
|
1445
1444
|
if (!existing) {
|
|
1446
|
-
return { success: false, error:
|
|
1445
|
+
return { success: false, error: RECORD_NOT_FOUND };
|
|
1447
1446
|
}
|
|
1448
1447
|
if (!skipUserRbac && schema && !canRead(schema, userRole, { ...existing, recordId }, userId, ctx.getPermissionContext())) {
|
|
1449
1448
|
return { success: false, error: `READ DENIED: role=${userRole}, collection=${collection}` };
|
|
@@ -1474,9 +1473,7 @@ function hasYjsSubscription(attachment, target) {
|
|
|
1474
1473
|
(subscription) => subscription.collection === target.collection && subscription.recordId === target.recordId && subscription.fieldName === target.fieldName
|
|
1475
1474
|
);
|
|
1476
1475
|
}
|
|
1477
|
-
var SYSTEM_COLLECTIONS = /* @__PURE__ */ new Set([
|
|
1478
|
-
"canvas-settings"
|
|
1479
|
-
]);
|
|
1476
|
+
var SYSTEM_COLLECTIONS = /* @__PURE__ */ new Set(["canvas-settings"]);
|
|
1480
1477
|
var SYSTEM_COLLECTION_SCHEMAS = [
|
|
1481
1478
|
{
|
|
1482
1479
|
name: "canvas-settings",
|
|
@@ -1493,10 +1490,7 @@ function getOrCreateYjsDoc(ctx, docKey) {
|
|
|
1493
1490
|
let doc = ctx.yjsDocs.get(docKey);
|
|
1494
1491
|
if (doc) return doc;
|
|
1495
1492
|
doc = new Y2.Doc();
|
|
1496
|
-
const row = ctx.sql.exec(
|
|
1497
|
-
`SELECT state FROM yjs_docs WHERE doc_key = ?`,
|
|
1498
|
-
docKey
|
|
1499
|
-
).toArray()[0];
|
|
1493
|
+
const row = ctx.sql.exec(`SELECT state FROM yjs_docs WHERE doc_key = ?`, docKey).toArray()[0];
|
|
1500
1494
|
if (row?.state) {
|
|
1501
1495
|
try {
|
|
1502
1496
|
Y2.applyUpdate(doc, new Uint8Array(row.state));
|
|
@@ -1561,11 +1555,17 @@ function handleYjsJoin(ctx, ws, attachment, payload) {
|
|
|
1561
1555
|
}
|
|
1562
1556
|
} else {
|
|
1563
1557
|
if (!schema) {
|
|
1564
|
-
|
|
1558
|
+
const resolution = resolveCollection(ctx, collection);
|
|
1559
|
+
ctx.send(ws, {
|
|
1560
|
+
type: MSG.ERROR,
|
|
1561
|
+
payload: {
|
|
1562
|
+
error: resolution.ok ? `Schema not registered for collection: ${collection}` : resolution.error
|
|
1563
|
+
}
|
|
1564
|
+
});
|
|
1565
1565
|
return;
|
|
1566
1566
|
}
|
|
1567
1567
|
if (!record) {
|
|
1568
|
-
ctx.send(ws, { type: MSG.ERROR, payload: { error:
|
|
1568
|
+
ctx.send(ws, { type: MSG.ERROR, payload: { error: RECORD_NOT_FOUND } });
|
|
1569
1569
|
return;
|
|
1570
1570
|
}
|
|
1571
1571
|
const permCtx = ctx.getPermissionContext();
|
|
@@ -1598,7 +1598,10 @@ function handleYjsJoin(ctx, ws, attachment, payload) {
|
|
|
1598
1598
|
writeVarUint8Array(encoder2, fullState);
|
|
1599
1599
|
ctx.sendBinary(ws, toUint8Array(encoder2));
|
|
1600
1600
|
}
|
|
1601
|
-
ctx.send(ws, {
|
|
1601
|
+
ctx.send(ws, {
|
|
1602
|
+
type: MSG.YJS_JOIN,
|
|
1603
|
+
payload: { collection, recordId, fieldName, canWrite: hasWriteAccess }
|
|
1604
|
+
});
|
|
1602
1605
|
}
|
|
1603
1606
|
function handleYjsLeave(ctx, ws, attachment, payload) {
|
|
1604
1607
|
const { collection, recordId, fieldName } = payload;
|
|
@@ -1667,7 +1670,14 @@ function handleYjsBinaryMessage(ctx, ws, attachment, data) {
|
|
|
1667
1670
|
if (!syncSchema) return;
|
|
1668
1671
|
const record = getRecord(ctx.sql, collection, recordId, syncSchema);
|
|
1669
1672
|
if (!record) return;
|
|
1670
|
-
if (!canUpdate(
|
|
1673
|
+
if (!canUpdate(
|
|
1674
|
+
syncSchema,
|
|
1675
|
+
attachment.role,
|
|
1676
|
+
{ ...record, recordId },
|
|
1677
|
+
attachment.userId,
|
|
1678
|
+
ctx.getPermissionContext()
|
|
1679
|
+
))
|
|
1680
|
+
return;
|
|
1671
1681
|
}
|
|
1672
1682
|
const update = readVarUint8Array(decoder);
|
|
1673
1683
|
Y2.applyUpdate(doc, update, "client");
|
|
@@ -1741,6 +1751,19 @@ function handleYjsDisconnect(ctx, ws, attachment) {
|
|
|
1741
1751
|
}
|
|
1742
1752
|
|
|
1743
1753
|
// src/server/handlers/subscriptions.ts
|
|
1754
|
+
function resolveCollection(ctx, collection) {
|
|
1755
|
+
const isSystem = SYSTEM_COLLECTIONS.has(collection);
|
|
1756
|
+
const schema = ctx.schemaRegistry.get(collection);
|
|
1757
|
+
if (!schema && !isSystem) {
|
|
1758
|
+
const known = ctx.schemaRegistry.names().sort().join(", ") || "(none)";
|
|
1759
|
+
const room = ctx.scopeId ? `Room '${ctx.scopeId}'` : "This room";
|
|
1760
|
+
return {
|
|
1761
|
+
ok: false,
|
|
1762
|
+
error: `Schema not registered for collection: ${collection} \u2014 ${room} serves only: ${known}. Records are sharded by scope, so address the room that owns '${collection}', or add it to the schemas this room is constructed with.`
|
|
1763
|
+
};
|
|
1764
|
+
}
|
|
1765
|
+
return { ok: true, schema, isSystem };
|
|
1766
|
+
}
|
|
1744
1767
|
function handleSubscribe(ctx, ws, attachment, payload) {
|
|
1745
1768
|
const { subscriptionId, query } = payload;
|
|
1746
1769
|
const records = executeQuery(ctx, query, attachment.userId, attachment.role);
|
|
@@ -1749,15 +1772,20 @@ function handleSubscribe(ctx, ws, attachment, payload) {
|
|
|
1749
1772
|
function handleUnsubscribe(_ctx, _ws, _attachment, _payload) {
|
|
1750
1773
|
}
|
|
1751
1774
|
function executeQuery(ctx, query, userId, userRole, skipUserRbac = false) {
|
|
1752
|
-
const
|
|
1753
|
-
|
|
1754
|
-
if (!schema
|
|
1755
|
-
return [];
|
|
1756
|
-
}
|
|
1757
|
-
if (!schema) {
|
|
1775
|
+
const resolved = resolveCollection(ctx, query.collection);
|
|
1776
|
+
if (!resolved.ok) return [];
|
|
1777
|
+
if (!resolved.schema) {
|
|
1758
1778
|
return executeSystemQuery(ctx, query);
|
|
1759
1779
|
}
|
|
1760
|
-
return executeTableQuery(
|
|
1780
|
+
return executeTableQuery(
|
|
1781
|
+
ctx,
|
|
1782
|
+
query,
|
|
1783
|
+
resolved.schema,
|
|
1784
|
+
userId,
|
|
1785
|
+
userRole,
|
|
1786
|
+
resolved.isSystem,
|
|
1787
|
+
skipUserRbac
|
|
1788
|
+
);
|
|
1761
1789
|
}
|
|
1762
1790
|
function executeSystemQuery(ctx, query) {
|
|
1763
1791
|
const tbl = collectionTableName(query.collection);
|
|
@@ -2258,7 +2286,10 @@ async function handleToolsRequest(ctx, request, path) {
|
|
|
2258
2286
|
const toolName = path.replace("tools/describe/", "");
|
|
2259
2287
|
const tool3 = BUILT_IN_TOOLS.find((t) => t.name === toolName);
|
|
2260
2288
|
if (!tool3) {
|
|
2261
|
-
return Response.json(
|
|
2289
|
+
return Response.json(
|
|
2290
|
+
{ error: `Tool not found: ${toolName}` },
|
|
2291
|
+
{ status: 404, headers: CORS_HEADERS }
|
|
2292
|
+
);
|
|
2262
2293
|
}
|
|
2263
2294
|
return Response.json({ tool: tool3 }, { headers: CORS_HEADERS });
|
|
2264
2295
|
}
|
|
@@ -2303,6 +2334,7 @@ async function handleToolExecute(ctx, request) {
|
|
|
2303
2334
|
const recordCtx = {
|
|
2304
2335
|
sql: ctx.sql,
|
|
2305
2336
|
schemaRegistry: ctx.schemaRegistry,
|
|
2337
|
+
scopeId: ctx.scopeId,
|
|
2306
2338
|
state: ctx.state,
|
|
2307
2339
|
getPermissionContext: ctx.getPermissionContext,
|
|
2308
2340
|
send: ctx.send
|
|
@@ -2317,6 +2349,8 @@ async function executeTool(ctx, toolName, params, userId, userRole, skipUserRbac
|
|
|
2317
2349
|
case "records.query": {
|
|
2318
2350
|
const collection = params.collection;
|
|
2319
2351
|
if (!collection) return { success: false, error: "Missing required param: collection" };
|
|
2352
|
+
const resolved = resolveCollection(ctx, collection);
|
|
2353
|
+
if (!resolved.ok) return { success: false, error: resolved.error };
|
|
2320
2354
|
const query = {
|
|
2321
2355
|
collection,
|
|
2322
2356
|
where: params.where,
|
|
@@ -2426,10 +2460,13 @@ async function executeTool(ctx, toolName, params, userId, userRole, skipUserRbac
|
|
|
2426
2460
|
}
|
|
2427
2461
|
function checkYjsPermission(ctx, collection, recordId, userId, userRole, action) {
|
|
2428
2462
|
if (SYSTEM_COLLECTIONS.has(collection)) return null;
|
|
2429
|
-
const
|
|
2430
|
-
if (!
|
|
2463
|
+
const resolution = resolveCollection(ctx, collection);
|
|
2464
|
+
if (!resolution.ok) return { success: false, error: resolution.error };
|
|
2465
|
+
const schema = resolution.schema;
|
|
2466
|
+
if (!schema)
|
|
2467
|
+
return { success: false, error: `Schema not registered for collection: ${collection}` };
|
|
2431
2468
|
const record = getRecord(ctx.sql, collection, recordId, schema);
|
|
2432
|
-
if (!record) return { success: false, error:
|
|
2469
|
+
if (!record) return { success: false, error: `${RECORD_NOT_FOUND}: ${collection}/${recordId}` };
|
|
2433
2470
|
const recordWithId = { ...record, recordId };
|
|
2434
2471
|
const permCtx = ctx.getPermissionContext();
|
|
2435
2472
|
if (action === "read" && !canRead(schema, userRole, recordWithId, userId, permCtx)) {
|
|
@@ -2462,9 +2499,7 @@ function withYjsDoc(ctx, docKey, operation) {
|
|
|
2462
2499
|
function executeYjsTool(ctx, toolName, params, userId, userRole) {
|
|
2463
2500
|
switch (toolName) {
|
|
2464
2501
|
case "yjs.list": {
|
|
2465
|
-
const rows = ctx.sql.exec(
|
|
2466
|
-
`SELECT doc_key, updated_at FROM yjs_docs ORDER BY updated_at DESC`
|
|
2467
|
-
).toArray();
|
|
2502
|
+
const rows = ctx.sql.exec(`SELECT doc_key, updated_at FROM yjs_docs ORDER BY updated_at DESC`).toArray();
|
|
2468
2503
|
const docs = rows.map((row) => {
|
|
2469
2504
|
const firstColon = row.doc_key.indexOf(":");
|
|
2470
2505
|
const lastColon = row.doc_key.lastIndexOf(":");
|
|
@@ -3087,6 +3122,10 @@ var RecordRoom = class extends BaseRoom {
|
|
|
3087
3122
|
sql: this.sql,
|
|
3088
3123
|
state: this.state,
|
|
3089
3124
|
schemaRegistry: this.schemaRegistry,
|
|
3125
|
+
// Every record room stub is addressed with `idFromName(scopeId)`, so the
|
|
3126
|
+
// DO's own name is the scope. Handlers use it to name the room when a
|
|
3127
|
+
// caller asks it for a collection that lives in a different scope.
|
|
3128
|
+
scopeId: this.state.id.name,
|
|
3090
3129
|
getPermissionContext: () => this.getPermissionContext(),
|
|
3091
3130
|
send: (ws, msg) => this.send(ws, msg),
|
|
3092
3131
|
sendBinary: (ws, data) => this.sendBinaryHelper(ws, data),
|
|
@@ -7542,7 +7581,7 @@ function authWorkerFetch(env, path, init) {
|
|
|
7542
7581
|
function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
7543
7582
|
const roomIdObj = env.RECORD_ROOMS.idFromName(roomId);
|
|
7544
7583
|
const room = env.RECORD_ROOMS.get(roomIdObj);
|
|
7545
|
-
async function
|
|
7584
|
+
async function executeTool2(tool3, params) {
|
|
7546
7585
|
const response = await room.fetch(
|
|
7547
7586
|
new Request("https://internal/api/tools/execute", {
|
|
7548
7587
|
method: "POST",
|
|
@@ -7565,18 +7604,18 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
|
|
|
7565
7604
|
const params = { collection };
|
|
7566
7605
|
if (opts?.where) params.where = opts.where;
|
|
7567
7606
|
if (opts?.limit) params.limit = opts.limit;
|
|
7568
|
-
const data = await
|
|
7607
|
+
const data = await executeTool2("records.query", params);
|
|
7569
7608
|
const records2 = data?.records;
|
|
7570
7609
|
return records2 ?? [];
|
|
7571
7610
|
},
|
|
7572
7611
|
async create(collection, data) {
|
|
7573
|
-
return
|
|
7612
|
+
return executeTool2("records.create", { collection, data });
|
|
7574
7613
|
},
|
|
7575
7614
|
async update(collection, recordId, data) {
|
|
7576
|
-
return
|
|
7615
|
+
return executeTool2("records.update", { collection, recordId, data });
|
|
7577
7616
|
},
|
|
7578
7617
|
async delete(collection, recordId) {
|
|
7579
|
-
return
|
|
7618
|
+
return executeTool2("records.delete", { collection, recordId });
|
|
7580
7619
|
}
|
|
7581
7620
|
};
|
|
7582
7621
|
const integrations = {
|
|
@@ -8312,7 +8351,7 @@ function makeDefaultSummarizer(env, options = {}) {
|
|
|
8312
8351
|
}
|
|
8313
8352
|
|
|
8314
8353
|
// src/server/utils/chat-history.ts
|
|
8315
|
-
async function
|
|
8354
|
+
async function executeToolAsApp(stub, userId, tool3, params) {
|
|
8316
8355
|
const res = await stub.fetch(new Request("https://internal/api/tools/execute", {
|
|
8317
8356
|
method: "POST",
|
|
8318
8357
|
headers: {
|
|
@@ -8353,13 +8392,15 @@ function toMessageRow(env) {
|
|
|
8353
8392
|
}
|
|
8354
8393
|
async function getChat(stub, chatId, userId) {
|
|
8355
8394
|
try {
|
|
8356
|
-
const result = await
|
|
8395
|
+
const result = await executeToolAsApp(stub, userId, "records.get", {
|
|
8357
8396
|
collection: "ai-chats",
|
|
8358
8397
|
recordId: chatId
|
|
8359
8398
|
});
|
|
8360
|
-
|
|
8399
|
+
if (!result.record) return null;
|
|
8400
|
+
const chat = toChatRow(result.record);
|
|
8401
|
+
return chat.userId === userId ? chat : null;
|
|
8361
8402
|
} catch (err) {
|
|
8362
|
-
if (err instanceof Error && err.message.includes(
|
|
8403
|
+
if (err instanceof Error && err.message.includes(RECORD_NOT_FOUND)) return null;
|
|
8363
8404
|
throw err;
|
|
8364
8405
|
}
|
|
8365
8406
|
}
|
|
@@ -8367,28 +8408,28 @@ async function createChat(stub, userId, opts = {}) {
|
|
|
8367
8408
|
const data = { userId };
|
|
8368
8409
|
if (opts.title !== void 0) data.title = opts.title;
|
|
8369
8410
|
if (opts.model !== void 0) data.model = opts.model;
|
|
8370
|
-
const result = await
|
|
8411
|
+
const result = await executeToolAsApp(stub, userId, "records.create", {
|
|
8371
8412
|
collection: "ai-chats",
|
|
8372
8413
|
data
|
|
8373
8414
|
});
|
|
8374
8415
|
return toChatRow(result.record);
|
|
8375
8416
|
}
|
|
8376
8417
|
async function updateChat(stub, chatId, userId, patch) {
|
|
8377
|
-
await
|
|
8418
|
+
await executeToolAsApp(stub, userId, "records.update", {
|
|
8378
8419
|
collection: "ai-chats",
|
|
8379
8420
|
recordId: chatId,
|
|
8380
8421
|
data: patch
|
|
8381
8422
|
});
|
|
8382
8423
|
}
|
|
8383
8424
|
async function deleteChatCascade(stub, chatId, userId) {
|
|
8384
|
-
const list = await
|
|
8425
|
+
const list = await executeToolAsApp(stub, userId, "records.query", {
|
|
8385
8426
|
collection: "ai-messages",
|
|
8386
8427
|
where: { chatId }
|
|
8387
8428
|
});
|
|
8388
8429
|
const errors = [];
|
|
8389
8430
|
for (const env of list.records) {
|
|
8390
8431
|
try {
|
|
8391
|
-
await
|
|
8432
|
+
await executeToolAsApp(stub, userId, "records.delete", {
|
|
8392
8433
|
collection: "ai-messages",
|
|
8393
8434
|
recordId: env.recordId
|
|
8394
8435
|
});
|
|
@@ -8397,7 +8438,7 @@ async function deleteChatCascade(stub, chatId, userId) {
|
|
|
8397
8438
|
}
|
|
8398
8439
|
}
|
|
8399
8440
|
try {
|
|
8400
|
-
await
|
|
8441
|
+
await executeToolAsApp(stub, userId, "records.delete", {
|
|
8401
8442
|
collection: "ai-chats",
|
|
8402
8443
|
recordId: chatId
|
|
8403
8444
|
});
|
|
@@ -8413,7 +8454,7 @@ async function deleteChatCascade(stub, chatId, userId) {
|
|
|
8413
8454
|
}
|
|
8414
8455
|
}
|
|
8415
8456
|
async function loadMessages(stub, chatId, userId) {
|
|
8416
|
-
const result = await
|
|
8457
|
+
const result = await executeToolAsApp(stub, userId, "records.query", {
|
|
8417
8458
|
collection: "ai-messages",
|
|
8418
8459
|
where: { chatId, userId },
|
|
8419
8460
|
orderBy: "createdAt",
|
|
@@ -8429,7 +8470,7 @@ async function appendMessage(stub, msg) {
|
|
|
8429
8470
|
content: msg.content
|
|
8430
8471
|
};
|
|
8431
8472
|
if (msg.parts !== void 0) data.parts = msg.parts;
|
|
8432
|
-
await
|
|
8473
|
+
await executeToolAsApp(stub, msg.userId, "records.create", {
|
|
8433
8474
|
collection: "ai-messages",
|
|
8434
8475
|
recordId: msg.id,
|
|
8435
8476
|
data
|
|
@@ -10185,6 +10226,7 @@ export {
|
|
|
10185
10226
|
PresenceRoom,
|
|
10186
10227
|
REACTIONS_SCHEMA,
|
|
10187
10228
|
READ_RECEIPTS_SCHEMA,
|
|
10229
|
+
RECORD_NOT_FOUND,
|
|
10188
10230
|
REGISTRY_INSTANCE,
|
|
10189
10231
|
RELEASE_STAMP_PATH,
|
|
10190
10232
|
REPO_STORE_LIMIT_BYTES,
|
|
@@ -10201,7 +10243,9 @@ export {
|
|
|
10201
10243
|
SDK_RUN_WORKER_FIRST,
|
|
10202
10244
|
SECURE_ROOM_BOUNDARIES_MIGRATION_ID,
|
|
10203
10245
|
STRICT_APP_ID_RE,
|
|
10246
|
+
SYSTEM_ASSIGNED_COLUMNS,
|
|
10204
10247
|
SYSTEM_COLLECTIONS,
|
|
10248
|
+
SYSTEM_MAINTAINED_COLUMNS,
|
|
10205
10249
|
SYSTEM_MANAGED_COLUMNS,
|
|
10206
10250
|
SchemaRegistry,
|
|
10207
10251
|
TEST_ACCOUNT_EMAIL_SUFFIX,
|