@supyagent/sdk 0.1.8 → 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/dist/prisma.cjs CHANGED
@@ -35,16 +35,23 @@ function createPrismaAdapter(prisma) {
35
35
  create: { id: chatId, title },
36
36
  update: { title }
37
37
  });
38
- await prisma.message.createMany({
39
- data: messages.map((msg) => ({
40
- id: msg.id,
41
- chatId,
42
- role: msg.role,
43
- parts: JSON.stringify(msg.parts),
44
- metadata: msg.metadata ? JSON.stringify(msg.metadata) : null
45
- })),
46
- skipDuplicates: true
38
+ const existing = await prisma.message.findMany({
39
+ where: { chatId },
40
+ select: { id: true }
47
41
  });
42
+ const existingIds = new Set(existing.map((m) => m.id));
43
+ const newMessages = messages.filter((msg) => !existingIds.has(msg.id));
44
+ if (newMessages.length > 0) {
45
+ await prisma.message.createMany({
46
+ data: newMessages.map((msg) => ({
47
+ id: msg.id,
48
+ chatId,
49
+ role: msg.role,
50
+ parts: JSON.stringify(msg.parts),
51
+ metadata: msg.metadata ? JSON.stringify(msg.metadata) : null
52
+ }))
53
+ });
54
+ }
48
55
  },
49
56
  async loadChat(chatId) {
50
57
  const messages = await prisma.message.findMany({
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/prisma.ts","../src/persistence/prisma-adapter.ts"],"sourcesContent":["export { createPrismaAdapter } from \"./persistence/prisma-adapter.js\";\nexport type { ChatAdapter, ChatSummary, UIMessageLike } from \"./persistence/types.js\";\n","import type { ChatAdapter, ChatSummary, UIMessageLike } from \"./types.js\";\n\n/**\n * Accepts any PrismaClient instance.\n * We use `any` here because Prisma generates unique client types per schema,\n * and a structural interface can't satisfy Prisma's branded enum types\n * (e.g. SortOrder). The implementation only calls standard Prisma methods.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PrismaLike = any;\n\n/**\n * Create a ChatAdapter backed by Prisma.\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@supyagent/sdk/prisma';\n * import { prisma } from '@/lib/prisma';\n *\n * const adapter = createPrismaAdapter(prisma);\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaLike): ChatAdapter {\n return {\n async saveChat(chatId: string, messages: UIMessageLike[]) {\n // Extract title from first user message\n const firstUserMsg = messages.find((m) => m.role === \"user\");\n const title = extractTitle(firstUserMsg);\n\n // Upsert the chat record\n await prisma.chat.upsert({\n where: { id: chatId },\n create: { id: chatId, title },\n update: { title },\n });\n\n // Insert only messages not already persisted (idempotent)\n await prisma.message.createMany({\n data: messages.map((msg) => ({\n id: msg.id,\n chatId,\n role: msg.role,\n parts: JSON.stringify(msg.parts),\n metadata: msg.metadata ? JSON.stringify(msg.metadata) : null,\n })),\n skipDuplicates: true,\n });\n },\n\n async loadChat(chatId: string) {\n const messages = await prisma.message.findMany({\n where: { chatId },\n orderBy: { createdAt: \"asc\" },\n });\n\n return messages.map((msg: { id: string; role: string; parts: string; metadata: string | null }) => ({\n id: msg.id,\n role: msg.role,\n parts: JSON.parse(msg.parts),\n metadata: msg.metadata ? JSON.parse(msg.metadata) : undefined,\n }));\n },\n\n async listChats() {\n return prisma.chat.findMany({\n orderBy: { updatedAt: \"desc\" },\n select: {\n id: true,\n title: true,\n createdAt: true,\n updatedAt: true,\n },\n });\n },\n\n async deleteChat(chatId: string) {\n await prisma.chat.delete({ where: { id: chatId } });\n },\n };\n}\n\nfunction extractTitle(message?: UIMessageLike): string {\n if (!message) return \"New Chat\";\n const textPart = message.parts.find((p) => p.type === \"text\");\n if (textPart && typeof textPart.text === \"string\") {\n return textPart.text.slice(0, 100);\n }\n return \"New Chat\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBO,SAAS,oBAAoB,QAAiC;AACnE,SAAO;AAAA,IACL,MAAM,SAAS,QAAgB,UAA2B;AAExD,YAAM,eAAe,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,YAAM,QAAQ,aAAa,YAAY;AAGvC,YAAM,OAAO,KAAK,OAAO;AAAA,QACvB,OAAO,EAAE,IAAI,OAAO;AAAA,QACpB,QAAQ,EAAE,IAAI,QAAQ,MAAM;AAAA,QAC5B,QAAQ,EAAE,MAAM;AAAA,MAClB,CAAC;AAGD,YAAM,OAAO,QAAQ,WAAW;AAAA,QAC9B,MAAM,SAAS,IAAI,CAAC,SAAS;AAAA,UAC3B,IAAI,IAAI;AAAA,UACR;AAAA,UACA,MAAM,IAAI;AAAA,UACV,OAAO,KAAK,UAAU,IAAI,KAAK;AAAA,UAC/B,UAAU,IAAI,WAAW,KAAK,UAAU,IAAI,QAAQ,IAAI;AAAA,QAC1D,EAAE;AAAA,QACF,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,SAAS,QAAgB;AAC7B,YAAM,WAAW,MAAM,OAAO,QAAQ,SAAS;AAAA,QAC7C,OAAO,EAAE,OAAO;AAAA,QAChB,SAAS,EAAE,WAAW,MAAM;AAAA,MAC9B,CAAC;AAED,aAAO,SAAS,IAAI,CAAC,SAA+E;AAAA,QAClG,IAAI,IAAI;AAAA,QACR,MAAM,IAAI;AAAA,QACV,OAAO,KAAK,MAAM,IAAI,KAAK;AAAA,QAC3B,UAAU,IAAI,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI;AAAA,MACtD,EAAE;AAAA,IACJ;AAAA,IAEA,MAAM,YAAY;AAChB,aAAO,OAAO,KAAK,SAAS;AAAA,QAC1B,SAAS,EAAE,WAAW,OAAO;AAAA,QAC7B,QAAQ;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,WAAW,QAAgB;AAC/B,YAAM,OAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,aAAa,SAAiC;AACrD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC5D,MAAI,YAAY,OAAO,SAAS,SAAS,UAAU;AACjD,WAAO,SAAS,KAAK,MAAM,GAAG,GAAG;AAAA,EACnC;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/prisma.ts","../src/persistence/prisma-adapter.ts"],"sourcesContent":["export { createPrismaAdapter } from \"./persistence/prisma-adapter.js\";\nexport type { ChatAdapter, ChatSummary, UIMessageLike } from \"./persistence/types.js\";\n","import type { ChatAdapter, ChatSummary, UIMessageLike } from \"./types.js\";\n\n/**\n * Accepts any PrismaClient instance.\n * We use `any` here because Prisma generates unique client types per schema,\n * and a structural interface can't satisfy Prisma's branded enum types\n * (e.g. SortOrder). The implementation only calls standard Prisma methods.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PrismaLike = any;\n\n/**\n * Create a ChatAdapter backed by Prisma.\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@supyagent/sdk/prisma';\n * import { prisma } from '@/lib/prisma';\n *\n * const adapter = createPrismaAdapter(prisma);\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaLike): ChatAdapter {\n return {\n async saveChat(chatId: string, messages: UIMessageLike[]) {\n // Extract title from first user message\n const firstUserMsg = messages.find((m) => m.role === \"user\");\n const title = extractTitle(firstUserMsg);\n\n // Upsert the chat record\n await prisma.chat.upsert({\n where: { id: chatId },\n create: { id: chatId, title },\n update: { title },\n });\n\n // Insert only messages not already persisted (idempotent)\n const existing = await prisma.message.findMany({\n where: { chatId },\n select: { id: true },\n });\n const existingIds = new Set(existing.map((m: { id: string }) => m.id));\n const newMessages = messages.filter((msg) => !existingIds.has(msg.id));\n\n if (newMessages.length > 0) {\n await prisma.message.createMany({\n data: newMessages.map((msg) => ({\n id: msg.id,\n chatId,\n role: msg.role,\n parts: JSON.stringify(msg.parts),\n metadata: msg.metadata ? JSON.stringify(msg.metadata) : null,\n })),\n });\n }\n },\n\n async loadChat(chatId: string) {\n const messages = await prisma.message.findMany({\n where: { chatId },\n orderBy: { createdAt: \"asc\" },\n });\n\n return messages.map((msg: { id: string; role: string; parts: string; metadata: string | null }) => ({\n id: msg.id,\n role: msg.role,\n parts: JSON.parse(msg.parts),\n metadata: msg.metadata ? JSON.parse(msg.metadata) : undefined,\n }));\n },\n\n async listChats() {\n return prisma.chat.findMany({\n orderBy: { updatedAt: \"desc\" },\n select: {\n id: true,\n title: true,\n createdAt: true,\n updatedAt: true,\n },\n });\n },\n\n async deleteChat(chatId: string) {\n await prisma.chat.delete({ where: { id: chatId } });\n },\n };\n}\n\nfunction extractTitle(message?: UIMessageLike): string {\n if (!message) return \"New Chat\";\n const textPart = message.parts.find((p) => p.type === \"text\");\n if (textPart && typeof textPart.text === \"string\") {\n return textPart.text.slice(0, 100);\n }\n return \"New Chat\";\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACsBO,SAAS,oBAAoB,QAAiC;AACnE,SAAO;AAAA,IACL,MAAM,SAAS,QAAgB,UAA2B;AAExD,YAAM,eAAe,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,YAAM,QAAQ,aAAa,YAAY;AAGvC,YAAM,OAAO,KAAK,OAAO;AAAA,QACvB,OAAO,EAAE,IAAI,OAAO;AAAA,QACpB,QAAQ,EAAE,IAAI,QAAQ,MAAM;AAAA,QAC5B,QAAQ,EAAE,MAAM;AAAA,MAClB,CAAC;AAGD,YAAM,WAAW,MAAM,OAAO,QAAQ,SAAS;AAAA,QAC7C,OAAO,EAAE,OAAO;AAAA,QAChB,QAAQ,EAAE,IAAI,KAAK;AAAA,MACrB,CAAC;AACD,YAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,MAAsB,EAAE,EAAE,CAAC;AACrE,YAAM,cAAc,SAAS,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;AAErE,UAAI,YAAY,SAAS,GAAG;AAC1B,cAAM,OAAO,QAAQ,WAAW;AAAA,UAC9B,MAAM,YAAY,IAAI,CAAC,SAAS;AAAA,YAC9B,IAAI,IAAI;AAAA,YACR;AAAA,YACA,MAAM,IAAI;AAAA,YACV,OAAO,KAAK,UAAU,IAAI,KAAK;AAAA,YAC/B,UAAU,IAAI,WAAW,KAAK,UAAU,IAAI,QAAQ,IAAI;AAAA,UAC1D,EAAE;AAAA,QACJ,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,QAAgB;AAC7B,YAAM,WAAW,MAAM,OAAO,QAAQ,SAAS;AAAA,QAC7C,OAAO,EAAE,OAAO;AAAA,QAChB,SAAS,EAAE,WAAW,MAAM;AAAA,MAC9B,CAAC;AAED,aAAO,SAAS,IAAI,CAAC,SAA+E;AAAA,QAClG,IAAI,IAAI;AAAA,QACR,MAAM,IAAI;AAAA,QACV,OAAO,KAAK,MAAM,IAAI,KAAK;AAAA,QAC3B,UAAU,IAAI,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI;AAAA,MACtD,EAAE;AAAA,IACJ;AAAA,IAEA,MAAM,YAAY;AAChB,aAAO,OAAO,KAAK,SAAS;AAAA,QAC1B,SAAS,EAAE,WAAW,OAAO;AAAA,QAC7B,QAAQ;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,WAAW,QAAgB;AAC/B,YAAM,OAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,aAAa,SAAiC;AACrD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC5D,MAAI,YAAY,OAAO,SAAS,SAAS,UAAU;AACjD,WAAO,SAAS,KAAK,MAAM,GAAG,GAAG;AAAA,EACnC;AACA,SAAO;AACT;","names":[]}
package/dist/prisma.js CHANGED
@@ -9,16 +9,23 @@ function createPrismaAdapter(prisma) {
9
9
  create: { id: chatId, title },
10
10
  update: { title }
11
11
  });
12
- await prisma.message.createMany({
13
- data: messages.map((msg) => ({
14
- id: msg.id,
15
- chatId,
16
- role: msg.role,
17
- parts: JSON.stringify(msg.parts),
18
- metadata: msg.metadata ? JSON.stringify(msg.metadata) : null
19
- })),
20
- skipDuplicates: true
12
+ const existing = await prisma.message.findMany({
13
+ where: { chatId },
14
+ select: { id: true }
21
15
  });
16
+ const existingIds = new Set(existing.map((m) => m.id));
17
+ const newMessages = messages.filter((msg) => !existingIds.has(msg.id));
18
+ if (newMessages.length > 0) {
19
+ await prisma.message.createMany({
20
+ data: newMessages.map((msg) => ({
21
+ id: msg.id,
22
+ chatId,
23
+ role: msg.role,
24
+ parts: JSON.stringify(msg.parts),
25
+ metadata: msg.metadata ? JSON.stringify(msg.metadata) : null
26
+ }))
27
+ });
28
+ }
22
29
  },
23
30
  async loadChat(chatId) {
24
31
  const messages = await prisma.message.findMany({
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/persistence/prisma-adapter.ts"],"sourcesContent":["import type { ChatAdapter, ChatSummary, UIMessageLike } from \"./types.js\";\n\n/**\n * Accepts any PrismaClient instance.\n * We use `any` here because Prisma generates unique client types per schema,\n * and a structural interface can't satisfy Prisma's branded enum types\n * (e.g. SortOrder). The implementation only calls standard Prisma methods.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PrismaLike = any;\n\n/**\n * Create a ChatAdapter backed by Prisma.\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@supyagent/sdk/prisma';\n * import { prisma } from '@/lib/prisma';\n *\n * const adapter = createPrismaAdapter(prisma);\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaLike): ChatAdapter {\n return {\n async saveChat(chatId: string, messages: UIMessageLike[]) {\n // Extract title from first user message\n const firstUserMsg = messages.find((m) => m.role === \"user\");\n const title = extractTitle(firstUserMsg);\n\n // Upsert the chat record\n await prisma.chat.upsert({\n where: { id: chatId },\n create: { id: chatId, title },\n update: { title },\n });\n\n // Insert only messages not already persisted (idempotent)\n await prisma.message.createMany({\n data: messages.map((msg) => ({\n id: msg.id,\n chatId,\n role: msg.role,\n parts: JSON.stringify(msg.parts),\n metadata: msg.metadata ? JSON.stringify(msg.metadata) : null,\n })),\n skipDuplicates: true,\n });\n },\n\n async loadChat(chatId: string) {\n const messages = await prisma.message.findMany({\n where: { chatId },\n orderBy: { createdAt: \"asc\" },\n });\n\n return messages.map((msg: { id: string; role: string; parts: string; metadata: string | null }) => ({\n id: msg.id,\n role: msg.role,\n parts: JSON.parse(msg.parts),\n metadata: msg.metadata ? JSON.parse(msg.metadata) : undefined,\n }));\n },\n\n async listChats() {\n return prisma.chat.findMany({\n orderBy: { updatedAt: \"desc\" },\n select: {\n id: true,\n title: true,\n createdAt: true,\n updatedAt: true,\n },\n });\n },\n\n async deleteChat(chatId: string) {\n await prisma.chat.delete({ where: { id: chatId } });\n },\n };\n}\n\nfunction extractTitle(message?: UIMessageLike): string {\n if (!message) return \"New Chat\";\n const textPart = message.parts.find((p) => p.type === \"text\");\n if (textPart && typeof textPart.text === \"string\") {\n return textPart.text.slice(0, 100);\n }\n return \"New Chat\";\n}\n"],"mappings":";AAsBO,SAAS,oBAAoB,QAAiC;AACnE,SAAO;AAAA,IACL,MAAM,SAAS,QAAgB,UAA2B;AAExD,YAAM,eAAe,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,YAAM,QAAQ,aAAa,YAAY;AAGvC,YAAM,OAAO,KAAK,OAAO;AAAA,QACvB,OAAO,EAAE,IAAI,OAAO;AAAA,QACpB,QAAQ,EAAE,IAAI,QAAQ,MAAM;AAAA,QAC5B,QAAQ,EAAE,MAAM;AAAA,MAClB,CAAC;AAGD,YAAM,OAAO,QAAQ,WAAW;AAAA,QAC9B,MAAM,SAAS,IAAI,CAAC,SAAS;AAAA,UAC3B,IAAI,IAAI;AAAA,UACR;AAAA,UACA,MAAM,IAAI;AAAA,UACV,OAAO,KAAK,UAAU,IAAI,KAAK;AAAA,UAC/B,UAAU,IAAI,WAAW,KAAK,UAAU,IAAI,QAAQ,IAAI;AAAA,QAC1D,EAAE;AAAA,QACF,gBAAgB;AAAA,MAClB,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,SAAS,QAAgB;AAC7B,YAAM,WAAW,MAAM,OAAO,QAAQ,SAAS;AAAA,QAC7C,OAAO,EAAE,OAAO;AAAA,QAChB,SAAS,EAAE,WAAW,MAAM;AAAA,MAC9B,CAAC;AAED,aAAO,SAAS,IAAI,CAAC,SAA+E;AAAA,QAClG,IAAI,IAAI;AAAA,QACR,MAAM,IAAI;AAAA,QACV,OAAO,KAAK,MAAM,IAAI,KAAK;AAAA,QAC3B,UAAU,IAAI,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI;AAAA,MACtD,EAAE;AAAA,IACJ;AAAA,IAEA,MAAM,YAAY;AAChB,aAAO,OAAO,KAAK,SAAS;AAAA,QAC1B,SAAS,EAAE,WAAW,OAAO;AAAA,QAC7B,QAAQ;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,WAAW,QAAgB;AAC/B,YAAM,OAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,aAAa,SAAiC;AACrD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC5D,MAAI,YAAY,OAAO,SAAS,SAAS,UAAU;AACjD,WAAO,SAAS,KAAK,MAAM,GAAG,GAAG;AAAA,EACnC;AACA,SAAO;AACT;","names":[]}
1
+ {"version":3,"sources":["../src/persistence/prisma-adapter.ts"],"sourcesContent":["import type { ChatAdapter, ChatSummary, UIMessageLike } from \"./types.js\";\n\n/**\n * Accepts any PrismaClient instance.\n * We use `any` here because Prisma generates unique client types per schema,\n * and a structural interface can't satisfy Prisma's branded enum types\n * (e.g. SortOrder). The implementation only calls standard Prisma methods.\n */\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\ntype PrismaLike = any;\n\n/**\n * Create a ChatAdapter backed by Prisma.\n *\n * @example\n * ```ts\n * import { createPrismaAdapter } from '@supyagent/sdk/prisma';\n * import { prisma } from '@/lib/prisma';\n *\n * const adapter = createPrismaAdapter(prisma);\n * ```\n */\nexport function createPrismaAdapter(prisma: PrismaLike): ChatAdapter {\n return {\n async saveChat(chatId: string, messages: UIMessageLike[]) {\n // Extract title from first user message\n const firstUserMsg = messages.find((m) => m.role === \"user\");\n const title = extractTitle(firstUserMsg);\n\n // Upsert the chat record\n await prisma.chat.upsert({\n where: { id: chatId },\n create: { id: chatId, title },\n update: { title },\n });\n\n // Insert only messages not already persisted (idempotent)\n const existing = await prisma.message.findMany({\n where: { chatId },\n select: { id: true },\n });\n const existingIds = new Set(existing.map((m: { id: string }) => m.id));\n const newMessages = messages.filter((msg) => !existingIds.has(msg.id));\n\n if (newMessages.length > 0) {\n await prisma.message.createMany({\n data: newMessages.map((msg) => ({\n id: msg.id,\n chatId,\n role: msg.role,\n parts: JSON.stringify(msg.parts),\n metadata: msg.metadata ? JSON.stringify(msg.metadata) : null,\n })),\n });\n }\n },\n\n async loadChat(chatId: string) {\n const messages = await prisma.message.findMany({\n where: { chatId },\n orderBy: { createdAt: \"asc\" },\n });\n\n return messages.map((msg: { id: string; role: string; parts: string; metadata: string | null }) => ({\n id: msg.id,\n role: msg.role,\n parts: JSON.parse(msg.parts),\n metadata: msg.metadata ? JSON.parse(msg.metadata) : undefined,\n }));\n },\n\n async listChats() {\n return prisma.chat.findMany({\n orderBy: { updatedAt: \"desc\" },\n select: {\n id: true,\n title: true,\n createdAt: true,\n updatedAt: true,\n },\n });\n },\n\n async deleteChat(chatId: string) {\n await prisma.chat.delete({ where: { id: chatId } });\n },\n };\n}\n\nfunction extractTitle(message?: UIMessageLike): string {\n if (!message) return \"New Chat\";\n const textPart = message.parts.find((p) => p.type === \"text\");\n if (textPart && typeof textPart.text === \"string\") {\n return textPart.text.slice(0, 100);\n }\n return \"New Chat\";\n}\n"],"mappings":";AAsBO,SAAS,oBAAoB,QAAiC;AACnE,SAAO;AAAA,IACL,MAAM,SAAS,QAAgB,UAA2B;AAExD,YAAM,eAAe,SAAS,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC3D,YAAM,QAAQ,aAAa,YAAY;AAGvC,YAAM,OAAO,KAAK,OAAO;AAAA,QACvB,OAAO,EAAE,IAAI,OAAO;AAAA,QACpB,QAAQ,EAAE,IAAI,QAAQ,MAAM;AAAA,QAC5B,QAAQ,EAAE,MAAM;AAAA,MAClB,CAAC;AAGD,YAAM,WAAW,MAAM,OAAO,QAAQ,SAAS;AAAA,QAC7C,OAAO,EAAE,OAAO;AAAA,QAChB,QAAQ,EAAE,IAAI,KAAK;AAAA,MACrB,CAAC;AACD,YAAM,cAAc,IAAI,IAAI,SAAS,IAAI,CAAC,MAAsB,EAAE,EAAE,CAAC;AACrE,YAAM,cAAc,SAAS,OAAO,CAAC,QAAQ,CAAC,YAAY,IAAI,IAAI,EAAE,CAAC;AAErE,UAAI,YAAY,SAAS,GAAG;AAC1B,cAAM,OAAO,QAAQ,WAAW;AAAA,UAC9B,MAAM,YAAY,IAAI,CAAC,SAAS;AAAA,YAC9B,IAAI,IAAI;AAAA,YACR;AAAA,YACA,MAAM,IAAI;AAAA,YACV,OAAO,KAAK,UAAU,IAAI,KAAK;AAAA,YAC/B,UAAU,IAAI,WAAW,KAAK,UAAU,IAAI,QAAQ,IAAI;AAAA,UAC1D,EAAE;AAAA,QACJ,CAAC;AAAA,MACH;AAAA,IACF;AAAA,IAEA,MAAM,SAAS,QAAgB;AAC7B,YAAM,WAAW,MAAM,OAAO,QAAQ,SAAS;AAAA,QAC7C,OAAO,EAAE,OAAO;AAAA,QAChB,SAAS,EAAE,WAAW,MAAM;AAAA,MAC9B,CAAC;AAED,aAAO,SAAS,IAAI,CAAC,SAA+E;AAAA,QAClG,IAAI,IAAI;AAAA,QACR,MAAM,IAAI;AAAA,QACV,OAAO,KAAK,MAAM,IAAI,KAAK;AAAA,QAC3B,UAAU,IAAI,WAAW,KAAK,MAAM,IAAI,QAAQ,IAAI;AAAA,MACtD,EAAE;AAAA,IACJ;AAAA,IAEA,MAAM,YAAY;AAChB,aAAO,OAAO,KAAK,SAAS;AAAA,QAC1B,SAAS,EAAE,WAAW,OAAO;AAAA,QAC7B,QAAQ;AAAA,UACN,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,WAAW;AAAA,UACX,WAAW;AAAA,QACb;AAAA,MACF,CAAC;AAAA,IACH;AAAA,IAEA,MAAM,WAAW,QAAgB;AAC/B,YAAM,OAAO,KAAK,OAAO,EAAE,OAAO,EAAE,IAAI,OAAO,EAAE,CAAC;AAAA,IACpD;AAAA,EACF;AACF;AAEA,SAAS,aAAa,SAAiC;AACrD,MAAI,CAAC,QAAS,QAAO;AACrB,QAAM,WAAW,QAAQ,MAAM,KAAK,CAAC,MAAM,EAAE,SAAS,MAAM;AAC5D,MAAI,YAAY,OAAO,SAAS,SAAS,UAAU;AACjD,WAAO,SAAS,KAAK,MAAM,GAAG,GAAG;AAAA,EACnC;AACA,SAAO;AACT;","names":[]}
package/dist/react.cjs CHANGED
@@ -814,8 +814,21 @@ function formatRecipients(to) {
814
814
  if (Array.isArray(to)) return to.join(", ");
815
815
  return to;
816
816
  }
817
+ var HIDDEN_LABELS = /* @__PURE__ */ new Set(["INBOX", "UNREAD", "SENT", "DRAFT", "SPAM", "TRASH", "STARRED", "IMPORTANT"]);
818
+ function humanizeLabel(label) {
819
+ if (label.startsWith("CATEGORY_")) return label.slice(9).charAt(0) + label.slice(10).toLowerCase();
820
+ return label;
821
+ }
822
+ function resolveLabels(email) {
823
+ if (email.labels && email.labels.length > 0) return email.labels;
824
+ if (email.labelIds && email.labelIds.length > 0) {
825
+ return email.labelIds.filter((id) => !HIDDEN_LABELS.has(id)).map(humanizeLabel);
826
+ }
827
+ return [];
828
+ }
817
829
  function EmailCard({ email }) {
818
830
  const recipients = formatRecipients(email.to);
831
+ const labels = resolveLabels(email);
819
832
  return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "rounded-lg border border-border bg-card p-3 space-y-2", children: [
820
833
  /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)("div", { className: "flex items-start gap-2", children: [
821
834
  /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(import_lucide_react4.Mail, { className: "h-4 w-4 text-muted-foreground mt-0.5 shrink-0" }),
@@ -832,7 +845,7 @@ function EmailCard({ email }) {
832
845
  email.date && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "text-xs text-muted-foreground", children: formatRelativeDate(email.date) })
833
846
  ] })
834
847
  ] }),
835
- email.labels && email.labels.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center gap-1.5 flex-wrap", children: email.labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
848
+ labels.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { className: "flex items-center gap-1.5 flex-wrap", children: labels.map((label) => /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
836
849
  "span",
837
850
  {
838
851
  className: "inline-flex items-center gap-1 rounded-full bg-muted px-2 py-0.5 text-xs text-muted-foreground",
@@ -1003,11 +1016,12 @@ function MessageBubble({ message }) {
1003
1016
  ] });
1004
1017
  }
1005
1018
  function ChannelCard({ channel }) {
1019
+ const members = channel.num_members ?? channel.memberCount;
1006
1020
  return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { className: "flex items-center gap-2 rounded-lg border border-border bg-card p-3", children: [
1007
1021
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(import_lucide_react6.Hash, { className: "h-4 w-4 text-muted-foreground shrink-0" }),
1008
1022
  /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "text-sm text-foreground flex-1", children: channel.name || channel.id }),
1009
- channel.num_members !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
1010
- channel.num_members,
1023
+ members !== void 0 && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { className: "text-xs text-muted-foreground", children: [
1024
+ members,
1011
1025
  " members"
1012
1026
  ] })
1013
1027
  ] });
