@sentry/junior 0.156.0 → 0.158.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/dist/{agent-hooks-CCAR46PQ.js → agent-hooks-BOWFTDE5.js} +10 -10
- package/dist/api/conversations/attachments.d.ts +32 -0
- package/dist/api/conversations/priority.d.ts +22 -0
- package/dist/api/conversations/routes.d.ts +4 -1
- package/dist/api/conversations/user-message-activity.d.ts +3 -0
- package/dist/api/locations/detail.d.ts +3 -1
- package/dist/api/schema/conversation.d.ts +14 -4
- package/dist/api/schema/location.d.ts +3 -1
- package/dist/api/schema/person.d.ts +3 -1
- package/dist/api/schema/task.d.ts +8 -8
- package/dist/api/schema.js +1 -1
- package/dist/api.js +350 -187
- package/dist/app.js +35 -54
- package/dist/{catalog-runtime-3SNKYCBG.js → catalog-runtime-7GZ25WTR.js} +5 -5
- package/dist/chat/agent-invocations/types.d.ts +12 -12
- package/dist/chat/attachments/storage.d.ts +2 -0
- package/dist/chat/attachments/store.d.ts +16 -0
- package/dist/chat/event-tasks/tool-support.d.ts +1 -1
- package/dist/chat/event-tasks/types.d.ts +1 -1
- package/dist/chat/plugins/unfinished-work.d.ts +6 -1
- package/dist/chat/scheduled-tasks/tool-support.d.ts +5 -5
- package/dist/chat/scheduled-tasks/tools/create.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/delete.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/list.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/run-now.d.ts +2 -2
- package/dist/chat/scheduled-tasks/tools/update.d.ts +2 -2
- package/dist/chat/task-execution/slack-work.d.ts +2 -2
- package/dist/{chunk-4ZZDTHFC.js → chunk-3A7VXSPJ.js} +8 -8
- package/dist/{chunk-7RAETIYO.js → chunk-4JAOLUDB.js} +6 -6
- package/dist/{chunk-KCA5MKHU.js → chunk-4Q6QVTKA.js} +351 -5
- package/dist/{chunk-TN4LVILT.js → chunk-4XJ2WSTI.js} +5 -5
- package/dist/{chunk-OGZPRMZA.js → chunk-6GJCOUTA.js} +1 -1
- package/dist/{chunk-6CINHXIL.js → chunk-A7EDLNGU.js} +4 -4
- package/dist/{chunk-IIO5PFZX.js → chunk-AF4PHIP6.js} +3 -3
- package/dist/{chunk-IZEBHYI4.js → chunk-BNFGY66A.js} +1 -1
- package/dist/{chunk-3L2PMOSR.js → chunk-C3FYJZSA.js} +4 -4
- package/dist/{chunk-X5NZQH5U.js → chunk-CZCMFRUQ.js} +16 -0
- package/dist/{chunk-CK2H7CFO.js → chunk-DTVTBZNP.js} +1 -1
- package/dist/{chunk-WD7SEUZO.js → chunk-EQ6Y37MD.js} +1 -1
- package/dist/{chunk-53W3LZEW.js → chunk-EXITAVHO.js} +64 -361
- package/dist/{chunk-ZNWRYNCA.js → chunk-FA32YRZ3.js} +5 -5
- package/dist/{chunk-GKC43TLS.js → chunk-FAJ6SMEE.js} +2 -2
- package/dist/{chunk-GSBPZHLQ.js → chunk-IEM3GFXL.js} +9 -9
- package/dist/{chunk-KBGMYLSV.js → chunk-IXYGGJRA.js} +1 -1
- package/dist/{chunk-OMQJB7YN.js → chunk-JEXQQLEC.js} +18 -18
- package/dist/{chunk-PMFGVLDU.js → chunk-KAFYW3O6.js} +35 -10
- package/dist/{chunk-X7W45B5G.js → chunk-KSZXVR5G.js} +1 -1
- package/dist/{chunk-SRJA6QLM.js → chunk-LUSAAJJA.js} +2 -2
- package/dist/{chunk-3FFUC32L.js → chunk-NOEERHHR.js} +6 -6
- package/dist/{chunk-MC57E5U5.js → chunk-PHQDXC27.js} +1 -1
- package/dist/{chunk-A6WPDFHQ.js → chunk-RCIKTZZF.js} +1 -1
- package/dist/{chunk-NTNU6T2D.js → chunk-ROOTB7J7.js} +2 -2
- package/dist/{chunk-TNXGMFWV.js → chunk-SAJPQLTY.js} +1 -1
- package/dist/{chunk-SE3D225X.js → chunk-SSU65ZTZ.js} +1 -1
- package/dist/{chunk-6JUU7J2B.js → chunk-UJ6N32ZM.js} +4 -4
- package/dist/{chunk-MJE7XKWP.js → chunk-UPPU3FQU.js} +1 -1
- package/dist/{chunk-JUJR6WTL.js → chunk-UQJO35BP.js} +4 -4
- package/dist/{chunk-AIJRG227.js → chunk-VURJ2NSF.js} +1 -1
- package/dist/{chunk-CN2XSVKF.js → chunk-X4BLYIMV.js} +6 -6
- package/dist/{chunk-EDJ64P2P.js → chunk-YEZS4TEY.js} +1 -1
- package/dist/cli/chat.js +30 -30
- package/dist/cli/check.js +6 -6
- package/dist/cli/plugins.js +13 -13
- package/dist/cli/snapshot-create.js +9 -9
- package/dist/cli/upgrade.js +7 -7
- package/dist/db/schema/agent-invocations.d.ts +4 -4
- package/dist/db/schema.d.ts +4 -4
- package/dist/{db-TYUUKGJX.js → db-HFWTPYT7.js} +7 -7
- package/dist/instrumentation.js +4 -4
- package/dist/nitro.js +2 -2
- package/dist/{oauth-callback-server-AWVDKPR5.js → oauth-callback-server-J3NW4QL5.js} +23 -23
- package/dist/{runner-JUQXMACC.js → runner-CL6QHML5.js} +14 -15
- package/dist/{skills-4GZTZX4V.js → skills-WZWKZIFQ.js} +6 -6
- package/dist/spawn-TQJWADG4.js +37 -0
- package/dist/{validation-DRLNJRND.js → validation-4HVSSLJV.js} +6 -6
- package/dist/version.js +1 -1
- package/dist/{work-TGIXRRJY.js → work-UF4KXPVG.js} +17 -17
- package/dist/worker-HI7I2W2U.js +24 -0
- package/package.json +5 -5
- package/dist/spawn-32SSRWU4.js +0 -37
- package/dist/worker-IFXZOYED.js +0 -24
package/dist/api.js
CHANGED
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
apiErrorSchema,
|
|
7
7
|
archiveConversationBodySchema,
|
|
8
8
|
archiveConversationResponseSchema,
|
|
9
|
+
conversationAttachmentParamsSchema,
|
|
9
10
|
conversationDetailQuerySchema,
|
|
10
11
|
conversationDetailReportSchema,
|
|
11
12
|
conversationEventPageSchema,
|
|
@@ -33,23 +34,24 @@ import {
|
|
|
33
34
|
taskListSchema,
|
|
34
35
|
taskParamsSchema,
|
|
35
36
|
taskRunListSchema
|
|
36
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-CZCMFRUQ.js";
|
|
37
38
|
import {
|
|
38
39
|
appendAndEnqueueApiConversationMessage,
|
|
39
40
|
createAndEnqueueApiConversation,
|
|
41
|
+
createVercelAttachmentStorage,
|
|
40
42
|
formatSlackConversationRedactedLabel,
|
|
41
43
|
lookupSlackUser,
|
|
42
44
|
readHealthReport,
|
|
43
45
|
resolveSlackConversationContextFromThreadId,
|
|
44
46
|
webActorFromEmail
|
|
45
|
-
} from "./chunk-
|
|
47
|
+
} from "./chunk-KAFYW3O6.js";
|
|
46
48
|
import {
|
|
47
49
|
buildSentryConversationUrl,
|
|
48
50
|
getWebAuthorization
|
|
49
|
-
} from "./chunk-
|
|
51
|
+
} from "./chunk-SSU65ZTZ.js";
|
|
50
52
|
import {
|
|
51
53
|
getConversation
|
|
52
|
-
} from "./chunk-
|
|
54
|
+
} from "./chunk-A7EDLNGU.js";
|
|
53
55
|
import {
|
|
54
56
|
readTaskExecutionByConversationId,
|
|
55
57
|
readTaskExecutionDays,
|
|
@@ -57,8 +59,8 @@ import {
|
|
|
57
59
|
readTaskExecutionSummaries,
|
|
58
60
|
readTaskExecutions,
|
|
59
61
|
readTaskRuns
|
|
60
|
-
} from "./chunk-
|
|
61
|
-
import "./chunk-
|
|
62
|
+
} from "./chunk-IEM3GFXL.js";
|
|
63
|
+
import "./chunk-4XJ2WSTI.js";
|
|
62
64
|
import {
|
|
63
65
|
healthReportSchema,
|
|
64
66
|
pluginOperationalReportFeedSchema,
|
|
@@ -81,17 +83,18 @@ import {
|
|
|
81
83
|
listEventTasksCreatedBy,
|
|
82
84
|
listPublicEventTasksForTeams,
|
|
83
85
|
listPublicScheduledTasksForTeams,
|
|
86
|
+
readLiveAttachment,
|
|
84
87
|
readStats
|
|
85
|
-
} from "./chunk-
|
|
88
|
+
} from "./chunk-4Q6QVTKA.js";
|
|
86
89
|
import {
|
|
87
90
|
parseSlackThreadId
|
|
88
|
-
} from "./chunk-
|
|
91
|
+
} from "./chunk-DTVTBZNP.js";
|
|
89
92
|
import {
|
|
90
93
|
agentTurnUsageSchema,
|
|
91
94
|
fallbackShortTitle,
|
|
92
95
|
hasAgentTurnUsage,
|
|
93
96
|
renderJuniorNativeConversationEvent
|
|
94
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-C3FYJZSA.js";
|
|
95
98
|
import "./chunk-3Y47VMHV.js";
|
|
96
99
|
import "./chunk-PDO5BLNM.js";
|
|
97
100
|
import {
|
|
@@ -101,11 +104,11 @@ import {
|
|
|
101
104
|
renderPluginConversationEvent,
|
|
102
105
|
resolveViewerUser,
|
|
103
106
|
updateViewerDisplayName
|
|
104
|
-
} from "./chunk-
|
|
107
|
+
} from "./chunk-NOEERHHR.js";
|
|
105
108
|
import {
|
|
106
109
|
getSlackClient,
|
|
107
110
|
withSlackRetries
|
|
108
|
-
} from "./chunk-
|
|
111
|
+
} from "./chunk-ROOTB7J7.js";
|
|
109
112
|
import {
|
|
110
113
|
decodeStoredConversationEvent,
|
|
111
114
|
getConversationStore,
|
|
@@ -113,7 +116,7 @@ import {
|
|
|
113
116
|
getSqlExecutor,
|
|
114
117
|
locationFromRow,
|
|
115
118
|
parseSessionSource
|
|
116
|
-
} from "./chunk-
|
|
119
|
+
} from "./chunk-AF4PHIP6.js";
|
|
117
120
|
import {
|
|
118
121
|
juniorApiTokens,
|
|
119
122
|
juniorConversationEvents,
|
|
@@ -121,16 +124,16 @@ import {
|
|
|
121
124
|
juniorConversations,
|
|
122
125
|
juniorIdentities,
|
|
123
126
|
juniorUsers
|
|
124
|
-
} from "./chunk-
|
|
127
|
+
} from "./chunk-VURJ2NSF.js";
|
|
125
128
|
import "./chunk-EM225ITJ.js";
|
|
126
|
-
import "./chunk-
|
|
127
|
-
import "./chunk-
|
|
129
|
+
import "./chunk-PHQDXC27.js";
|
|
130
|
+
import "./chunk-FAJ6SMEE.js";
|
|
128
131
|
import {
|
|
129
132
|
juniorDestinations
|
|
130
133
|
} from "./chunk-VFUK3X5B.js";
|
|
131
134
|
import {
|
|
132
135
|
canExposeConversationPayload
|
|
133
|
-
} from "./chunk-
|
|
136
|
+
} from "./chunk-UPPU3FQU.js";
|
|
134
137
|
import "./chunk-BDUENQD3.js";
|
|
135
138
|
import {
|
|
136
139
|
parseSlackChannelId,
|
|
@@ -140,10 +143,10 @@ import {
|
|
|
140
143
|
import {
|
|
141
144
|
logException,
|
|
142
145
|
logWarn
|
|
143
|
-
} from "./chunk-
|
|
146
|
+
} from "./chunk-KSZXVR5G.js";
|
|
144
147
|
import "./chunk-6GWA276C.js";
|
|
145
|
-
import "./chunk-
|
|
146
|
-
import "./chunk-
|
|
148
|
+
import "./chunk-6GJCOUTA.js";
|
|
149
|
+
import "./chunk-IXYGGJRA.js";
|
|
147
150
|
import "./chunk-MLKGABMK.js";
|
|
148
151
|
|
|
149
152
|
// src/api.ts
|
|
@@ -353,6 +356,47 @@ async function readConversationAccessFromSql(db, conversationIds, viewer) {
|
|
|
353
356
|
);
|
|
354
357
|
}
|
|
355
358
|
|
|
359
|
+
// src/api/conversations/attachments.ts
|
|
360
|
+
function mayDisplayInline(contentType) {
|
|
361
|
+
return contentType === "image/gif" || contentType === "image/jpeg" || contentType === "image/png" || contentType === "image/webp";
|
|
362
|
+
}
|
|
363
|
+
function contentDisposition(filename, contentType) {
|
|
364
|
+
const disposition = mayDisplayInline(contentType) ? "inline" : "attachment";
|
|
365
|
+
const fallback = filename.replace(/[^\x20-\x7e]|["\\]/g, "_");
|
|
366
|
+
return `${disposition}; filename="${fallback}"; filename*=UTF-8''${encodeURIComponent(filename)}`;
|
|
367
|
+
}
|
|
368
|
+
function conversationAttachmentHeaders(args) {
|
|
369
|
+
return new Headers({
|
|
370
|
+
"cache-control": "private, no-store",
|
|
371
|
+
"content-disposition": contentDisposition(args.filename, args.contentType),
|
|
372
|
+
"content-length": String(args.bytes),
|
|
373
|
+
"content-type": args.contentType,
|
|
374
|
+
"x-content-type-options": "nosniff"
|
|
375
|
+
});
|
|
376
|
+
}
|
|
377
|
+
async function openConversationAttachment(args) {
|
|
378
|
+
const access = (await readConversationAccessFromSql(
|
|
379
|
+
getDb(),
|
|
380
|
+
[args.conversationId],
|
|
381
|
+
args.viewer
|
|
382
|
+
)).get(args.conversationId);
|
|
383
|
+
if (!access?.canViewPrivateContent) return null;
|
|
384
|
+
const attachment = await readLiveAttachment({
|
|
385
|
+
attachmentId: args.attachmentId,
|
|
386
|
+
conversationId: args.conversationId,
|
|
387
|
+
db: getSqlExecutor()
|
|
388
|
+
});
|
|
389
|
+
if (!attachment) return null;
|
|
390
|
+
if (attachment.provider !== args.storage.provider) return null;
|
|
391
|
+
const body = await args.storage.get(attachment.storageKey);
|
|
392
|
+
return body ? { attachment, body } : null;
|
|
393
|
+
}
|
|
394
|
+
async function requireConversationAttachment(args) {
|
|
395
|
+
const opened = await openConversationAttachment(args);
|
|
396
|
+
if (!opened) throwApiError(404, "Attachment not found.");
|
|
397
|
+
return opened;
|
|
398
|
+
}
|
|
399
|
+
|
|
356
400
|
// src/api/conversations/create.ts
|
|
357
401
|
function actorFromViewer(viewer) {
|
|
358
402
|
const normalized = viewer.email.trim().toLowerCase();
|
|
@@ -1210,7 +1254,7 @@ async function readConversationEventPage(executor, args) {
|
|
|
1210
1254
|
}
|
|
1211
1255
|
|
|
1212
1256
|
// src/api/conversations/list.ts
|
|
1213
|
-
import { and as
|
|
1257
|
+
import { and as and8, asc as asc2, desc as desc2, eq as eq9, isNull as isNull3 } from "drizzle-orm";
|
|
1214
1258
|
|
|
1215
1259
|
// src/api/conversations/shared.ts
|
|
1216
1260
|
function slackStatsLocationLabel(input) {
|
|
@@ -1607,10 +1651,11 @@ async function readConversationAuxiliaryCostsFromSql(db, conversationIds, option
|
|
|
1607
1651
|
// src/chat/plugins/unfinished-work.ts
|
|
1608
1652
|
async function listConversationWork(conversationIds) {
|
|
1609
1653
|
if (conversationIds.length === 0) {
|
|
1610
|
-
return { assignedIds: [], unfinishedIds: [] };
|
|
1654
|
+
return { assignedIds: [], finishedAtById: {}, unfinishedIds: [] };
|
|
1611
1655
|
}
|
|
1612
1656
|
const candidates = new Set(conversationIds);
|
|
1613
1657
|
const assigned = /* @__PURE__ */ new Set();
|
|
1658
|
+
const finishedAtById = /* @__PURE__ */ new Map();
|
|
1614
1659
|
const unfinished = /* @__PURE__ */ new Set();
|
|
1615
1660
|
for (const plugin of getPlugins()) {
|
|
1616
1661
|
const hook = plugin.hooks?.unfinishedWork;
|
|
@@ -1630,6 +1675,17 @@ async function listConversationWork(conversationIds) {
|
|
|
1630
1675
|
for (const conversationId of result.assignedConversationIds ?? []) {
|
|
1631
1676
|
if (candidates.has(conversationId)) assigned.add(conversationId);
|
|
1632
1677
|
}
|
|
1678
|
+
for (const [conversationId, finishedAt] of Object.entries(
|
|
1679
|
+
result.finishedWorkAtByConversationId ?? {}
|
|
1680
|
+
)) {
|
|
1681
|
+
if (!candidates.has(conversationId)) continue;
|
|
1682
|
+
const time = Date.parse(finishedAt);
|
|
1683
|
+
if (!Number.isFinite(time)) continue;
|
|
1684
|
+
const current = finishedAtById.get(conversationId);
|
|
1685
|
+
if (!current || time > Date.parse(current)) {
|
|
1686
|
+
finishedAtById.set(conversationId, finishedAt);
|
|
1687
|
+
}
|
|
1688
|
+
}
|
|
1633
1689
|
} catch (error) {
|
|
1634
1690
|
logWarn("plugin.unfinished_work.hook.failed", {
|
|
1635
1691
|
"app.plugin.name": plugin.manifest.name,
|
|
@@ -1641,24 +1697,82 @@ async function listConversationWork(conversationIds) {
|
|
|
1641
1697
|
assignedIds: conversationIds.filter(
|
|
1642
1698
|
(conversationId) => assigned.has(conversationId)
|
|
1643
1699
|
),
|
|
1700
|
+
finishedAtById: Object.fromEntries(
|
|
1701
|
+
conversationIds.flatMap((conversationId) => {
|
|
1702
|
+
const finishedAt = finishedAtById.get(conversationId);
|
|
1703
|
+
return finishedAt ? [[conversationId, finishedAt]] : [];
|
|
1704
|
+
})
|
|
1705
|
+
),
|
|
1644
1706
|
unfinishedIds: conversationIds.filter(
|
|
1645
1707
|
(conversationId) => unfinished.has(conversationId)
|
|
1646
1708
|
)
|
|
1647
1709
|
};
|
|
1648
1710
|
}
|
|
1649
1711
|
|
|
1712
|
+
// src/api/conversations/priority.ts
|
|
1713
|
+
var UNASSIGNED_PRIORITY_WINDOW_MS = 3 * 60 * 60 * 1e3;
|
|
1714
|
+
var UNFINISHED_PRIORITY_WINDOW_MS = 48 * 60 * 60 * 1e3;
|
|
1715
|
+
function isConversationPriority(conversation, nowMs) {
|
|
1716
|
+
const lastSeenAt = Date.parse(conversation.lastSeenAt);
|
|
1717
|
+
if (!Number.isFinite(lastSeenAt)) return false;
|
|
1718
|
+
if (conversation.unfinishedWork) {
|
|
1719
|
+
return nowMs - lastSeenAt <= UNFINISHED_PRIORITY_WINDOW_MS;
|
|
1720
|
+
}
|
|
1721
|
+
if (conversation.assignedWork) {
|
|
1722
|
+
const finishedAt = Date.parse(conversation.finishedWorkAt ?? "");
|
|
1723
|
+
const lastUserMessageAt = Date.parse(conversation.lastUserMessageAt ?? "");
|
|
1724
|
+
return Number.isFinite(finishedAt) && Number.isFinite(lastUserMessageAt) && lastUserMessageAt > finishedAt;
|
|
1725
|
+
}
|
|
1726
|
+
return nowMs - lastSeenAt <= UNASSIGNED_PRIORITY_WINDOW_MS;
|
|
1727
|
+
}
|
|
1728
|
+
|
|
1729
|
+
// src/api/conversations/user-message-activity.ts
|
|
1730
|
+
import { and as and7, eq as eq8, inArray as inArray6, isNotNull as isNotNull3, or as or3, sql as sql5 } from "drizzle-orm";
|
|
1731
|
+
async function readLastUserMessageAtByConversation(db, conversationIds) {
|
|
1732
|
+
if (conversationIds.length === 0) return /* @__PURE__ */ new Map();
|
|
1733
|
+
const authority = sql5`${juniorConversationEvents.payload}->'provenance'->>'authority'`;
|
|
1734
|
+
const actorPlatform = sql5`${juniorConversationEvents.payload}->'provenance'->'actor'->>'platform'`;
|
|
1735
|
+
const role = sql5`${juniorConversationEvents.payload}->>'role'`;
|
|
1736
|
+
const rows = await db.select({
|
|
1737
|
+
conversationId: juniorConversationEvents.conversationId,
|
|
1738
|
+
lastUserMessageAt: sql5`max(${juniorConversationEvents.createdAt})`
|
|
1739
|
+
}).from(juniorConversationEvents).where(
|
|
1740
|
+
and7(
|
|
1741
|
+
inArray6(juniorConversationEvents.conversationId, conversationIds),
|
|
1742
|
+
or3(
|
|
1743
|
+
and7(
|
|
1744
|
+
eq8(juniorConversationEvents.type, "user_message"),
|
|
1745
|
+
eq8(authority, "instruction"),
|
|
1746
|
+
sql5`${actorPlatform} in ('slack', 'local', 'web')`
|
|
1747
|
+
),
|
|
1748
|
+
and7(
|
|
1749
|
+
eq8(juniorConversationEvents.type, "message"),
|
|
1750
|
+
eq8(role, "user"),
|
|
1751
|
+
isNotNull3(juniorConversationEvents.actorIdentityId)
|
|
1752
|
+
)
|
|
1753
|
+
)
|
|
1754
|
+
)
|
|
1755
|
+
).groupBy(juniorConversationEvents.conversationId);
|
|
1756
|
+
return new Map(
|
|
1757
|
+
rows.map((row) => [
|
|
1758
|
+
row.conversationId,
|
|
1759
|
+
new Date(row.lastUserMessageAt).toISOString()
|
|
1760
|
+
])
|
|
1761
|
+
);
|
|
1762
|
+
}
|
|
1763
|
+
|
|
1650
1764
|
// src/api/conversations/list.ts
|
|
1651
1765
|
var CONVERSATION_FEED_LIMIT = 50;
|
|
1652
1766
|
function conversationFeedMembershipFilter(filter) {
|
|
1653
1767
|
if (!filter) return void 0;
|
|
1654
1768
|
if (filter.kind === "viewer") {
|
|
1655
1769
|
return viewerConversationMembership({
|
|
1656
|
-
actorMatch:
|
|
1770
|
+
actorMatch: eq9(juniorIdentities.userId, filter.userId),
|
|
1657
1771
|
participantMatch: conversationHasParticipantUser(filter.userId)
|
|
1658
1772
|
});
|
|
1659
1773
|
}
|
|
1660
1774
|
return viewerConversationMembership({
|
|
1661
|
-
actorMatch:
|
|
1775
|
+
actorMatch: eq9(juniorUsers.primaryEmailNormalized, filter.email),
|
|
1662
1776
|
participantMatch: conversationHasParticipantEmail(filter.email)
|
|
1663
1777
|
});
|
|
1664
1778
|
}
|
|
@@ -1675,12 +1789,12 @@ async function conversationRows(db, limit, filter) {
|
|
|
1675
1789
|
userDisplayName: juniorUsers.displayName
|
|
1676
1790
|
}).from(juniorConversations).leftJoin(
|
|
1677
1791
|
juniorDestinations,
|
|
1678
|
-
|
|
1792
|
+
eq9(juniorDestinations.id, juniorConversations.destinationId)
|
|
1679
1793
|
).leftJoin(
|
|
1680
1794
|
juniorIdentities,
|
|
1681
|
-
|
|
1682
|
-
).leftJoin(juniorUsers,
|
|
1683
|
-
|
|
1795
|
+
eq9(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
1796
|
+
).leftJoin(juniorUsers, eq9(juniorUsers.id, juniorIdentities.userId)).where(
|
|
1797
|
+
and8(
|
|
1684
1798
|
isNull3(juniorConversations.parentConversationId),
|
|
1685
1799
|
isNull3(juniorConversations.archivedAt),
|
|
1686
1800
|
conversationFeedMembershipFilter(filter)
|
|
@@ -1741,11 +1855,11 @@ async function readConversationRecordFromSql(conversationId) {
|
|
|
1741
1855
|
userDisplayName: juniorUsers.displayName
|
|
1742
1856
|
}).from(juniorConversations).leftJoin(
|
|
1743
1857
|
juniorDestinations,
|
|
1744
|
-
|
|
1858
|
+
eq9(juniorDestinations.id, juniorConversations.destinationId)
|
|
1745
1859
|
).leftJoin(
|
|
1746
1860
|
juniorIdentities,
|
|
1747
|
-
|
|
1748
|
-
).leftJoin(juniorUsers,
|
|
1861
|
+
eq9(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
1862
|
+
).leftJoin(juniorUsers, eq9(juniorUsers.id, juniorIdentities.userId)).where(eq9(juniorConversations.conversationId, conversationId)).limit(1);
|
|
1749
1863
|
const row = rows[0];
|
|
1750
1864
|
return row ? {
|
|
1751
1865
|
conversation: conversationFromRow(row),
|
|
@@ -1787,7 +1901,8 @@ async function readConversationFeedFromSql(options = {}) {
|
|
|
1787
1901
|
auxiliaryCostsByRoot,
|
|
1788
1902
|
metricsByRoot,
|
|
1789
1903
|
teamDomainByTeamId,
|
|
1790
|
-
conversationWork
|
|
1904
|
+
conversationWork,
|
|
1905
|
+
lastUserMessageAtByConversation
|
|
1791
1906
|
] = await Promise.all([
|
|
1792
1907
|
readConversationAccessFromSql(db, conversationIds, options.viewer),
|
|
1793
1908
|
readConversationAuxiliaryCostsFromSql(db, conversationIds, {
|
|
@@ -1799,7 +1914,8 @@ async function readConversationFeedFromSql(options = {}) {
|
|
|
1799
1914
|
(conversation) => conversation.sessionSource?.platform === "slack" ? [conversation.sessionSource.teamId] : []
|
|
1800
1915
|
)
|
|
1801
1916
|
),
|
|
1802
|
-
listConversationWork(conversationIds)
|
|
1917
|
+
listConversationWork(conversationIds),
|
|
1918
|
+
readLastUserMessageAtByConversation(db, conversationIds)
|
|
1803
1919
|
]);
|
|
1804
1920
|
const assignedWork = new Set(conversationWork.assignedIds);
|
|
1805
1921
|
const unfinishedWork = new Set(conversationWork.unfinishedIds);
|
|
@@ -1807,19 +1923,36 @@ async function readConversationFeedFromSql(options = {}) {
|
|
|
1807
1923
|
conversations: conversations.map((conversation, index) => {
|
|
1808
1924
|
const row = rows[index];
|
|
1809
1925
|
const metrics = metricsByRoot.get(conversation.conversationId);
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1926
|
+
const summary = conversationSummaryFromStoredConversation({
|
|
1927
|
+
conversation,
|
|
1928
|
+
access: accessByConversation.get(conversation.conversationId),
|
|
1929
|
+
auxiliaryCosts: auxiliaryCostsByRoot.get(conversation.conversationId),
|
|
1930
|
+
durationMs: metrics?.durationMs ?? row.conversation.durationMs,
|
|
1931
|
+
teamDomainByTeamId,
|
|
1932
|
+
...row.destination?.visibility === "public" ? { locationId: row.destination.id } : {},
|
|
1933
|
+
usage: metrics?.usage ?? row.conversation.usage ?? void 0
|
|
1934
|
+
});
|
|
1935
|
+
const work = {
|
|
1820
1936
|
...assignedWork.has(conversation.conversationId) ? { assignedWork: true } : {},
|
|
1937
|
+
...conversationWork.finishedAtById[conversation.conversationId] ? {
|
|
1938
|
+
finishedWorkAt: conversationWork.finishedAtById[conversation.conversationId]
|
|
1939
|
+
} : {},
|
|
1821
1940
|
...unfinishedWork.has(conversation.conversationId) ? { unfinishedWork: true } : {}
|
|
1822
1941
|
};
|
|
1942
|
+
return {
|
|
1943
|
+
...summary,
|
|
1944
|
+
...work,
|
|
1945
|
+
isPriority: isConversationPriority(
|
|
1946
|
+
{
|
|
1947
|
+
lastSeenAt: summary.lastSeenAt,
|
|
1948
|
+
lastUserMessageAt: lastUserMessageAtByConversation.get(
|
|
1949
|
+
conversation.conversationId
|
|
1950
|
+
),
|
|
1951
|
+
...work
|
|
1952
|
+
},
|
|
1953
|
+
nowMs
|
|
1954
|
+
)
|
|
1955
|
+
};
|
|
1823
1956
|
}),
|
|
1824
1957
|
generatedAt: new Date(nowMs).toISOString(),
|
|
1825
1958
|
source: "conversation_index"
|
|
@@ -1832,7 +1965,7 @@ async function readConversationFeed(options = {}) {
|
|
|
1832
1965
|
}
|
|
1833
1966
|
|
|
1834
1967
|
// src/chat/tasks/read.ts
|
|
1835
|
-
import { and as
|
|
1968
|
+
import { and as and9, eq as eq10, or as or4 } from "drizzle-orm";
|
|
1836
1969
|
|
|
1837
1970
|
// src/chat/scheduled-tasks/personal.ts
|
|
1838
1971
|
import { z as z3 } from "zod";
|
|
@@ -1942,16 +2075,16 @@ async function creatorProfileEmails(candidates) {
|
|
|
1942
2075
|
email: juniorUsers.primaryEmailNormalized,
|
|
1943
2076
|
slackUserId: juniorIdentities.providerSubjectId,
|
|
1944
2077
|
teamId: juniorIdentities.providerTenantId
|
|
1945
|
-
}).from(juniorIdentities).innerJoin(juniorUsers,
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
1949
|
-
|
|
1950
|
-
|
|
2078
|
+
}).from(juniorIdentities).innerJoin(juniorUsers, eq10(juniorUsers.id, juniorIdentities.userId)).where(
|
|
2079
|
+
and9(
|
|
2080
|
+
eq10(juniorIdentities.kind, "user"),
|
|
2081
|
+
eq10(juniorIdentities.provider, "slack"),
|
|
2082
|
+
eq10(juniorIdentities.emailVerified, true),
|
|
2083
|
+
or4(
|
|
1951
2084
|
...[...selectors.values()].map(
|
|
1952
|
-
(selector) =>
|
|
1953
|
-
|
|
1954
|
-
|
|
2085
|
+
(selector) => and9(
|
|
2086
|
+
eq10(juniorIdentities.providerTenantId, selector.teamId),
|
|
2087
|
+
eq10(juniorIdentities.providerSubjectId, selector.slackUserId)
|
|
1955
2088
|
)
|
|
1956
2089
|
)
|
|
1957
2090
|
)
|
|
@@ -1987,12 +2120,12 @@ async function destinationDetails(destinations) {
|
|
|
1987
2120
|
providerTenantId: juniorDestinations.providerTenantId,
|
|
1988
2121
|
visibility: juniorDestinations.visibility
|
|
1989
2122
|
}).from(juniorDestinations).where(
|
|
1990
|
-
|
|
2123
|
+
or4(
|
|
1991
2124
|
...[...selectors.values()].map(
|
|
1992
|
-
(destination) =>
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
2125
|
+
(destination) => and9(
|
|
2126
|
+
eq10(juniorDestinations.provider, "slack"),
|
|
2127
|
+
eq10(juniorDestinations.providerTenantId, destination.teamId),
|
|
2128
|
+
eq10(juniorDestinations.providerDestinationId, destination.channelId)
|
|
1996
2129
|
)
|
|
1997
2130
|
)
|
|
1998
2131
|
)
|
|
@@ -2645,20 +2778,20 @@ async function requireConversationPendingMessages(conversationId, options = {})
|
|
|
2645
2778
|
}
|
|
2646
2779
|
|
|
2647
2780
|
// src/api/conversations/stats.query.ts
|
|
2648
|
-
import { and as
|
|
2781
|
+
import { and as and10, eq as eq11, gte, isNull as isNull4, lte, sql as sql7 } from "drizzle-orm";
|
|
2649
2782
|
import { alias as alias4 } from "drizzle-orm/pg-core";
|
|
2650
2783
|
|
|
2651
2784
|
// src/api/conversations/aggregate.ts
|
|
2652
|
-
import { sql as
|
|
2785
|
+
import { sql as sql6 } from "drizzle-orm";
|
|
2653
2786
|
function usageTokenValue(source, field) {
|
|
2654
|
-
return
|
|
2787
|
+
return sql6`CASE
|
|
2655
2788
|
WHEN ${source.usage}->>${field} IS NOT NULL
|
|
2656
2789
|
THEN (${source.usage}->>${field})::double precision
|
|
2657
2790
|
ELSE NULL
|
|
2658
2791
|
END`;
|
|
2659
2792
|
}
|
|
2660
2793
|
function tokenValue(source) {
|
|
2661
|
-
return
|
|
2794
|
+
return sql6`
|
|
2662
2795
|
CASE
|
|
2663
2796
|
WHEN COALESCE(
|
|
2664
2797
|
${source.usage}->>'inputTokens',
|
|
@@ -2677,7 +2810,7 @@ function tokenValue(source) {
|
|
|
2677
2810
|
`;
|
|
2678
2811
|
}
|
|
2679
2812
|
function costValue(source) {
|
|
2680
|
-
return
|
|
2813
|
+
return sql6`
|
|
2681
2814
|
CASE
|
|
2682
2815
|
WHEN ${source.usage}->'cost'->>'total' IS NOT NULL
|
|
2683
2816
|
THEN (${source.usage}->'cost'->>'total')::double precision
|
|
@@ -2698,34 +2831,34 @@ function costValue(source) {
|
|
|
2698
2831
|
function conversationAggregateColumns(sources) {
|
|
2699
2832
|
const metrics = sources?.metrics ?? juniorConversations;
|
|
2700
2833
|
const roots = sources?.roots ?? juniorConversations;
|
|
2701
|
-
const conversationCount = sources ?
|
|
2834
|
+
const conversationCount = sources ? sql6`COUNT(DISTINCT ${roots.conversationId})` : sql6`COUNT(*)`;
|
|
2702
2835
|
return {
|
|
2703
|
-
active:
|
|
2836
|
+
active: sql6`${conversationCount} FILTER (
|
|
2704
2837
|
WHERE ${roots.executionStatus} NOT IN ('idle', 'failed')
|
|
2705
2838
|
)::integer`,
|
|
2706
|
-
conversations:
|
|
2707
|
-
cachedInputTokens:
|
|
2708
|
-
costUsd:
|
|
2709
|
-
durationMs:
|
|
2710
|
-
failed:
|
|
2839
|
+
conversations: sql6`${conversationCount}::integer`,
|
|
2840
|
+
cachedInputTokens: sql6`SUM(${usageTokenValue(metrics, "cachedInputTokens")})::double precision`,
|
|
2841
|
+
costUsd: sql6`SUM(${costValue(metrics)})::double precision`,
|
|
2842
|
+
durationMs: sql6`COALESCE(SUM(${metrics.durationMs}), 0)::double precision`,
|
|
2843
|
+
failed: sql6`${conversationCount} FILTER (
|
|
2711
2844
|
WHERE ${roots.executionStatus} = 'failed'
|
|
2712
2845
|
)::integer`,
|
|
2713
|
-
inputTokens:
|
|
2714
|
-
tokens:
|
|
2846
|
+
inputTokens: sql6`SUM(${usageTokenValue(metrics, "inputTokens")})::double precision`,
|
|
2847
|
+
tokens: sql6`SUM(${tokenValue(metrics)})::double precision`
|
|
2715
2848
|
};
|
|
2716
2849
|
}
|
|
2717
2850
|
function conversationRangeColumns() {
|
|
2718
2851
|
return {
|
|
2719
|
-
firstSeenAt:
|
|
2852
|
+
firstSeenAt: sql6`MIN(${juniorConversations.createdAt})`.mapWith(
|
|
2720
2853
|
juniorConversations.createdAt
|
|
2721
2854
|
),
|
|
2722
|
-
lastSeenAt:
|
|
2855
|
+
lastSeenAt: sql6`MAX(${juniorConversations.lastActivityAt})`.mapWith(
|
|
2723
2856
|
juniorConversations.lastActivityAt
|
|
2724
2857
|
)
|
|
2725
2858
|
};
|
|
2726
2859
|
}
|
|
2727
2860
|
function conversationActiveDaysColumn() {
|
|
2728
|
-
return
|
|
2861
|
+
return sql6`COUNT(DISTINCT (${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC')::date)::integer`;
|
|
2729
2862
|
}
|
|
2730
2863
|
|
|
2731
2864
|
// src/api/conversations/stats.query.ts
|
|
@@ -2789,7 +2922,7 @@ function statsItems(map) {
|
|
|
2789
2922
|
);
|
|
2790
2923
|
}
|
|
2791
2924
|
function statsWhere(start, end) {
|
|
2792
|
-
return
|
|
2925
|
+
return and10(
|
|
2793
2926
|
isNull4(juniorConversations.parentConversationId),
|
|
2794
2927
|
gte(juniorConversations.lastActivityAt, start),
|
|
2795
2928
|
lte(juniorConversations.lastActivityAt, end)
|
|
@@ -2866,14 +2999,14 @@ function guardianStats(rows, endMs) {
|
|
|
2866
2999
|
}
|
|
2867
3000
|
async function aggregateStats(db, start, end) {
|
|
2868
3001
|
const where = statsWhere(start, end);
|
|
2869
|
-
const activityDate =
|
|
3002
|
+
const activityDate = sql7`TO_CHAR(
|
|
2870
3003
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
2871
3004
|
'YYYY-MM-DD'
|
|
2872
3005
|
)`;
|
|
2873
3006
|
const [totalsRows, actorRows, locationRows, metricRows] = await Promise.all([
|
|
2874
3007
|
db.select(treeAggregateColumns).from(juniorConversations).innerJoin(
|
|
2875
3008
|
treeConversation,
|
|
2876
|
-
|
|
3009
|
+
eq11(
|
|
2877
3010
|
treeConversation.rootConversationId,
|
|
2878
3011
|
juniorConversations.conversationId
|
|
2879
3012
|
)
|
|
@@ -2888,14 +3021,14 @@ async function aggregateStats(db, start, end) {
|
|
|
2888
3021
|
...treeAggregateColumns
|
|
2889
3022
|
}).from(juniorConversations).innerJoin(
|
|
2890
3023
|
treeConversation,
|
|
2891
|
-
|
|
3024
|
+
eq11(
|
|
2892
3025
|
treeConversation.rootConversationId,
|
|
2893
3026
|
juniorConversations.conversationId
|
|
2894
3027
|
)
|
|
2895
3028
|
).leftJoin(
|
|
2896
3029
|
juniorIdentities,
|
|
2897
|
-
|
|
2898
|
-
).leftJoin(juniorUsers,
|
|
3030
|
+
eq11(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3031
|
+
).leftJoin(juniorUsers, eq11(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
|
|
2899
3032
|
juniorIdentities.displayName,
|
|
2900
3033
|
juniorIdentities.emailNormalized,
|
|
2901
3034
|
juniorIdentities.handle,
|
|
@@ -2913,13 +3046,13 @@ async function aggregateStats(db, start, end) {
|
|
|
2913
3046
|
...treeAggregateColumns
|
|
2914
3047
|
}).from(juniorConversations).innerJoin(
|
|
2915
3048
|
treeConversation,
|
|
2916
|
-
|
|
3049
|
+
eq11(
|
|
2917
3050
|
treeConversation.rootConversationId,
|
|
2918
3051
|
juniorConversations.conversationId
|
|
2919
3052
|
)
|
|
2920
3053
|
).leftJoin(
|
|
2921
3054
|
juniorDestinations,
|
|
2922
|
-
|
|
3055
|
+
eq11(juniorDestinations.id, juniorConversations.destinationId)
|
|
2923
3056
|
).where(where).groupBy(
|
|
2924
3057
|
juniorConversations.channelName,
|
|
2925
3058
|
juniorConversations.source,
|
|
@@ -2938,7 +3071,7 @@ async function aggregateStats(db, start, end) {
|
|
|
2938
3071
|
tokens: treeAggregateColumns.tokens
|
|
2939
3072
|
}).from(juniorConversations).innerJoin(
|
|
2940
3073
|
treeConversation,
|
|
2941
|
-
|
|
3074
|
+
eq11(
|
|
2942
3075
|
treeConversation.rootConversationId,
|
|
2943
3076
|
juniorConversations.conversationId
|
|
2944
3077
|
)
|
|
@@ -2947,26 +3080,26 @@ async function aggregateStats(db, start, end) {
|
|
|
2947
3080
|
return { actorRows, locationRows, metricRows, totals: totalsRows[0] };
|
|
2948
3081
|
}
|
|
2949
3082
|
async function aggregateGuardianStats(db, start, end) {
|
|
2950
|
-
const date =
|
|
3083
|
+
const date = sql7`TO_CHAR(
|
|
2951
3084
|
${juniorConversationEvents.createdAt} AT TIME ZONE 'UTC',
|
|
2952
3085
|
'YYYY-MM-DD'
|
|
2953
3086
|
)`;
|
|
2954
|
-
const decision =
|
|
2955
|
-
const cost2 =
|
|
3087
|
+
const decision = sql7`${juniorConversationEvents.payload}->>'decision'`;
|
|
3088
|
+
const cost2 = sql7`CASE
|
|
2956
3089
|
WHEN jsonb_typeof(${juniorConversationEvents.payload}->'costUsd') = 'number'
|
|
2957
3090
|
THEN (${juniorConversationEvents.payload}->>'costUsd')::double precision
|
|
2958
3091
|
ELSE NULL
|
|
2959
3092
|
END`;
|
|
2960
3093
|
return await db.select({
|
|
2961
|
-
allow:
|
|
2962
|
-
ask:
|
|
2963
|
-
costUsd:
|
|
3094
|
+
allow: sql7`COUNT(*) FILTER (WHERE ${decision} = 'allow')::integer`,
|
|
3095
|
+
ask: sql7`COUNT(*) FILTER (WHERE ${decision} = 'ask')::integer`,
|
|
3096
|
+
costUsd: sql7`SUM(${cost2})::double precision`,
|
|
2964
3097
|
date,
|
|
2965
|
-
deny:
|
|
2966
|
-
requests:
|
|
3098
|
+
deny: sql7`COUNT(*) FILTER (WHERE ${decision} = 'deny')::integer`,
|
|
3099
|
+
requests: sql7`COUNT(*)::integer`
|
|
2967
3100
|
}).from(juniorConversationEvents).where(
|
|
2968
|
-
|
|
2969
|
-
|
|
3101
|
+
and10(
|
|
3102
|
+
eq11(juniorConversationEvents.type, "guardian_action_reviewed"),
|
|
2970
3103
|
gte(juniorConversationEvents.createdAt, start),
|
|
2971
3104
|
lte(juniorConversationEvents.createdAt, end)
|
|
2972
3105
|
)
|
|
@@ -3016,7 +3149,7 @@ async function readConversationStats() {
|
|
|
3016
3149
|
}
|
|
3017
3150
|
|
|
3018
3151
|
// src/api/conversations/routes.ts
|
|
3019
|
-
function createConversationRoutes() {
|
|
3152
|
+
function createConversationRoutes(options) {
|
|
3020
3153
|
const app = new Hono();
|
|
3021
3154
|
app.get(
|
|
3022
3155
|
"/",
|
|
@@ -3144,6 +3277,31 @@ function createConversationRoutes() {
|
|
|
3144
3277
|
);
|
|
3145
3278
|
}
|
|
3146
3279
|
);
|
|
3280
|
+
app.get(
|
|
3281
|
+
"/:conversationId/attachments/:attachmentId",
|
|
3282
|
+
validateRequest(
|
|
3283
|
+
"param",
|
|
3284
|
+
conversationAttachmentParamsSchema,
|
|
3285
|
+
"Invalid route parameters."
|
|
3286
|
+
),
|
|
3287
|
+
async (context) => {
|
|
3288
|
+
const { attachmentId, conversationId } = context.req.valid("param");
|
|
3289
|
+
const viewer = context.get("viewer");
|
|
3290
|
+
const opened = await requireConversationAttachment({
|
|
3291
|
+
attachmentId,
|
|
3292
|
+
conversationId,
|
|
3293
|
+
storage: options.attachmentStorage,
|
|
3294
|
+
...viewer ? { viewer } : {}
|
|
3295
|
+
});
|
|
3296
|
+
return new Response(opened.body, {
|
|
3297
|
+
headers: conversationAttachmentHeaders({
|
|
3298
|
+
bytes: opened.attachment.bytes,
|
|
3299
|
+
contentType: opened.attachment.contentType,
|
|
3300
|
+
filename: opened.attachment.filename
|
|
3301
|
+
})
|
|
3302
|
+
});
|
|
3303
|
+
}
|
|
3304
|
+
);
|
|
3147
3305
|
app.get(
|
|
3148
3306
|
"/:conversationId",
|
|
3149
3307
|
validateRequest(
|
|
@@ -3175,7 +3333,7 @@ function createConversationRoutes() {
|
|
|
3175
3333
|
import { Hono as Hono2 } from "hono";
|
|
3176
3334
|
|
|
3177
3335
|
// src/api/locations/query.ts
|
|
3178
|
-
import { and as
|
|
3336
|
+
import { and as and11, asc as asc3, desc as desc3, eq as eq12, gte as gte2, isNull as isNull5, sql as sql8 } from "drizzle-orm";
|
|
3179
3337
|
import { alias as alias5 } from "drizzle-orm/pg-core";
|
|
3180
3338
|
|
|
3181
3339
|
// src/api/conversations/reporting.ts
|
|
@@ -3283,10 +3441,10 @@ function topLevelWhere() {
|
|
|
3283
3441
|
return isNull5(juniorConversations.parentConversationId);
|
|
3284
3442
|
}
|
|
3285
3443
|
function publicLocationWhere(destinationId) {
|
|
3286
|
-
return
|
|
3444
|
+
return and11(
|
|
3287
3445
|
topLevelWhere(),
|
|
3288
|
-
|
|
3289
|
-
|
|
3446
|
+
eq12(juniorDestinations.id, destinationId),
|
|
3447
|
+
eq12(juniorDestinations.visibility, "public")
|
|
3290
3448
|
);
|
|
3291
3449
|
}
|
|
3292
3450
|
function locationColumns() {
|
|
@@ -3337,28 +3495,28 @@ async function directoryRows(db) {
|
|
|
3337
3495
|
...conversationRangeColumns()
|
|
3338
3496
|
}).from(juniorConversations).innerJoin(
|
|
3339
3497
|
treeConversation2,
|
|
3340
|
-
|
|
3498
|
+
eq12(
|
|
3341
3499
|
treeConversation2.rootConversationId,
|
|
3342
3500
|
juniorConversations.conversationId
|
|
3343
3501
|
)
|
|
3344
3502
|
).leftJoin(
|
|
3345
3503
|
juniorDestinations,
|
|
3346
|
-
|
|
3504
|
+
eq12(juniorDestinations.id, juniorConversations.destinationId)
|
|
3347
3505
|
).where(topLevelWhere()).groupBy(...locationGroupBy());
|
|
3348
3506
|
}
|
|
3349
3507
|
async function directoryActivityRows(db, start) {
|
|
3350
|
-
const date =
|
|
3508
|
+
const date = sql8`TO_CHAR(
|
|
3351
3509
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3352
3510
|
'YYYY-MM-DD'
|
|
3353
3511
|
)`;
|
|
3354
3512
|
return db.select({
|
|
3355
|
-
conversations:
|
|
3513
|
+
conversations: sql8`COUNT(*)::integer`,
|
|
3356
3514
|
date,
|
|
3357
3515
|
visibility: juniorDestinations.visibility
|
|
3358
3516
|
}).from(juniorConversations).leftJoin(
|
|
3359
3517
|
juniorDestinations,
|
|
3360
|
-
|
|
3361
|
-
).where(
|
|
3518
|
+
eq12(juniorDestinations.id, juniorConversations.destinationId)
|
|
3519
|
+
).where(and11(topLevelWhere(), gte2(juniorConversations.lastActivityAt, start))).groupBy(date, juniorDestinations.visibility);
|
|
3362
3520
|
}
|
|
3363
3521
|
function directoryActivityDays(rows, nowMs) {
|
|
3364
3522
|
const days = /* @__PURE__ */ new Map();
|
|
@@ -3431,7 +3589,7 @@ async function recentLocationRows(db, locationId) {
|
|
|
3431
3589
|
createdAt: juniorConversations.createdAt,
|
|
3432
3590
|
destinationId: juniorDestinations.id,
|
|
3433
3591
|
durationMs: juniorConversations.durationMs,
|
|
3434
|
-
email:
|
|
3592
|
+
email: sql8`COALESCE(
|
|
3435
3593
|
${juniorUsers.primaryEmailNormalized},
|
|
3436
3594
|
${juniorIdentities.email}
|
|
3437
3595
|
)`,
|
|
@@ -3440,7 +3598,7 @@ async function recentLocationRows(db, locationId) {
|
|
|
3440
3598
|
fullName: juniorUsers.displayName,
|
|
3441
3599
|
handle: juniorIdentities.handle,
|
|
3442
3600
|
lastActivityAt: juniorConversations.lastActivityAt,
|
|
3443
|
-
providerSubjectId:
|
|
3601
|
+
providerSubjectId: sql8`CASE
|
|
3444
3602
|
WHEN ${juniorIdentities.provider} = 'slack'
|
|
3445
3603
|
THEN ${juniorIdentities.providerSubjectId}
|
|
3446
3604
|
ELSE NULL
|
|
@@ -3451,12 +3609,12 @@ async function recentLocationRows(db, locationId) {
|
|
|
3451
3609
|
usage: juniorConversations.usage
|
|
3452
3610
|
}).from(juniorConversations).innerJoin(
|
|
3453
3611
|
juniorDestinations,
|
|
3454
|
-
|
|
3612
|
+
eq12(juniorDestinations.id, juniorConversations.destinationId)
|
|
3455
3613
|
).leftJoin(
|
|
3456
3614
|
juniorIdentities,
|
|
3457
|
-
|
|
3458
|
-
).leftJoin(juniorUsers,
|
|
3459
|
-
|
|
3615
|
+
eq12(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3616
|
+
).leftJoin(juniorUsers, eq12(juniorUsers.id, juniorIdentities.userId)).where(
|
|
3617
|
+
and11(
|
|
3460
3618
|
publicLocationWhere(locationId),
|
|
3461
3619
|
isNull5(juniorConversations.archivedAt)
|
|
3462
3620
|
)
|
|
@@ -3472,7 +3630,7 @@ async function readLocationDetailFromSql(locationId, options = {}) {
|
|
|
3472
3630
|
const start = new Date(end);
|
|
3473
3631
|
start.setUTCDate(start.getUTCDate() - (ACTIVITY_DAYS - 1));
|
|
3474
3632
|
const where = publicLocationWhere(locationId);
|
|
3475
|
-
const activityDate =
|
|
3633
|
+
const activityDate = sql8`TO_CHAR(
|
|
3476
3634
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3477
3635
|
'YYYY-MM-DD'
|
|
3478
3636
|
)`;
|
|
@@ -3483,27 +3641,27 @@ async function readLocationDetailFromSql(locationId, options = {}) {
|
|
|
3483
3641
|
...conversationRangeColumns()
|
|
3484
3642
|
}).from(juniorConversations).innerJoin(
|
|
3485
3643
|
treeConversation2,
|
|
3486
|
-
|
|
3644
|
+
eq12(
|
|
3487
3645
|
treeConversation2.rootConversationId,
|
|
3488
3646
|
juniorConversations.conversationId
|
|
3489
3647
|
)
|
|
3490
3648
|
).innerJoin(
|
|
3491
3649
|
juniorDestinations,
|
|
3492
|
-
|
|
3650
|
+
eq12(juniorDestinations.id, juniorConversations.destinationId)
|
|
3493
3651
|
).where(where).groupBy(...locationGroupBy()),
|
|
3494
3652
|
getDb().select({
|
|
3495
3653
|
date: activityDate,
|
|
3496
3654
|
...treeAggregateColumns2
|
|
3497
3655
|
}).from(juniorConversations).innerJoin(
|
|
3498
3656
|
treeConversation2,
|
|
3499
|
-
|
|
3657
|
+
eq12(
|
|
3500
3658
|
treeConversation2.rootConversationId,
|
|
3501
3659
|
juniorConversations.conversationId
|
|
3502
3660
|
)
|
|
3503
3661
|
).innerJoin(
|
|
3504
3662
|
juniorDestinations,
|
|
3505
|
-
|
|
3506
|
-
).where(
|
|
3663
|
+
eq12(juniorDestinations.id, juniorConversations.destinationId)
|
|
3664
|
+
).where(and11(where, gte2(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
|
|
3507
3665
|
getDb().select({
|
|
3508
3666
|
actorIdentityId: juniorConversations.actorIdentityId,
|
|
3509
3667
|
email: juniorUsers.primaryEmailNormalized,
|
|
@@ -3515,17 +3673,17 @@ async function readLocationDetailFromSql(locationId, options = {}) {
|
|
|
3515
3673
|
...treeAggregateColumns2
|
|
3516
3674
|
}).from(juniorConversations).innerJoin(
|
|
3517
3675
|
treeConversation2,
|
|
3518
|
-
|
|
3676
|
+
eq12(
|
|
3519
3677
|
treeConversation2.rootConversationId,
|
|
3520
3678
|
juniorConversations.conversationId
|
|
3521
3679
|
)
|
|
3522
3680
|
).innerJoin(
|
|
3523
3681
|
juniorDestinations,
|
|
3524
|
-
|
|
3682
|
+
eq12(juniorDestinations.id, juniorConversations.destinationId)
|
|
3525
3683
|
).leftJoin(
|
|
3526
3684
|
juniorIdentities,
|
|
3527
|
-
|
|
3528
|
-
).leftJoin(juniorUsers,
|
|
3685
|
+
eq12(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3686
|
+
).leftJoin(juniorUsers, eq12(juniorUsers.id, juniorIdentities.userId)).where(where).groupBy(
|
|
3529
3687
|
juniorConversations.actorIdentityId,
|
|
3530
3688
|
juniorUsers.primaryEmailNormalized,
|
|
3531
3689
|
juniorUsers.displayName,
|
|
@@ -3638,10 +3796,10 @@ function createLocationRoutes() {
|
|
|
3638
3796
|
import { Hono as Hono3 } from "hono";
|
|
3639
3797
|
|
|
3640
3798
|
// src/api/people/list.query.ts
|
|
3641
|
-
import { and as
|
|
3799
|
+
import { and as and13, eq as eq14, gte as gte3, sql as sql10 } from "drizzle-orm";
|
|
3642
3800
|
|
|
3643
3801
|
// src/api/people/shared.ts
|
|
3644
|
-
import { and as
|
|
3802
|
+
import { and as and12, asc as asc4, desc as desc4, eq as eq13, isNull as isNull6, notExists, or as or5, sql as sql9 } from "drizzle-orm";
|
|
3645
3803
|
import { alias as alias6 } from "drizzle-orm/pg-core";
|
|
3646
3804
|
var RECENT_LIMIT2 = 25;
|
|
3647
3805
|
var ACTIVITY_DAYS2 = 365;
|
|
@@ -3661,37 +3819,37 @@ var peopleTreeAggregateColumns = conversationAggregateColumns({
|
|
|
3661
3819
|
function peopleTreeMetricsJoin() {
|
|
3662
3820
|
const rootOwnedByActor = getDb().select({ conversationId: peopleRootConversation.conversationId }).from(peopleRootConversation).innerJoin(
|
|
3663
3821
|
peopleRootIdentity,
|
|
3664
|
-
|
|
3822
|
+
eq13(peopleRootIdentity.id, peopleRootConversation.actorIdentityId)
|
|
3665
3823
|
).where(
|
|
3666
|
-
|
|
3667
|
-
|
|
3824
|
+
and12(
|
|
3825
|
+
eq13(
|
|
3668
3826
|
peopleRootConversation.conversationId,
|
|
3669
3827
|
juniorConversations.rootConversationId
|
|
3670
3828
|
),
|
|
3671
3829
|
isNull6(peopleRootConversation.parentConversationId),
|
|
3672
|
-
|
|
3830
|
+
eq13(
|
|
3673
3831
|
peopleRootConversation.rootConversationId,
|
|
3674
3832
|
peopleRootConversation.conversationId
|
|
3675
3833
|
),
|
|
3676
|
-
|
|
3834
|
+
eq13(
|
|
3677
3835
|
peopleRootIdentity.emailNormalized,
|
|
3678
3836
|
juniorUsers.primaryEmailNormalized
|
|
3679
3837
|
),
|
|
3680
|
-
|
|
3838
|
+
eq13(peopleRootIdentity.emailVerified, true)
|
|
3681
3839
|
)
|
|
3682
3840
|
);
|
|
3683
|
-
return
|
|
3684
|
-
|
|
3841
|
+
return and12(
|
|
3842
|
+
eq13(
|
|
3685
3843
|
peopleTreeConversation.rootConversationId,
|
|
3686
3844
|
juniorConversations.rootConversationId
|
|
3687
3845
|
),
|
|
3688
|
-
|
|
3689
|
-
|
|
3846
|
+
or5(
|
|
3847
|
+
eq13(
|
|
3690
3848
|
juniorConversations.rootConversationId,
|
|
3691
3849
|
juniorConversations.conversationId
|
|
3692
3850
|
),
|
|
3693
|
-
|
|
3694
|
-
|
|
3851
|
+
and12(
|
|
3852
|
+
eq13(
|
|
3695
3853
|
peopleTreeConversation.conversationId,
|
|
3696
3854
|
juniorConversations.conversationId
|
|
3697
3855
|
),
|
|
@@ -3741,11 +3899,11 @@ function statsItems2(map) {
|
|
|
3741
3899
|
}
|
|
3742
3900
|
function verifiedActorWhere(email) {
|
|
3743
3901
|
const normalizedEmail = normalizeEmail(email);
|
|
3744
|
-
return
|
|
3745
|
-
|
|
3746
|
-
|
|
3747
|
-
|
|
3748
|
-
normalizedEmail ?
|
|
3902
|
+
return and12(
|
|
3903
|
+
eq13(juniorIdentities.provider, "slack"),
|
|
3904
|
+
eq13(juniorIdentities.emailVerified, true),
|
|
3905
|
+
sql9`${juniorUsers.primaryEmailNormalized} IS NOT NULL`,
|
|
3906
|
+
normalizedEmail ? eq13(juniorUsers.primaryEmailNormalized, normalizedEmail) : void 0
|
|
3749
3907
|
);
|
|
3750
3908
|
}
|
|
3751
3909
|
async function recentActorRows(email) {
|
|
@@ -3768,12 +3926,12 @@ async function recentActorRows(email) {
|
|
|
3768
3926
|
usage: juniorConversations.usage
|
|
3769
3927
|
}).from(juniorConversations).innerJoin(
|
|
3770
3928
|
juniorIdentities,
|
|
3771
|
-
|
|
3772
|
-
).innerJoin(juniorUsers,
|
|
3929
|
+
eq13(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3930
|
+
).innerJoin(juniorUsers, eq13(juniorUsers.id, juniorIdentities.userId)).leftJoin(
|
|
3773
3931
|
juniorDestinations,
|
|
3774
|
-
|
|
3932
|
+
eq13(juniorDestinations.id, juniorConversations.destinationId)
|
|
3775
3933
|
).where(
|
|
3776
|
-
|
|
3934
|
+
and12(verifiedActorWhere(email), isNull6(juniorConversations.archivedAt))
|
|
3777
3935
|
).orderBy(
|
|
3778
3936
|
desc4(juniorConversations.lastActivityAt),
|
|
3779
3937
|
asc4(juniorConversations.conversationId)
|
|
@@ -3802,7 +3960,7 @@ function directoryActivityDays2(rows, nowMs) {
|
|
|
3802
3960
|
async function readPeopleListFromSql() {
|
|
3803
3961
|
const nowMs = Date.now();
|
|
3804
3962
|
const { end, start } = activityWindow(nowMs);
|
|
3805
|
-
const activityDate =
|
|
3963
|
+
const activityDate = sql10`TO_CHAR(
|
|
3806
3964
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3807
3965
|
'YYYY-MM-DD'
|
|
3808
3966
|
)`;
|
|
@@ -3810,24 +3968,24 @@ async function readPeopleListFromSql() {
|
|
|
3810
3968
|
getDb().select({
|
|
3811
3969
|
email: juniorUsers.primaryEmailNormalized,
|
|
3812
3970
|
fullName: juniorUsers.displayName,
|
|
3813
|
-
slackUserId:
|
|
3814
|
-
slackUserName:
|
|
3971
|
+
slackUserId: sql10`MAX(${juniorIdentities.providerSubjectId})`,
|
|
3972
|
+
slackUserName: sql10`MAX(${juniorIdentities.handle})`,
|
|
3815
3973
|
activeDays: conversationActiveDaysColumn(),
|
|
3816
3974
|
...peopleTreeAggregateColumns,
|
|
3817
3975
|
...conversationRangeColumns()
|
|
3818
3976
|
}).from(juniorConversations).innerJoin(
|
|
3819
3977
|
juniorIdentities,
|
|
3820
|
-
|
|
3821
|
-
).innerJoin(juniorUsers,
|
|
3978
|
+
eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3979
|
+
).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, peopleTreeMetricsJoin()).where(verifiedActorWhere()).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
|
|
3822
3980
|
getDb().select({
|
|
3823
|
-
activePeople:
|
|
3824
|
-
conversations:
|
|
3981
|
+
activePeople: sql10`COUNT(DISTINCT ${juniorUsers.id})::int`,
|
|
3982
|
+
conversations: sql10`COUNT(*)::int`,
|
|
3825
3983
|
date: activityDate
|
|
3826
3984
|
}).from(juniorConversations).innerJoin(
|
|
3827
3985
|
juniorIdentities,
|
|
3828
|
-
|
|
3829
|
-
).innerJoin(juniorUsers,
|
|
3830
|
-
|
|
3986
|
+
eq14(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
3987
|
+
).innerJoin(juniorUsers, eq14(juniorUsers.id, juniorIdentities.userId)).where(
|
|
3988
|
+
and13(
|
|
3831
3989
|
verifiedActorWhere(),
|
|
3832
3990
|
gte3(juniorConversations.lastActivityAt, start)
|
|
3833
3991
|
)
|
|
@@ -3870,7 +4028,7 @@ async function readPeopleList() {
|
|
|
3870
4028
|
}
|
|
3871
4029
|
|
|
3872
4030
|
// src/api/people/profile.query.ts
|
|
3873
|
-
import { and as
|
|
4031
|
+
import { and as and14, eq as eq15, gte as gte4, sql as sql11 } from "drizzle-orm";
|
|
3874
4032
|
function emptyProfile(email, nowMs) {
|
|
3875
4033
|
const end = new Date(nowMs);
|
|
3876
4034
|
end.setUTCHours(0, 0, 0, 0);
|
|
@@ -3905,7 +4063,7 @@ function addAggregate2(map, label, row) {
|
|
|
3905
4063
|
map.set(label, item);
|
|
3906
4064
|
}
|
|
3907
4065
|
function surfaceExpression() {
|
|
3908
|
-
return
|
|
4066
|
+
return sql11`CASE
|
|
3909
4067
|
WHEN ${juniorConversations.source} IN ('api', 'scheduler', 'slack')
|
|
3910
4068
|
THEN ${juniorConversations.source}
|
|
3911
4069
|
WHEN ${juniorConversations.conversationId} LIKE 'slack:%' THEN 'slack'
|
|
@@ -3934,30 +4092,30 @@ async function readPeopleProfileFromSql(email, options = {}) {
|
|
|
3934
4092
|
const where = verifiedActorWhere(normalizedEmail);
|
|
3935
4093
|
const metricsJoin = peopleTreeMetricsJoin();
|
|
3936
4094
|
const surface = surfaceExpression();
|
|
3937
|
-
const activityDate =
|
|
4095
|
+
const activityDate = sql11`TO_CHAR(
|
|
3938
4096
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
3939
4097
|
'YYYY-MM-DD'
|
|
3940
4098
|
)`;
|
|
3941
|
-
const channel =
|
|
4099
|
+
const channel = sql11`SPLIT_PART(${juniorConversations.conversationId}, ':', 2)`;
|
|
3942
4100
|
const [totalsRows, dayRows, locationRows, surfaceRows, recentRows] = await Promise.all([
|
|
3943
4101
|
getDb().select({
|
|
3944
4102
|
email: juniorUsers.primaryEmailNormalized,
|
|
3945
4103
|
fullName: juniorUsers.displayName,
|
|
3946
|
-
slackUserId:
|
|
3947
|
-
slackUserName:
|
|
4104
|
+
slackUserId: sql11`MAX(${juniorIdentities.providerSubjectId})`,
|
|
4105
|
+
slackUserName: sql11`MAX(${juniorIdentities.handle})`,
|
|
3948
4106
|
activeDays: conversationActiveDaysColumn(),
|
|
3949
4107
|
...peopleTreeAggregateColumns
|
|
3950
4108
|
}).from(juniorConversations).innerJoin(
|
|
3951
4109
|
juniorIdentities,
|
|
3952
|
-
|
|
3953
|
-
).innerJoin(juniorUsers,
|
|
4110
|
+
eq15(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
4111
|
+
).innerJoin(juniorUsers, eq15(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(where).groupBy(juniorUsers.primaryEmailNormalized, juniorUsers.displayName),
|
|
3954
4112
|
getDb().select({
|
|
3955
4113
|
date: activityDate,
|
|
3956
4114
|
...peopleTreeAggregateColumns
|
|
3957
4115
|
}).from(juniorConversations).innerJoin(
|
|
3958
4116
|
juniorIdentities,
|
|
3959
|
-
|
|
3960
|
-
).innerJoin(juniorUsers,
|
|
4117
|
+
eq15(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
4118
|
+
).innerJoin(juniorUsers, eq15(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(and14(where, gte4(juniorConversations.lastActivityAt, start))).groupBy(activityDate),
|
|
3961
4119
|
getDb().select({
|
|
3962
4120
|
channel,
|
|
3963
4121
|
channelName: juniorConversations.channelName,
|
|
@@ -3966,10 +4124,10 @@ async function readPeopleProfileFromSql(email, options = {}) {
|
|
|
3966
4124
|
...peopleTreeAggregateColumns
|
|
3967
4125
|
}).from(juniorConversations).innerJoin(
|
|
3968
4126
|
juniorIdentities,
|
|
3969
|
-
|
|
3970
|
-
).innerJoin(juniorUsers,
|
|
4127
|
+
eq15(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
4128
|
+
).innerJoin(juniorUsers, eq15(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).leftJoin(
|
|
3971
4129
|
juniorDestinations,
|
|
3972
|
-
|
|
4130
|
+
eq15(juniorDestinations.id, juniorConversations.destinationId)
|
|
3973
4131
|
).where(where).groupBy(
|
|
3974
4132
|
channel,
|
|
3975
4133
|
juniorConversations.channelName,
|
|
@@ -3978,8 +4136,8 @@ async function readPeopleProfileFromSql(email, options = {}) {
|
|
|
3978
4136
|
),
|
|
3979
4137
|
getDb().select({ surface, ...peopleTreeAggregateColumns }).from(juniorConversations).innerJoin(
|
|
3980
4138
|
juniorIdentities,
|
|
3981
|
-
|
|
3982
|
-
).innerJoin(juniorUsers,
|
|
4139
|
+
eq15(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
4140
|
+
).innerJoin(juniorUsers, eq15(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(where).groupBy(surface),
|
|
3983
4141
|
recentActorRows(normalizedEmail)
|
|
3984
4142
|
]);
|
|
3985
4143
|
const totalsRow = totalsRows[0];
|
|
@@ -4057,7 +4215,7 @@ async function readPeopleProfile(email, options = {}) {
|
|
|
4057
4215
|
}
|
|
4058
4216
|
|
|
4059
4217
|
// src/api/people/spend.query.ts
|
|
4060
|
-
import { and as
|
|
4218
|
+
import { and as and15, eq as eq16, gte as gte5, lte as lte2, sql as sql12 } from "drizzle-orm";
|
|
4061
4219
|
var SEVEN_DAY_OFFSET = 6;
|
|
4062
4220
|
var THIRTY_DAY_OFFSET = 29;
|
|
4063
4221
|
function addUsd2(current, next) {
|
|
@@ -4076,7 +4234,7 @@ function spendWindow(nowMs) {
|
|
|
4076
4234
|
async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
|
|
4077
4235
|
const normalizedEmail = normalizeEmail(email);
|
|
4078
4236
|
const { end, sevenDayStart, thirtyDayStart } = spendWindow(nowMs);
|
|
4079
|
-
const activityDate =
|
|
4237
|
+
const activityDate = sql12`TO_CHAR(
|
|
4080
4238
|
${juniorConversations.lastActivityAt} AT TIME ZONE 'UTC',
|
|
4081
4239
|
'YYYY-MM-DD'
|
|
4082
4240
|
)`;
|
|
@@ -4086,9 +4244,9 @@ async function readPersonalSpendFromSql(email, nowMs = Date.now()) {
|
|
|
4086
4244
|
date: activityDate
|
|
4087
4245
|
}).from(juniorConversations).innerJoin(
|
|
4088
4246
|
juniorIdentities,
|
|
4089
|
-
|
|
4090
|
-
).innerJoin(juniorUsers,
|
|
4091
|
-
|
|
4247
|
+
eq16(juniorIdentities.id, juniorConversations.actorIdentityId)
|
|
4248
|
+
).innerJoin(juniorUsers, eq16(juniorUsers.id, juniorIdentities.userId)).leftJoin(peopleTreeConversation, metricsJoin).where(
|
|
4249
|
+
and15(
|
|
4092
4250
|
verifiedActorWhere(normalizedEmail),
|
|
4093
4251
|
gte5(juniorConversations.lastActivityAt, thirtyDayStart),
|
|
4094
4252
|
lte2(juniorConversations.lastActivityAt, end)
|
|
@@ -4176,7 +4334,7 @@ import { Hono as Hono4 } from "hono";
|
|
|
4176
4334
|
|
|
4177
4335
|
// src/personal-tokens/store.ts
|
|
4178
4336
|
import { createHash, randomBytes, randomUUID } from "crypto";
|
|
4179
|
-
import { and as
|
|
4337
|
+
import { and as and16, desc as desc5, eq as eq17, gt, isNull as isNull7 } from "drizzle-orm";
|
|
4180
4338
|
var TOKEN_PREFIX = "jr_pat_";
|
|
4181
4339
|
var TOKEN_SUFFIX_LENGTH = 8;
|
|
4182
4340
|
var DEFAULT_TOKEN_LIFETIME_MS = 90 * 24 * 60 * 60 * 1e3;
|
|
@@ -4213,8 +4371,8 @@ async function createPersonalToken(args) {
|
|
|
4213
4371
|
}
|
|
4214
4372
|
async function listPersonalTokens(email, now = /* @__PURE__ */ new Date()) {
|
|
4215
4373
|
const rows = await getDb().select().from(juniorApiTokens).where(
|
|
4216
|
-
|
|
4217
|
-
|
|
4374
|
+
and16(
|
|
4375
|
+
eq17(juniorApiTokens.ownerEmailNormalized, normalizeEmail2(email)),
|
|
4218
4376
|
isNull7(juniorApiTokens.revokedAt),
|
|
4219
4377
|
gt(juniorApiTokens.expiresAt, now)
|
|
4220
4378
|
)
|
|
@@ -4223,9 +4381,9 @@ async function listPersonalTokens(email, now = /* @__PURE__ */ new Date()) {
|
|
|
4223
4381
|
}
|
|
4224
4382
|
async function revokePersonalToken(args) {
|
|
4225
4383
|
const rows = await getDb().update(juniorApiTokens).set({ revokedAt: args.now ?? /* @__PURE__ */ new Date() }).where(
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4384
|
+
and16(
|
|
4385
|
+
eq17(juniorApiTokens.id, args.id),
|
|
4386
|
+
eq17(juniorApiTokens.ownerEmailNormalized, normalizeEmail2(args.email)),
|
|
4229
4387
|
isNull7(juniorApiTokens.revokedAt)
|
|
4230
4388
|
)
|
|
4231
4389
|
).returning({ id: juniorApiTokens.id });
|
|
@@ -4237,15 +4395,15 @@ async function authenticatePersonalToken(token2, now = /* @__PURE__ */ new Date(
|
|
|
4237
4395
|
id: juniorApiTokens.id,
|
|
4238
4396
|
ownerEmailNormalized: juniorApiTokens.ownerEmailNormalized
|
|
4239
4397
|
}).from(juniorApiTokens).where(
|
|
4240
|
-
|
|
4241
|
-
|
|
4398
|
+
and16(
|
|
4399
|
+
eq17(juniorApiTokens.tokenHash, hashToken(token2)),
|
|
4242
4400
|
isNull7(juniorApiTokens.revokedAt),
|
|
4243
4401
|
gt(juniorApiTokens.expiresAt, now)
|
|
4244
4402
|
)
|
|
4245
4403
|
).limit(1);
|
|
4246
4404
|
const match = rows[0];
|
|
4247
4405
|
if (!match) return void 0;
|
|
4248
|
-
await getDb().update(juniorApiTokens).set({ lastUsedAt: now }).where(
|
|
4406
|
+
await getDb().update(juniorApiTokens).set({ lastUsedAt: now }).where(eq17(juniorApiTokens.id, match.id));
|
|
4249
4407
|
return match.ownerEmailNormalized;
|
|
4250
4408
|
}
|
|
4251
4409
|
|
|
@@ -4502,7 +4660,7 @@ function readDescriptionText(home) {
|
|
|
4502
4660
|
}
|
|
4503
4661
|
}
|
|
4504
4662
|
async function readSkillReports() {
|
|
4505
|
-
const { discoverSkills } = await import("./skills-
|
|
4663
|
+
const { discoverSkills } = await import("./skills-WZWKZIFQ.js");
|
|
4506
4664
|
const skills = await discoverSkills();
|
|
4507
4665
|
return skillReportsSchema.parse(
|
|
4508
4666
|
skills.map((skill) => ({
|
|
@@ -4512,7 +4670,7 @@ async function readSkillReports() {
|
|
|
4512
4670
|
);
|
|
4513
4671
|
}
|
|
4514
4672
|
async function readPlugins() {
|
|
4515
|
-
const { pluginCatalogRuntime } = await import("./catalog-runtime-
|
|
4673
|
+
const { pluginCatalogRuntime } = await import("./catalog-runtime-7GZ25WTR.js");
|
|
4516
4674
|
return pluginsSchema.parse(
|
|
4517
4675
|
pluginCatalogRuntime.getProviders().map((plugin) => ({
|
|
4518
4676
|
configKeys: plugin.manifest.configKeys ?? [],
|
|
@@ -4525,7 +4683,7 @@ async function readPlugins() {
|
|
|
4525
4683
|
async function readRuntimeInfoReport() {
|
|
4526
4684
|
const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
|
|
4527
4685
|
import("./discovery-GUFTFBTL.js"),
|
|
4528
|
-
import("./catalog-runtime-
|
|
4686
|
+
import("./catalog-runtime-7GZ25WTR.js"),
|
|
4529
4687
|
readPlugins(),
|
|
4530
4688
|
readSkillReports()
|
|
4531
4689
|
]);
|
|
@@ -4541,7 +4699,7 @@ async function readRuntimeInfoReport() {
|
|
|
4541
4699
|
}
|
|
4542
4700
|
async function readPluginOperationalReportFeed() {
|
|
4543
4701
|
const nowMs = Date.now();
|
|
4544
|
-
const { getPluginOperationalReports } = await import("./agent-hooks-
|
|
4702
|
+
const { getPluginOperationalReports } = await import("./agent-hooks-BOWFTDE5.js");
|
|
4545
4703
|
return pluginOperationalReportFeedSchema.parse({
|
|
4546
4704
|
source: "plugins",
|
|
4547
4705
|
generatedAt: new Date(nowMs).toISOString(),
|
|
@@ -4579,7 +4737,12 @@ function createJuniorApi() {
|
|
|
4579
4737
|
"/api/stats",
|
|
4580
4738
|
async () => jsonResponse(statsReportSchema, await readStatsReport())
|
|
4581
4739
|
);
|
|
4582
|
-
app.route(
|
|
4740
|
+
app.route(
|
|
4741
|
+
"/api/conversations",
|
|
4742
|
+
createConversationRoutes({
|
|
4743
|
+
attachmentStorage: createVercelAttachmentStorage()
|
|
4744
|
+
})
|
|
4745
|
+
);
|
|
4583
4746
|
app.route("/api/personal-tokens", createPersonalTokenRoutes());
|
|
4584
4747
|
app.route("/api/people", createPeopleRoutes());
|
|
4585
4748
|
app.route("/api/locations", createLocationRoutes());
|