deepspace 0.2.5 → 0.2.7

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/worker.js CHANGED
@@ -4130,6 +4130,40 @@ var DEFAULT_DO_MANIFEST = [
4130
4130
  { binding: "YJS_ROOMS", className: "AppYjsRoom", sqlite: true }
4131
4131
  ];
4132
4132
 
4133
+ // src/server/schemas/ai-chat.ts
4134
+ var AI_CHATS_SCHEMA = {
4135
+ name: "ai-chats",
4136
+ columns: [
4137
+ { name: "userId", storage: "text", interpretation: "plain", userBound: true, immutable: true, required: true },
4138
+ { name: "title", storage: "text", interpretation: "plain" },
4139
+ { name: "model", storage: "text", interpretation: "plain" },
4140
+ { name: "compactedSummary", storage: "text", interpretation: "plain" },
4141
+ { name: "compactedThroughId", storage: "text", interpretation: "plain" }
4142
+ ],
4143
+ ownerField: "userId",
4144
+ permissions: {
4145
+ admin: { read: true, create: true, update: true, delete: true },
4146
+ member: { read: "own", create: false, update: "own", delete: "own" },
4147
+ viewer: { read: "own", create: false, update: false, delete: false }
4148
+ }
4149
+ };
4150
+ var AI_MESSAGES_SCHEMA = {
4151
+ name: "ai-messages",
4152
+ columns: [
4153
+ { name: "chatId", storage: "text", interpretation: "plain", immutable: true, required: true },
4154
+ { name: "userId", storage: "text", interpretation: "plain", userBound: true, immutable: true, required: true },
4155
+ { name: "role", storage: "text", interpretation: "plain", required: true },
4156
+ { name: "content", storage: "text", interpretation: "plain" },
4157
+ { name: "parts", storage: "text", interpretation: { kind: "json" } }
4158
+ ],
4159
+ ownerField: "userId",
4160
+ permissions: {
4161
+ admin: { read: true, create: true, update: true, delete: true },
4162
+ member: { read: "own", create: false, update: "own", delete: "own" },
4163
+ viewer: { read: "own", create: false, update: false, delete: false }
4164
+ }
4165
+ };
4166
+
4133
4167
  // src/server/schemas/messaging.ts