@@ -1380,7 +1394,9 @@ var import_lucide_react13 = require("lucide-react");
1380
1394
  var import_jsx_runtime13 = require("react/jsx-runtime");
1381
1395
  function isHubspotContact(data) {
1382
1396
  if (typeof data !== "object" || data === null) return false;
1383
- const props = data.properties;
1397
+ const d = data;
1398
+ if ("firstName" in d || "lastName" in d || d.email && d.id) return true;
1399
+ const props = d.properties;
1384
1400
  return props && ("firstname" in props || "lastname" in props || "email" in props);
1385
1401
  }
1386
1402
  function isHubspotCompany(data) {
@@ -1390,23 +1406,28 @@ function isHubspotCompany(data) {
1390
1406
  }
1391
1407
  function ContactCard({ contact }) {
1392
1408
  const p = contact.properties || {};
1393
- const name = [p.firstname, p.lastname].filter(Boolean).join(" ") || "Unknown contact";
1409
+ const first = contact.firstName || p.firstname;
1410
+ const last = contact.lastName || p.lastname;
1411
+ const email = contact.email || p.email;
1412
+ const phone = contact.phone || p.phone;
1413
+ const company = contact.company || p.company;
1414
+ const name = [first, last].filter(Boolean).join(" ") || "Unknown contact";
1394
1415
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "rounded-lg border border-border bg-card p-3 space-y-1.5", children: [
1395
1416
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex items-start gap-2", children: [
1396
1417
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react13.Users, { className: "h-4 w-4 text-muted-foreground mt-0.5 shrink-0" }),
1397
1418
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "min-w-0 flex-1", children: [
1398
1419
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-sm font-medium text-foreground", children: name }),
1399
- p.company && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-xs text-muted-foreground", children: p.company })
1420
+ company && /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("p", { className: "text-xs text-muted-foreground", children: company })
1400
1421
  ] })
1401
1422
  ] }),
1402
1423
  /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("div", { className: "flex flex-wrap gap-x-4 gap-y-1 pl-6", children: [
1403
- p.email && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
1424
+ email && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
1404
1425
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react13.Mail, { className: "h-3 w-3" }),
1405
- p.email
1426
+ email
1406
1427
  ] }),
1407
- p.phone && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
1428
+ phone && /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
1408
1429
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(import_lucide_react13.Phone, { className: "h-3 w-3" }),
1409
- p.phone
1430
+ phone
1410
1431
  ] })
1411
1432
  ] })
1412
1433
  ] });
@@ -1447,6 +1468,15 @@ function HubspotFormatter({ data }) {
1447
1468
  return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "space-y-2", children: companies.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(CompanyCard, { company: c }, c.id || i)) });
1448
1469
  }
1449
1470
  }
1471
+ if (typeof data === "object" && data !== null && "contacts" in data) {
1472
+ const contacts = data.contacts;
1473
+ if (Array.isArray(contacts)) {
1474
+ const valid = contacts.filter(isHubspotContact);
1475
+ if (valid.length > 0) {
1476
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsx)("div", { className: "space-y-2", children: valid.map((c, i) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(ContactCard, { contact: c }, c.id || i)) });
1477
+ }
1478
+ }
1479
+ }
1450
1480
  if (typeof data === "object" && data !== null && "results" in data) {
1451
1481
  const results = data.results;
1452
1482
  if (Array.isArray(results)) {
@@ -1638,6 +1668,21 @@ function PipedriveFormatter({ data }) {
1638
1668
  return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "space-y-2", children: deals.map((deal, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DealCard, { deal }, deal.id || i)) });
1639
1669
  }