4134
4168
  var CHANNELS_SCHEMA = {
4135
4169
  name: "channels",
@@ -5073,7 +5107,7 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
5073
5107
  const apiBase = env.API_BASE_URL || "https://api.deep.space";
5074
5108
  const roomIdObj = env.RECORD_ROOMS.idFromName(roomId);
5075
5109
  const room = env.RECORD_ROOMS.get(roomIdObj);
5076
- async function executeTool2(tool, params) {
5110
+ async function executeTool3(tool, params) {
5077
5111
  const response = await room.fetch(new Request("https://internal/api/tools/execute", {
5078
5112
  method: "POST",
5079
5113
  headers: {
@@ -5094,17 +5128,17 @@ function buildCronContext(env, ownerUserId, roomId = "default") {
5094
5128
  const params = { collection };
5095
5129
  if (opts?.where) params.where = opts.where;
5096
5130
  if (opts?.limit) params.limit = opts.limit;
5097
- const data = await executeTool2("records.query", params);
5131
+ const data = await executeTool3("records.query", params);
5098
5132
  return data.records || [];
5099
5133
  },
5100
5134
  async create(collection, data) {
5101
- return executeTool2("records.create", { collection, data });
5135
+ return executeTool3("records.create", { collection, data });
5102
5136
  },
5103
5137
  async update(collection, recordId, data) {
5104
- return executeTool2("records.update", { collection, recordId, data });
5138
+ return executeTool3("records.update", { collection, recordId, data });
5105
5139
  },
5106
5140
  async delete(collection, recordId) {
5107
- return executeTool2("records.delete", { collection, recordId });
5141
+ return executeTool3("records.delete", { collection, recordId });
5108
5142
  }
5109
5143
  };
5110
5144
  const integrations = {
@@ -5266,13 +5300,10 @@ function createDeepSpaceAI(env, provider, options = {}) {
5266
5300
  switch (provider) {
5267
5301
  case "anthropic":
5268
5302
  return createAnthropic({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
5269
- case "openai":
5270
- return createOpenAI({
5271
- baseURL,
5272
- apiKey: "platform-managed",
5273
- fetch: proxyFetch,
5274
- compatibility: "strict"
5275
- });
5303
+ case "openai": {
5304
+ const op = createOpenAI({ baseURL, apiKey: "platform-managed", fetch: proxyFetch });
5305
+ return op.chat;
5306
+ }
5276
5307
  case "cerebras":
5277
5308
  return createOpenAICompatible({
5278
5309
  name: "cerebras",
@@ -5287,7 +5318,407 @@ function createDeepSpaceAI(env, provider, options = {}) {
5287
5318
  }
5288
5319
  }
5289
5320
  }
5321
+
5322
+ // src/server/utils/chat-context.ts
5323
+ import { generateText } from "ai";
5324
+ var DEFAULT_CONTEXT_CONFIG = {
5325
+ contextBudget: 24e4,
5326
+ toolResultCap: 3e4,
5327
+ keepRecentToolResults: 5,
5328
+ minKept: 10
5329
+ };
5330
+ function sizeOf(m) {
5331
+ return (m.content ?? "").length + (m.parts ? JSON.stringify(m.parts).length : 0);
5332
+ }
5333
+ function totalChars(messages) {
5334
+ return messages.reduce((acc, m) => acc + sizeOf(m), 0);
5335
+ }
5336
+ function truncateOldToolResults(messages, keepRecent) {
5337
+ const assistantIdxs = [];
5338
+ for (let i = 0; i < messages.length; i++) {
5339
+ if (messages[i].role === "assistant") assistantIdxs.push(i);
5340
+ }
5341
+ const protectedStart = assistantIdxs.length > keepRecent ? assistantIdxs[assistantIdxs.length - keepRecent] : 0;
5342
+ return messages.map((msg, idx) => {
5343
+ if (msg.role !== "assistant" || idx >= protectedStart) return msg;
5344
+ if (!Array.isArray(msg.parts) || msg.parts.length === 0) return msg;
5345
+ const newParts = msg.parts.map((p) => {
5346
+ if (!p || typeof p !== "object") return p;
5347
+ const anyP = p;
5348
+ if (anyP.type !== "tool-invocation") return p;
5349
+ const inv = anyP.toolInvocation;
5350
+ if (!inv || inv.state !== "result") return p;
5351
+ const result = inv.result;
5352
+ if (result && result.success === false) return p;
5353
+ return {
5354
+ ...anyP,
5355
+ toolInvocation: {
5356
+ ...inv,
5357
+ result: {
5358
+ _truncated: true,
5359
+ note: "Result from an earlier turn omitted to save context. Call this tool again if you need the data."
5360
+ }
5361
+ }
5362
+ };
5363
+ });
5364
+ return { ...msg, parts: newParts };
5365
+ });
5366
+ }
5367
+ function applySlidingWindow(messages, charCap, minKept) {
5368
+ let total = totalChars(messages);
5369
+ if (total <= charCap) return messages;
5370
+ const out = [...messages];
5371
+ while (out.length > minKept && total > charCap) {
5372
+ const idx = out.findIndex((m) => m.role !== "system");
5373
+ if (idx < 0) break;
5374
+ const dropped = out.splice(idx, 1)[0];
5375
+ total -= sizeOf(dropped);
5376
+ }
5377
+ return out;
5378
+ }
5379
+ function capToolResultSize(result, byteCap) {
5380
+ let serialized;
5381
+ try {
5382
+ serialized = JSON.stringify(result);
5383
+ } catch {
5384
+ return { success: false, error: "Tool result could not be serialized." };
5385
+ }
5386
+ if (typeof serialized !== "string") return result;
5387
+ if (serialized.length <= byteCap) return result;
5388
+ return {
5389
+ success: false,
5390
+ truncated: true,
5391
+ error: `Tool result exceeded ${byteCap} bytes (was ${serialized.length}). Retry with a narrower query (e.g. add a \`where\` filter, reduce \`limit\`, or call records.get for a single record).`,
5392
+ preview: serialized.slice(0, 2e3)
5393
+ };
5394
+ }
5395
+ function turnsToCoreMessages(turns) {
5396
+ const out = [];
5397
+ for (const t of turns) {
5398
+ if (t.role === "system") {
5399
+ out.push({ role: "system", content: t.content });
5400
+ continue;
5401
+ }
5402
+ if (t.role === "user") {
5403
+ out.push({ role: "user", content: t.content });
5404
+ continue;
5405
+ }
5406
+ if (!Array.isArray(t.parts) || t.parts.length === 0) {
5407
+ if (t.content) out.push({ role: "assistant", content: t.content });
5408
+ continue;
5409
+ }
5410
+ let pending = [];
5411
+ let emittedAny = false;
5412
+ const flushAssistant = () => {
5413
+ if (pending.length === 0) return;
5414
+ out.push({ role: "assistant", content: pending });
5415
+ pending = [];
5416
+ emittedAny = true;
5417
+ };
5418
+ for (const p of t.parts) {
5419
+ if (!p || typeof p !== "object") continue;
5420
+ const anyP = p;
5421
+ if (anyP.type === "text" && typeof anyP.text === "string" && anyP.text) {
5422
+ pending.push({ type: "text", text: anyP.text });
5423
+ continue;
5424
+ }
5425
+ if (anyP.type !== "tool-invocation") continue;
5426
+ const inv = anyP.toolInvocation;
5427
+ const toolCallId = typeof anyP.toolCallId === "string" ? anyP.toolCallId : void 0;
5428
+ const toolName = typeof inv?.toolName === "string" ? inv.toolName : void 0;
5429
+ if (!toolCallId || !toolName) continue;
5430
+ if (inv?.state !== "result") continue;
5431
+ pending.push({ type: "tool-call", toolCallId, toolName, input: inv?.args });
5432
+ flushAssistant();
5433
+ const tr = {
5434
+ type: "tool-result",
5435
+ toolCallId,
5436
+ toolName,
5437
+ output: { type: "json", value: inv.result }
5438
+ };
5439
+ out.push({ role: "tool", content: [tr] });
5440
+ }
5441
+ flushAssistant();
5442
+ if (!emittedAny && t.content) {
5443
+ out.push({ role: "assistant", content: t.content });
5444
+ }
5445
+ }
5446
+ return out;
5447
+ }
5448
+ function buildUiParts(responseMessages) {
5449
+ const toolResults = /* @__PURE__ */ new Map();
5450
+ for (const msg of responseMessages) {
5451
+ if (msg.role !== "tool" || !Array.isArray(msg.content)) continue;
5452
+ for (const c of msg.content) {
5453
+ if (c.type === "tool-result") {
5454
+ toolResults.set(c.toolCallId, unwrapToolOutput(c.output));
5455
+ }
5456
+ }
5457
+ }
5458
+ const parts = [];
5459
+ for (const msg of responseMessages) {
5460
+ if (msg.role !== "assistant") continue;
5461
+ if (typeof msg.content === "string") {
5462
+ if (msg.content) parts.push({ type: "text", text: msg.content });
5463
+ continue;
5464
+ }
5465
+ if (!Array.isArray(msg.content)) continue;
5466
+ for (const c of msg.content) {
5467
+ if (c.type === "text" && typeof c.text === "string" && c.text) {
5468
+ parts.push({ type: "text", text: c.text });
5469
+ } else if (c.type === "tool-call") {
5470
+ const result = toolResults.get(c.toolCallId);
5471
+ if (result === void 0) {
5472
+ continue;
5473
+ }
5474
+ parts.push({
5475
+ type: "tool-invocation",
5476
+ toolCallId: c.toolCallId,
5477
+ toolInvocation: {
5478
+ toolName: c.toolName,
5479
+ state: "result",
5480
+ args: c.input,
5481
+ result
5482
+ }
5483
+ });
5484
+ }
5485
+ }
5486
+ }
5487
+ return parts;
5488
+ }
5489
+ function unwrapToolOutput(output) {
5490
+ if (!output || typeof output !== "object") return output;
5491
+ const o = output;
5492
+ const tag = typeof o.type === "string" ? o.type : null;
5493
+ if (tag === "json" || tag === "text") {
5494
+ return "value" in o ? o.value : output;
5495
+ }
5496
+ if (tag === "error-text" || tag === "error-json") {
5497
+ return { success: false, error: "value" in o ? o.value : "Tool execution failed" };
5498
+ }
5499
+ return output;
5500
+ }
5501
+ function buildSummaryMessage(text, throughId) {
5502
+ return {
5503
+ id: `summary-${throughId}`,
5504
+ role: "system",
5505
+ content: `Earlier conversation summary:
5506
+ ${text}`
5507
+ };
5508
+ }
5509
+ async function prepareMessagesWithCompaction(messages, config, options) {
5510
+ const truncated = truncateOldToolResults(messages, config.keepRecentToolResults);
5511
+ let working = truncated;
5512
+ if (options.cachedSummary) {
5513
+ const idx = truncated.findIndex((m) => m.id === options.cachedSummary.throughId);
5514
+ if (idx >= 0) {
5515
+ working = [
5516
+ buildSummaryMessage(options.cachedSummary.text, options.cachedSummary.throughId),
5517
+ ...truncated.slice(idx + 1)
5518
+ ];
5519
+ }
5520
+ }
5521
+ if (totalChars(working) <= config.contextBudget) {
5522
+ return { messages: working };
5523
+ }
5524
+ const half = Math.max(1, Math.floor(working.length / 2));
5525
+ const older = working.slice(0, half);
5526
+ const newer = working.slice(half);
5527
+ let throughId;
5528
+ for (let i = older.length - 1; i >= 0; i--) {
5529
+ const id = older[i].id;
5530
+ if (id && !id.startsWith("summary-")) {
5531
+ throughId = id;
5532
+ break;
5533
+ }
5534
+ }
5535
+ if (throughId) {
5536
+ try {
5537
+ const text = await options.summarizer(older);
5538
+ return {
5539
+ messages: [buildSummaryMessage(text, throughId), ...newer],
5540
+ newSummary: { text, throughId }
5541
+ };
5542
+ } catch (err) {
5543
+ console.error("prepareMessagesWithCompaction: summarizer failed, falling back to sliding window", err);
5544
+ }
5545
+ } else {
5546
+ console.warn("prepareMessagesWithCompaction: messages lack ids; cannot anchor a summary, falling back to sliding window");
5547
+ }
5548
+ return {
5549
+ messages: applySlidingWindow(working, config.contextBudget, config.minKept)
5550
+ };
5551
+ }
5552
+ var SUMMARIZER_SYSTEM_PROMPT = `You are compressing a conversation between a user and an AI assistant into a
5553
+ concise memory summary. The summary will replace the original messages in the
5554
+ conversation history; the assistant will read it on subsequent turns to
5555
+ maintain continuity.
5556
+
5557
+ Preserve in the summary:
5558
+ - User preferences and constraints the user stated (coding style, tone,
5559
+ skill level, goals).
5560
+ - Decisions made and rejected alternatives ("we chose X over Y because Z").
5561
+ - Current task state (what's in progress, what's been completed).
5562
+ - Any facts the user might reasonably reference later.
5563
+
5564
+ If the messages below contain a prior summary, incorporate its content into
5565
+ your new summary \u2014 do not drop information from earlier summaries.
5566
+
5567
+ Keep the summary under 2000 tokens. Write as a factual note to future-you,
5568
+ not as a narrative. Use terse bullet points where possible.`;
5569
+ function formatTranscript(messages) {
5570
+ return messages.map((m) => {
5571
+ const label = m.role === "user" ? "User" : m.role === "assistant" ? "Assistant" : "System";
5572
+ const tools = Array.isArray(m.parts) ? m.parts.filter((p) => p?.type === "tool-invocation").map((p) => {
5573
+ const name = p.toolInvocation?.toolName;
5574
+ return ` [tool: ${name ?? "unknown"}]`;
5575
+ }).join("\n") : "";
5576
+ return `${label}: ${m.content}${tools ? "\n" + tools : ""}`;
5577
+ }).join("\n\n");
5578
+ }
5579
+ function makeDefaultSummarizer(env, options = {}) {
5580
+ return async (messages) => {
5581
+ const anthropic = createDeepSpaceAI(env, "anthropic", { authToken: options.authToken });
5582
+ const { text } = await generateText({
5583
+ // Stable alias — provider bug-fix snapshots roll forward without code change.
5584
+ model: anthropic("claude-haiku-4-5"),
5585
+ // 2500 gives the model room to finish a sentence after hitting the
5586
+ // "under 2000 tokens" soft limit in the prompt.
5587
+ maxOutputTokens: 2500,
5588
+ system: SUMMARIZER_SYSTEM_PROMPT,
5589
+ messages: [{ role: "user", content: formatTranscript(messages) }]
5590
+ });
5591
+ return text;
5592
+ };
5593
+ }
5594
+
5595
+ // src/server/utils/chat-history.ts
5596
+ async function executeTool2(stub, userId, tool, params) {
5597
+ const res = await stub.fetch(new Request("https://internal/api/tools/execute", {
5598
+ method: "POST",
5599
+ headers: {
5600
+ "Content-Type": "application/json",
5601
+ "X-User-Id": userId,
5602
+ "X-App-Action": "true"
5603
+ },
5604
+ body: JSON.stringify({ tool, params })
5605
+ }));
5606
+ const body = await res.json();
5607
+ if (!body.success) {
5608
+ throw new Error(`chat-history ${tool} failed: ${body.error ?? "unknown error"}`);
5609
+ }
5610
+ return body.data;
5611
+ }
5612
+ function toChatRow(env) {
5613
+ return {
5614
+ id: env.recordId,
5615
+ userId: env.data.userId,
5616
+ title: env.data.title ?? "",
5617
+ model: env.data.model,
5618
+ compactedSummary: env.data.compactedSummary,
5619
+ compactedThroughId: env.data.compactedThroughId,
5620
+ createdAt: env.createdAt,
5621
+ updatedAt: env.updatedAt
5622
+ };
5623
+ }
5624
+ function toMessageRow(env) {
5625
+ return {
5626
+ id: env.recordId,
5627
+ chatId: env.data.chatId,
5628
+ userId: env.data.userId,
5629
+ role: env.data.role,
5630
+ content: env.data.content ?? "",
5631
+ parts: env.data.parts,
5632
+ createdAt: env.createdAt
5633
+ };
5634
+ }
5635
+ async function getChat(stub, chatId, userId) {
5636
+ try {
5637
+ const result = await executeTool2(stub, userId, "records.get", {
5638
+ collection: "ai-chats",
5639
+ recordId: chatId
5640
+ });
5641
+ return result.record ? toChatRow(result.record) : null;
5642
+ } catch (err) {
5643
+ if (err instanceof Error && err.message.includes("Record not found")) return null;
5644
+ throw err;
5645
+ }
5646
+ }
5647
+ async function createChat(stub, userId, opts = {}) {
5648
+ const data = { userId };
5649
+ if (opts.title !== void 0) data.title = opts.title;
5650
+ if (opts.model !== void 0) data.model = opts.model;
5651
+ const result = await executeTool2(stub, userId, "records.create", {
5652
+ collection: "ai-chats",
5653
+ data
5654
+ });
5655
+ return toChatRow(result.record);
5656
+ }
5657
+ async function updateChat(stub, chatId, userId, patch) {
5658
+ await executeTool2(stub, userId, "records.update", {
5659
+ collection: "ai-chats",
5660
+ recordId: chatId,
5661
+ data: patch
5662
+ });
5663
+ }
5664
+ async function deleteChatCascade(stub, chatId, userId) {
5665
+ const list = await executeTool2(stub, userId, "records.query", {
5666
+ collection: "ai-messages",
5667
+ where: { chatId }
5668
+ });
5669
+ const errors = [];
5670
+ for (const env of list.records) {
5671
+ try {
5672
+ await executeTool2(stub, userId, "records.delete", {
5673
+ collection: "ai-messages",
5674
+ recordId: env.recordId
5675
+ });
5676
+ } catch (err) {
5677
+ errors.push(err);
5678
+ }
5679
+ }
5680
+ try {
5681
+ await executeTool2(stub, userId, "records.delete", {
5682
+ collection: "ai-chats",
5683
+ recordId: chatId
5684
+ });
5685
+ } catch (err) {
5686
+ errors.push(err);
5687
+ }
5688
+ if (errors.length > 0) {
5689
+ const first = errors[0];
5690
+ throw new Error(
5691
+ `deleteChatCascade: ${errors.length} delete(s) failed; first: ${first instanceof Error ? first.message : String(first)}`,
5692
+ { cause: errors }
5693
+ );
5694
+ }
5695
+ }
5696
+ async function loadMessages(stub, chatId, userId) {
5697
+ const result = await executeTool2(stub, userId, "records.query", {
5698
+ collection: "ai-messages",
5699
+ where: { chatId, userId },
5700
+ orderBy: "createdAt",
5701
+ orderDir: "asc"
5702
+ });
5703
+ return result.records.map(toMessageRow);
5704
+ }
5705
+ async function appendMessage(stub, msg) {
5706
+ const data = {
5707
+ chatId: msg.chatId,
5708
+ userId: msg.userId,
5709
+ role: msg.role,
5710
+ content: msg.content
5711
+ };
5712
+ if (msg.parts !== void 0) data.parts = msg.parts;
5713
+ await executeTool2(stub, msg.userId, "records.create", {
5714
+ collection: "ai-messages",
5715
+ recordId: msg.id,
5716
+ data
5717
+ });
5718
+ }
5290
5719
  export {
5720
+ AI_CHATS_SCHEMA,
5721
+ AI_MESSAGES_SCHEMA,
5291
5722
  Awareness,
5292
5723
  BASE_USERS_SCHEMA,
5293
5724
  BUILT_IN_TOOLS,
@@ -5298,6 +5729,7 @@ export {
5298
5729
  CONVERSATION_SCHEMAS,
5299
5730
  CanvasRoom,
5300
5731
  CronRoom,
5732
+ DEFAULT_CONTEXT_CONFIG,
5301
5733
  DEFAULT_DO_MANIFEST,
5302
5734
  DEFAULT_MAX_SKEW_MS,
5303
5735
  DIRECTORY_SCHEMAS,
@@ -5330,20 +5762,25 @@ export {
5330
5762
  YjsRoom,
5331
5763
  analyzePermissions,
5332
5764
  apiWorkerFetch,
5765
+ appendMessage,
5766
+ applySlidingWindow,
5333
5767
  authWorkerFetch,
5334
5768
  buildCronContext,
5335
5769
  buildInternalPayload,
5336
5770
  buildTableSelect,
5771
+ buildUiParts,
5337
5772
  canCreate,
5338
5773
  canDelete,
5339
5774
  canRead,
5340
5775
  canUpdate,
5776
+ capToolResultSize,
5341
5777
  checkFieldPermissions,
5342
5778
  clientBuild,
5343
5779
  coerceValue,
5344
5780
  collectionTableName,
5345
5781
  columnId,
5346
5782
  computeHmacHex,
5783
+ createChat,
5347
5784
  createDecoder,
5348
5785
  createDeepSpaceAI,
5349
5786
  createDeepSpaceAuth,
@@ -5351,12 +5788,14 @@ export {
5351
5788
  createScopedR2Handler,
5352
5789
  dataToColumnValues,
5353
5790
  decodeJwtPayload,
5791
+ deleteChatCascade,
5354
5792
  dispatch,
5355
5793
  encode,
5356
5794
  encodeAwarenessMessage,
5357
5795
  encodeSyncStep1,
5358
5796
  encodeSyncStep2,
5359
5797
  encodeUpdate,
5798
+ getChat,
5360
5799
  getGlobalDOSchemas,
5361
5800
  getGlobalDOType,
5362
5801
  getMessageType,
@@ -5365,8 +5804,11 @@ export {
5365
5804
  handleSyncMessage,
5366
5805
  hasContent,
5367
5806
  isOwner,
5807
+ loadMessages,
5808
+ makeDefaultSummarizer,
5368
5809
  noopPermissionContext,
5369
5810
  platformWorkerFetch,
5811
+ prepareMessagesWithCompaction,
5370
5812
  readVarUint,
5371
5813
  readVarUint8Array,
5372
5814
  resolveColumn,
@@ -5375,6 +5817,11 @@ export {
5375
5817
  signInternalPayload,
5376
5818
  timingSafeEqualHex,
5377
5819
  toUint8Array,
5820
+ totalChars,
5821
+ truncateOldToolResults,
5822
+ turnsToCoreMessages,
5823
+ unwrapToolOutput,
5824
+ updateChat,
5378
5825
  verifyInternalSignature,
5379
5826
  verifyJwt,
5380
5827
  workspaceAccountsSchema,