1640
1670
  }
1671
+ if (typeof data === "object" && data !== null && "deals" in data) {
1672
+ const items = data.deals;
1673
+ if (Array.isArray(items)) {
1674
+ const deals = items.filter(isPipedriveDeal);
1675
+ if (deals.length > 0) {
1676
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { className: "space-y-2", children: deals.map((deal, i) => /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DealCard, { deal }, deal.id || i)) });
1677
+ }
1678
+ }
1679
+ }
1680
+ if (typeof data === "object" && data !== null && "deal" in data) {
1681
+ const item = data.deal;
1682
+ if (isPipedriveDeal(item)) {
1683
+ return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(DealCard, { deal: item });
1684
+ }
1685
+ }
1641
1686
  if (typeof data === "object" && data !== null && "data" in data) {
1642
1687
  const items = data.data;
1643
1688
  if (Array.isArray(items)) {
@@ -1939,11 +1984,16 @@ var import_lucide_react20 = require("lucide-react");
1939
1984
  var import_jsx_runtime20 = require("react/jsx-runtime");
1940
1985
  function isNotionPage(data) {
1941
1986
  if (typeof data !== "object" || data === null) return false;
1942
- return "properties" in data || "id" in data && "url" in data && String(data.url || "").includes("notion");
1987
+ if ("properties" in data) return true;
1988
+ if ("id" in data && "url" in data && String(data.url || "").includes("notion")) return true;
1989
+ if ("title" in data && "id" in data && "parentType" in data) return true;
1990
+ return false;
1943
1991
  }
1944
1992
  function isNotionDatabase(data) {
1945
1993
  if (typeof data !== "object" || data === null) return false;
1946
- return "title" in data && Array.isArray(data.title) && "id" in data;
1994
+ if ("title" in data && Array.isArray(data.title) && "id" in data) return true;
1995
+ if ("title" in data && "id" in data && "propertyCount" in data) return true;
1996
+ return false;
1947
1997
  }
1948
1998
  function extractPageTitle(page) {
1949
1999
  if (page.title) return page.title;
@@ -1986,17 +2036,17 @@ function PageCard({ page }) {
1986
2036
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react20.FileText, { className: "h-4 w-4 text-muted-foreground mt-0.5 shrink-0" }),
1987
2037
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "min-w-0 flex-1", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("p", { className: "text-sm font-medium text-foreground truncate", children: page.url ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("a", { href: page.url, target: "_blank", rel: "noopener noreferrer", className: "hover:underline", children: title }) : title }) }),
1988
2038
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-center gap-1.5 shrink-0", children: [
1989
- page.last_edited_time && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
2039
+ (page.last_edited_time || page.lastEditedTime) && /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("span", { className: "flex items-center gap-1 text-xs text-muted-foreground", children: [
1990
2040
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react20.Clock, { className: "h-3 w-3" }),
1991
- formatRelativeDate4(page.last_edited_time)
2041
+ formatRelativeDate4(page.last_edited_time || page.lastEditedTime)
1992
2042
  ] }),
1993
2043
  page.url && /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("a", { href: page.url, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react20.ExternalLink, { className: "h-3 w-3" }) })
1994
2044
  ] })
1995
2045
  ] }) });
1996
2046
  }
1997
2047
  function DatabaseCard({ db }) {
1998
- const title = Array.isArray(db.title) && db.title.length > 0 ? db.title.map((t) => t.plain_text || "").join("") : "Untitled database";
1999
- const desc = Array.isArray(db.description) && db.description.length > 0 ? db.description.map((d) => d.plain_text || "").join("") : null;
2048
+ const title = typeof db.title === "string" ? db.title : Array.isArray(db.title) && db.title.length > 0 ? db.title.map((t) => t.plain_text || "").join("") : "Untitled database";
2049
+ const desc = typeof db.description === "string" ? db.description : Array.isArray(db.description) && db.description.length > 0 ? db.description.map((d) => d.plain_text || "").join("") : null;
2000
2050
  return /* @__PURE__ */ (0, import_jsx_runtime20.jsx)("div", { className: "rounded-lg border border-border bg-card p-3 space-y-1", children: /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "flex items-start gap-2", children: [
2001
2051
  /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(import_lucide_react20.Database, { className: "h-4 w-4 text-muted-foreground mt-0.5 shrink-0" }),
2002
2052
  /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { className: "min-w-0 flex-1", children: [