@sentry/junior 0.128.0 → 0.129.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.
Files changed (73) hide show
  1. package/dist/{agent-hooks-F75ANGBV.js → agent-hooks-ZM4WMZCN.js} +9 -9
  2. package/dist/api/schema/task.d.ts +152 -0
  3. package/dist/api/schema.d.ts +2 -0
  4. package/dist/api/schema.js +13 -3
  5. package/dist/api/tasks/routes.d.ts +4 -0
  6. package/dist/api.js +425 -23
  7. package/dist/app.d.ts +2 -1
  8. package/dist/app.js +315 -27
  9. package/dist/{catalog-runtime-ZPSA5QM2.js → catalog-runtime-TN2GPVEI.js} +5 -5
  10. package/dist/chat/agent-dispatch/context.d.ts +18 -0
  11. package/dist/chat/event-tasks/store.d.ts +7 -1
  12. package/dist/chat/event-tasks/tool-support.d.ts +1 -0
  13. package/dist/chat/resource-events/runtime-catalog.d.ts +3 -0
  14. package/dist/chat/sandbox/resources.d.ts +12 -1
  15. package/dist/chat/scheduled-tasks/cadence.d.ts +27 -0
  16. package/dist/chat/scheduled-tasks/heartbeat.d.ts +6 -0
  17. package/dist/chat/scheduled-tasks/identity.d.ts +6 -0
  18. package/dist/chat/scheduled-tasks/personal.d.ts +26 -0
  19. package/dist/chat/scheduled-tasks/schedule-intent.d.ts +61 -0
  20. package/dist/chat/scheduled-tasks/store.d.ts +77 -0
  21. package/dist/chat/scheduled-tasks/tool-support.d.ts +203 -0
  22. package/dist/chat/scheduled-tasks/tools/create.d.ts +80 -0
  23. package/dist/chat/scheduled-tasks/tools/delete.d.ts +56 -0
  24. package/dist/chat/scheduled-tasks/tools/list.d.ts +54 -0
  25. package/dist/chat/scheduled-tasks/tools/run-now.d.ts +56 -0
  26. package/dist/chat/scheduled-tasks/tools/update.d.ts +82 -0
  27. package/dist/chat/scheduled-tasks/tools.d.ts +6 -0
  28. package/dist/chat/scheduled-tasks/types.d.ts +81 -0
  29. package/dist/chat/tasks/read.d.ts +9 -0
  30. package/dist/chat/tools/scheduled-tasks.d.ts +4 -0
  31. package/dist/{chunk-K5ZB3WWH.js → chunk-2BCQKJTX.js} +2 -2
  32. package/dist/{chunk-G6XQODHM.js → chunk-3N4MWF3R.js} +1 -1
  33. package/dist/{chunk-NHWE6Y7G.js → chunk-6CMYU62S.js} +7 -7
  34. package/dist/{chunk-YY6CVET7.js → chunk-6QQOLIJJ.js} +1308 -804
  35. package/dist/{chunk-WZ365SQC.js → chunk-A6QQPVSH.js} +1 -1
  36. package/dist/chunk-BDIEEZK7.js +1470 -0
  37. package/dist/{chunk-AFJF3RGU.js → chunk-BVKP37NE.js} +61 -13
  38. package/dist/{chunk-5KKIBIIP.js → chunk-CZJUBH6O.js} +12 -12
  39. package/dist/{chunk-OLGB5Y7R.js → chunk-CZQ2DSQZ.js} +1 -1
  40. package/dist/{chunk-3PKF6YNU.js → chunk-E4UCPRYL.js} +1 -1
  41. package/dist/{chunk-KNRODVH2.js → chunk-ESYXDXNX.js} +6 -6
  42. package/dist/{chunk-Z4KTQMWW.js → chunk-GPWHBHAG.js} +1 -1
  43. package/dist/{chunk-JDCPDJ54.js → chunk-GURSWCI4.js} +2 -2
  44. package/dist/{chunk-RYWMDDWK.js → chunk-K3U5447S.js} +1 -1
  45. package/dist/{chunk-SHMHHXD5.js → chunk-KB2M27DL.js} +58 -0
  46. package/dist/{chunk-PBWUUVVG.js → chunk-LV2BQ26V.js} +1 -1
  47. package/dist/{chunk-KTGJAWRO.js → chunk-NNRV4T2C.js} +1 -2
  48. package/dist/{chunk-B6E3YA2H.js → chunk-P6I7LFKC.js} +1 -1
  49. package/dist/{chunk-B7FPRGUJ.js → chunk-PQFNTLZI.js} +3 -3
  50. package/dist/{chunk-A76LKS5W.js → chunk-QAOA4GUG.js} +5 -5
  51. package/dist/{chunk-BY43CEXN.js → chunk-R62DRNKB.js} +2 -2
  52. package/dist/{chunk-HBFQLSGV.js → chunk-U23X4ASF.js} +4 -4
  53. package/dist/{chunk-2HTHX6XV.js → chunk-XENYUOZG.js} +38 -17
  54. package/dist/cli/chat.js +24 -24
  55. package/dist/cli/check.js +6 -6
  56. package/dist/cli/plugins.js +12 -12
  57. package/dist/cli/snapshot-create.js +9 -9
  58. package/dist/cli/upgrade.js +9 -17
  59. package/dist/db/schema/scheduled-tasks.d.ts +257 -0
  60. package/dist/db/schema.d.ts +258 -1
  61. package/dist/{db-FYJYPAKG.js → db-ZI6TBXIS.js} +7 -7
  62. package/dist/instrumentation.js +4 -4
  63. package/dist/nitro.js +2 -2
  64. package/dist/{oauth-callback-server-W3PPIHCS.js → oauth-callback-server-TLA4GARF.js} +17 -17
  65. package/dist/{runner-5NOFUYKR.js → runner-23YFRWQJ.js} +11 -11
  66. package/dist/{skills-ENIBKF5V.js → skills-QIUG4D6M.js} +6 -6
  67. package/dist/{validation-BHLBOO6K.js → validation-3KGEBATS.js} +6 -6
  68. package/dist/version.js +1 -1
  69. package/migrations/0016_neat_the_anarchist.sql +171 -0
  70. package/migrations/meta/0016_snapshot.json +1617 -0
  71. package/migrations/meta/_journal.json +7 -0
  72. package/package.json +5 -6
  73. package/dist/chunk-FJEIX3AH.js +0 -37
package/dist/api.js CHANGED
@@ -24,13 +24,15 @@ import {
24
24
  personalTokenListSchema,
25
25
  personalTokenParamsSchema,
26
26
  revokePersonalTokenResponseSchema,
27
- statsReportSchema
28
- } from "./chunk-AFJF3RGU.js";
27
+ statsReportSchema,
28
+ taskListSchema,
29
+ taskParamsSchema
30
+ } from "./chunk-BVKP37NE.js";
29
31
  import {
30
32
  formatSlackConversationRedactedLabel,
31
33
  readHealthReport,
32
34
  resolveSlackConversationContextFromThreadId
33
- } from "./chunk-JDCPDJ54.js";
35
+ } from "./chunk-GURSWCI4.js";
34
36
  import {
35
37
  buildSentryConversationUrl
36
38
  } from "./chunk-4CODA7P5.js";
@@ -42,11 +44,20 @@ import {
42
44
  skillReportsSchema
43
45
  } from "./chunk-UTL3MHPC.js";
44
46
  import {
47
+ createSchedulerSqlStore,
48
+ deleteEventTask,
49
+ eventTaskBelongsToUser,
50
+ eventTaskTriggerAvailable,
51
+ getEventTask,
52
+ getResourceEventCatalog,
53
+ listEventTasksCreatedBy,
54
+ listPublicEventTasksForTeams,
55
+ listPublicScheduledTasksForTeams,
45
56
  readStats
46
- } from "./chunk-FJEIX3AH.js";
57
+ } from "./chunk-BDIEEZK7.js";
47
58
  import {
48
59
  parseSlackThreadId
49
- } from "./chunk-PBWUUVVG.js";
60
+ } from "./chunk-LV2BQ26V.js";
50
61
  import {
51
62
  agentTurnUsageSchema,
52
63
  hasAgentTurnUsage,
@@ -59,41 +70,41 @@ import {
59
70
  listConversationAnnotations,
60
71
  renderPluginConversationEvent,
61
72
  resolveViewerUser
62
- } from "./chunk-A76LKS5W.js";
73
+ } from "./chunk-QAOA4GUG.js";
63
74
  import {
64
75
  decodeStoredConversationEvent,
65
76
  getDb,
66
77
  getSqlExecutor,
67
78
  parseSessionSource
68
- } from "./chunk-B7FPRGUJ.js";
79
+ } from "./chunk-PQFNTLZI.js";
69
80
  import {
70
81
  juniorApiTokens,
71
82
  juniorConversationEvents,
72
83
  juniorConversations,
73
84
  juniorIdentities,
74
85
  juniorUsers
75
- } from "./chunk-SHMHHXD5.js";
76
- import "./chunk-G6XQODHM.js";
77
- import "./chunk-K5ZB3WWH.js";
86
+ } from "./chunk-KB2M27DL.js";
87
+ import "./chunk-3N4MWF3R.js";
88
+ import "./chunk-2BCQKJTX.js";
78
89
  import {
79
90
  juniorDestinations
80
91
  } from "./chunk-VFUK3X5B.js";
81
92
  import {
82
93
  canExposeConversationPayload
83
- } from "./chunk-Z4KTQMWW.js";
94
+ } from "./chunk-GPWHBHAG.js";
84
95
  import "./chunk-HZF5P5UN.js";
85
96
  import {
86
97
  parseSlackChannelId,
87
98
  parseSlackTeamId
88
99
  } from "./chunk-F3B2YJ76.js";
89
- import "./chunk-B6E3YA2H.js";
100
+ import "./chunk-P6I7LFKC.js";
90
101
  import "./chunk-6GWA276C.js";
91
- import "./chunk-RYWMDDWK.js";
92
- import "./chunk-KTGJAWRO.js";
102
+ import "./chunk-K3U5447S.js";
103
+ import "./chunk-NNRV4T2C.js";
93
104
  import "./chunk-MLKGABMK.js";
94
105
 
95
106
  // src/api.ts
96
- import { Hono as Hono6 } from "hono";
107
+ import { Hono as Hono7 } from "hono";
97
108
 
98
109
  // src/api/conversations/routes.ts
99
110
  import { Hono } from "hono";
@@ -2015,7 +2026,7 @@ function readDescriptionText(home) {
2015
2026
  }
2016
2027
  }
2017
2028
  async function readSkillReports() {
2018
- const { discoverSkills } = await import("./skills-ENIBKF5V.js");
2029
+ const { discoverSkills } = await import("./skills-QIUG4D6M.js");
2019
2030
  const skills = await discoverSkills();
2020
2031
  return skillReportsSchema.parse(
2021
2032
  skills.map((skill) => ({
@@ -2025,7 +2036,7 @@ async function readSkillReports() {
2025
2036
  );
2026
2037
  }
2027
2038
  async function readPlugins() {
2028
- const { pluginCatalogRuntime } = await import("./catalog-runtime-ZPSA5QM2.js");
2039
+ const { pluginCatalogRuntime } = await import("./catalog-runtime-TN2GPVEI.js");
2029
2040
  return pluginsSchema.parse(
2030
2041
  pluginCatalogRuntime.getProviders().map((plugin) => ({
2031
2042
  configKeys: plugin.manifest.configKeys ?? [],
@@ -2038,7 +2049,7 @@ async function readPlugins() {
2038
2049
  async function readRuntimeInfoReport() {
2039
2050
  const [{ homeDir }, { pluginCatalogRuntime }, plugins, skills] = await Promise.all([
2040
2051
  import("./discovery-GUFTFBTL.js"),
2041
- import("./catalog-runtime-ZPSA5QM2.js"),
2052
+ import("./catalog-runtime-TN2GPVEI.js"),
2042
2053
  readPlugins(),
2043
2054
  readSkillReports()
2044
2055
  ]);
@@ -2054,7 +2065,7 @@ async function readRuntimeInfoReport() {
2054
2065
  }
2055
2066
  async function readPluginOperationalReportFeed() {
2056
2067
  const nowMs = Date.now();
2057
- const { getPluginOperationalReports } = await import("./agent-hooks-F75ANGBV.js");
2068
+ const { getPluginOperationalReports } = await import("./agent-hooks-ZM4WMZCN.js");
2058
2069
  return pluginOperationalReportFeedSchema.parse({
2059
2070
  source: "plugins",
2060
2071
  generatedAt: new Date(nowMs).toISOString(),
@@ -3262,8 +3273,8 @@ async function readPluginUserPage(input) {
3262
3273
  (candidate) => candidate.id === input.pageId
3263
3274
  );
3264
3275
  if (!plugin || !page) return void 0;
3265
- const viewer = await resolveViewerUser(input.email);
3266
- if (!viewer) {
3276
+ const viewer2 = await resolveViewerUser(input.email);
3277
+ if (!viewer2) {
3267
3278
  throw new Error("Authenticated viewer user could not be resolved");
3268
3279
  }
3269
3280
  const content = pluginUserPageContentSchema.parse(
@@ -3272,7 +3283,7 @@ async function readPluginUserPage(input) {
3272
3283
  db: getDb(),
3273
3284
  log: createPluginLogger(plugin.manifest.name),
3274
3285
  plugin: { name: plugin.manifest.name },
3275
- viewer
3286
+ viewer: viewer2
3276
3287
  },
3277
3288
  input.query
3278
3289
  )
@@ -3333,6 +3344,396 @@ function createUserPageRoutes() {
3333
3344
  return app;
3334
3345
  }
3335
3346
 
3347
+ // src/api/tasks/routes.ts
3348
+ import { Hono as Hono6 } from "hono";
3349
+
3350
+ // src/chat/tasks/read.ts
3351
+ import { and as and14, eq as eq15, or as or3 } from "drizzle-orm";
3352
+
3353
+ // src/chat/scheduled-tasks/personal.ts
3354
+ import { z as z3 } from "zod";
3355
+ var cursorSchema = z3.object({
3356
+ createdAtMs: z3.number().finite(),
3357
+ id: z3.string().min(1),
3358
+ query: z3.string().max(200).optional(),
3359
+ version: z3.literal(1)
3360
+ }).strict();
3361
+ var InvalidScheduledTaskCursorError = class extends Error {
3362
+ constructor() {
3363
+ super("Scheduled task cursor is invalid.");
3364
+ this.name = "InvalidScheduledTaskCursorError";
3365
+ }
3366
+ };
3367
+ var PersonalScheduledTaskNotFoundError = class extends Error {
3368
+ constructor() {
3369
+ super("Scheduled task was not found.");
3370
+ this.name = "PersonalScheduledTaskNotFoundError";
3371
+ }
3372
+ };
3373
+ function normalizeQuery(query) {
3374
+ return query?.trim().toLowerCase() || void 0;
3375
+ }
3376
+ function decodeCursor(value, query) {
3377
+ if (!value) return void 0;
3378
+ try {
3379
+ const parsed = cursorSchema.parse(
3380
+ JSON.parse(Buffer.from(value, "base64url").toString("utf8"))
3381
+ );
3382
+ if (parsed.query !== query) {
3383
+ throw new InvalidScheduledTaskCursorError();
3384
+ }
3385
+ return { createdAtMs: parsed.createdAtMs, id: parsed.id };
3386
+ } catch {
3387
+ throw new InvalidScheduledTaskCursorError();
3388
+ }
3389
+ }
3390
+ function encodeCursor(task, query) {
3391
+ return Buffer.from(
3392
+ JSON.stringify({
3393
+ createdAtMs: task.createdAtMs,
3394
+ id: task.id,
3395
+ ...query ? { query } : {},
3396
+ version: 1
3397
+ }),
3398
+ "utf8"
3399
+ ).toString("base64url");
3400
+ }
3401
+ function createViewerScheduledTasks(store, user) {
3402
+ const identityIds = new Set(user.identities.map((identity) => identity.id));
3403
+ return {
3404
+ async delete(id, nowMs = Date.now()) {
3405
+ const task = await store.getTask(id);
3406
+ if (!task || task.status === "deleted" || !identityIds.has(task.creatorIdentityId)) {
3407
+ throw new PersonalScheduledTaskNotFoundError();
3408
+ }
3409
+ await store.saveTask({
3410
+ ...task,
3411
+ nextRunAtMs: void 0,
3412
+ runNowAtMs: void 0,
3413
+ status: "deleted",
3414
+ updatedAtMs: nowMs
3415
+ });
3416
+ },
3417
+ async list(input) {
3418
+ const query = normalizeQuery(input.query);
3419
+ const cursor = decodeCursor(input.cursor, query);
3420
+ const matching = await store.listTasksCreatedBy({
3421
+ ...cursor ? { before: cursor } : {},
3422
+ identityIds: [...identityIds],
3423
+ limit: input.limit + 1,
3424
+ ...query ? { query } : {}
3425
+ });
3426
+ const tasks = matching.slice(0, input.limit);
3427
+ return {
3428
+ tasks,
3429
+ ...matching.length > input.limit && tasks.length > 0 ? { nextCursor: encodeCursor(tasks.at(-1), query) } : {}
3430
+ };
3431
+ }
3432
+ };
3433
+ }
3434
+
3435
+ // src/chat/tasks/read.ts
3436
+ var TASK_LIST_LIMIT = 100;
3437
+ var TASK_FETCH_LIMIT = TASK_LIST_LIMIT + 1;
3438
+ function creatorLabel(creator) {
3439
+ return creator.fullName?.trim() || (creator.userName?.trim() ? `@${creator.userName.trim()}` : "") || creator.slackUserId;
3440
+ }
3441
+ function creatorKey(teamId, slackUserId) {
3442
+ return `${teamId}:${slackUserId}`;
3443
+ }
3444
+ async function creatorProfileEmails(candidates) {
3445
+ const selectors = new Map(
3446
+ candidates.map(({ task }) => {
3447
+ const teamId = task.destination.teamId;
3448
+ const slackUserId = task.createdBy.slackUserId;
3449
+ return [
3450
+ creatorKey(teamId, slackUserId),
3451
+ { slackUserId, teamId }
3452
+ ];
3453
+ })
3454
+ );
3455
+ if (selectors.size === 0) return /* @__PURE__ */ new Map();
3456
+ const rows = await getDb().select({
3457
+ email: juniorUsers.primaryEmailNormalized,
3458
+ slackUserId: juniorIdentities.providerSubjectId,
3459
+ teamId: juniorIdentities.providerTenantId
3460
+ }).from(juniorIdentities).innerJoin(juniorUsers, eq15(juniorUsers.id, juniorIdentities.userId)).where(
3461
+ and14(
3462
+ eq15(juniorIdentities.kind, "user"),
3463
+ eq15(juniorIdentities.provider, "slack"),
3464
+ eq15(juniorIdentities.emailVerified, true),
3465
+ or3(
3466
+ ...[...selectors.values()].map(
3467
+ (selector) => and14(
3468
+ eq15(juniorIdentities.providerTenantId, selector.teamId),
3469
+ eq15(juniorIdentities.providerSubjectId, selector.slackUserId)
3470
+ )
3471
+ )
3472
+ )
3473
+ )
3474
+ );
3475
+ return new Map(
3476
+ rows.map((row) => [creatorKey(row.teamId, row.slackUserId), row.email])
3477
+ );
3478
+ }
3479
+ function destinationKey(destination) {
3480
+ return `${destination.teamId}:${destination.channelId}`;
3481
+ }
3482
+ function displayText(value, fallback) {
3483
+ return value.trim() || fallback;
3484
+ }
3485
+ async function destinationDetails(destinations) {
3486
+ const selectors = new Map(
3487
+ destinations.map((destination) => [
3488
+ destinationKey(destination),
3489
+ destination
3490
+ ])
3491
+ );
3492
+ if (selectors.size === 0) return /* @__PURE__ */ new Map();
3493
+ const rows = await getDb().select({
3494
+ displayName: juniorDestinations.displayName,
3495
+ kind: juniorDestinations.kind,
3496
+ providerDestinationId: juniorDestinations.providerDestinationId,
3497
+ providerTenantId: juniorDestinations.providerTenantId,
3498
+ visibility: juniorDestinations.visibility
3499
+ }).from(juniorDestinations).where(
3500
+ or3(
3501
+ ...[...selectors.values()].map(
3502
+ (destination) => and14(
3503
+ eq15(juniorDestinations.provider, "slack"),
3504
+ eq15(juniorDestinations.providerTenantId, destination.teamId),
3505
+ eq15(juniorDestinations.providerDestinationId, destination.channelId)
3506
+ )
3507
+ )
3508
+ )
3509
+ );
3510
+ return new Map(
3511
+ rows.map((row) => {
3512
+ const name = row.displayName?.trim();
3513
+ const label = name ? row.kind === "channel" ? `#${name.replace(/^#/, "")}` : name : row.kind === "dm" ? "Direct message" : row.kind === "group" ? "Group message" : `Channel ${row.providerDestinationId}`;
3514
+ return [
3515
+ `${row.providerTenantId}:${row.providerDestinationId}`,
3516
+ {
3517
+ label,
3518
+ visibility: row.visibility === "public" ? "public" : "private"
3519
+ }
3520
+ ];
3521
+ })
3522
+ );
3523
+ }
3524
+ function scheduledTaskSummary(task, ownedByViewer, destination) {
3525
+ if (task.status === "deleted") {
3526
+ throw new Error("Deleted scheduled tasks cannot enter the Tasks view");
3527
+ }
3528
+ const nextRunAtMs = task.runNowAtMs ?? task.nextRunAtMs;
3529
+ return {
3530
+ createdAt: new Date(task.createdAtMs).toISOString(),
3531
+ createdBy: creatorLabel(task.createdBy),
3532
+ destination: {
3533
+ channelId: task.destination.channelId,
3534
+ label: destination.label,
3535
+ teamId: task.destination.teamId,
3536
+ visibility: destination.visibility
3537
+ },
3538
+ id: task.id,
3539
+ instruction: displayText(task.task.text, "Untitled scheduled task"),
3540
+ kind: "scheduled",
3541
+ ...nextRunAtMs !== void 0 ? { nextRunAt: new Date(nextRunAtMs).toISOString() } : {},
3542
+ ownedByViewer,
3543
+ schedule: displayText(task.schedule.description, "Schedule unavailable"),
3544
+ status: task.status
3545
+ };
3546
+ }
3547
+ async function readViewerTasks(user) {
3548
+ const db = getDb();
3549
+ const schedulerStore = createSchedulerSqlStore(db);
3550
+ const identityIds = new Set(user.identities.map((identity) => identity.id));
3551
+ const teamIds = [
3552
+ ...new Set(
3553
+ user.identities.filter((identity) => identity.provider === "slack").map((identity) => identity.providerTenantId).filter((teamId) => Boolean(teamId))
3554
+ )
3555
+ ];
3556
+ const [scheduledPage, publicScheduled, eventTasks, publicEventTasks] = await Promise.all([
3557
+ createViewerScheduledTasks(schedulerStore, user).list({
3558
+ limit: TASK_FETCH_LIMIT
3559
+ }),
3560
+ listPublicScheduledTasksForTeams(db, teamIds, TASK_FETCH_LIMIT),
3561
+ listEventTasksCreatedBy(db, user, TASK_FETCH_LIMIT),
3562
+ listPublicEventTasksForTeams(db, teamIds, TASK_FETCH_LIMIT)
3563
+ ]);
3564
+ const candidatesById = /* @__PURE__ */ new Map();
3565
+ const publicScheduledIds = new Set(publicScheduled.map((task) => task.id));
3566
+ const publicEventTaskIds = new Set(publicEventTasks.map((task) => task.id));
3567
+ for (const task of [...scheduledPage.tasks, ...publicScheduled]) {
3568
+ candidatesById.set(`scheduled:${task.id}`, {
3569
+ kind: "scheduled",
3570
+ ownedByViewer: identityIds.has(task.creatorIdentityId),
3571
+ publicToViewer: publicScheduledIds.has(task.id),
3572
+ task
3573
+ });
3574
+ }
3575
+ for (const task of [...eventTasks, ...publicEventTasks]) {
3576
+ candidatesById.set(`event:${task.id}`, {
3577
+ kind: "event",
3578
+ ownedByViewer: eventTaskBelongsToUser(task, user),
3579
+ publicToViewer: publicEventTaskIds.has(task.id),
3580
+ task
3581
+ });
3582
+ }
3583
+ const candidates = [...candidatesById.values()].sort(
3584
+ (left, right) => right.task.createdAtMs - left.task.createdAtMs || right.task.id.localeCompare(left.task.id)
3585
+ );
3586
+ const ownedCandidates = candidates.filter(
3587
+ (candidate) => candidate.ownedByViewer
3588
+ );
3589
+ const publicCandidates = candidates.filter(
3590
+ (candidate) => candidate.publicToViewer
3591
+ );
3592
+ const selectedCandidates = /* @__PURE__ */ new Set([
3593
+ ...ownedCandidates.slice(0, TASK_LIST_LIMIT),
3594
+ ...publicCandidates.slice(0, TASK_LIST_LIMIT)
3595
+ ]);
3596
+ const selected = candidates.filter(
3597
+ (candidate) => selectedCandidates.has(candidate)
3598
+ );
3599
+ const [destinations, creatorEmails] = await Promise.all([
3600
+ destinationDetails(selected.map(({ task }) => task.destination)),
3601
+ creatorProfileEmails(selected)
3602
+ ]);
3603
+ const eventCatalog = getResourceEventCatalog();
3604
+ const visible = selected.filter(
3605
+ (candidate) => candidate.ownedByViewer || destinations.get(destinationKey(candidate.task.destination))?.visibility === "public"
3606
+ );
3607
+ const tasks = visible.map((candidate) => {
3608
+ const destination = destinations.get(
3609
+ destinationKey(candidate.task.destination)
3610
+ ) ?? {
3611
+ label: `Channel ${candidate.task.destination.channelId}`,
3612
+ visibility: "private"
3613
+ };
3614
+ const createdByEmail = creatorEmails.get(
3615
+ creatorKey(
3616
+ candidate.task.destination.teamId,
3617
+ candidate.task.createdBy.slackUserId
3618
+ )
3619
+ );
3620
+ if (candidate.kind === "scheduled") {
3621
+ const summary = scheduledTaskSummary(
3622
+ candidate.task,
3623
+ candidate.ownedByViewer,
3624
+ destination
3625
+ );
3626
+ return {
3627
+ ...summary,
3628
+ ...createdByEmail ? { createdByEmail } : {}
3629
+ };
3630
+ }
3631
+ const task = candidate.task;
3632
+ return {
3633
+ createdAt: new Date(task.createdAtMs).toISOString(),
3634
+ createdBy: creatorLabel(task.createdBy),
3635
+ ...createdByEmail ? { createdByEmail } : {},
3636
+ destination: {
3637
+ channelId: task.destination.channelId,
3638
+ label: destination.label,
3639
+ teamId: task.destination.teamId,
3640
+ visibility: destination.visibility
3641
+ },
3642
+ events: task.trigger.events,
3643
+ id: task.id,
3644
+ instruction: task.task.text,
3645
+ kind: "event",
3646
+ ownedByViewer: candidate.ownedByViewer,
3647
+ resource: `${task.trigger.label} \xB7 ${task.trigger.identifier}`,
3648
+ source: task.trigger.namespace,
3649
+ triggerAvailable: eventTaskTriggerAvailable(task, eventCatalog)
3650
+ };
3651
+ });
3652
+ return {
3653
+ tasks,
3654
+ truncated: ownedCandidates.length > TASK_LIST_LIMIT || publicCandidates.length > TASK_LIST_LIMIT
3655
+ };
3656
+ }
3657
+ var ViewerTaskNotFoundError = class extends Error {
3658
+ constructor() {
3659
+ super("Task was not found.");
3660
+ this.name = "ViewerTaskNotFoundError";
3661
+ }
3662
+ };
3663
+ async function deleteViewerTask(user, kind, id) {
3664
+ if (kind === "scheduled") {
3665
+ try {
3666
+ await createViewerScheduledTasks(
3667
+ createSchedulerSqlStore(getDb()),
3668
+ user
3669
+ ).delete(id);
3670
+ return;
3671
+ } catch (error) {
3672
+ if (error instanceof PersonalScheduledTaskNotFoundError) {
3673
+ throw new ViewerTaskNotFoundError();
3674
+ }
3675
+ throw error;
3676
+ }
3677
+ }
3678
+ const task = await getEventTask(getDb(), id);
3679
+ if (!task || !eventTaskBelongsToUser(task, user)) {
3680
+ throw new ViewerTaskNotFoundError();
3681
+ }
3682
+ await deleteEventTask(getDb(), id);
3683
+ }
3684
+
3685
+ // src/api/tasks/routes.ts
3686
+ async function viewer(context) {
3687
+ const email = context.get("verifiedViewerEmail")?.trim();
3688
+ return email ? await resolveViewerUser(email) : void 0;
3689
+ }
3690
+ function createTaskRoutes() {
3691
+ const app = new Hono6();
3692
+ app.get("/", async (context) => {
3693
+ const user = await viewer(context);
3694
+ return user ? jsonResponse(taskListSchema, await readViewerTasks(user)) : jsonResponse(
3695
+ apiErrorSchema,
3696
+ { error: "Authentication required." },
3697
+ { status: 401 }
3698
+ );
3699
+ });
3700
+ app.delete("/:kind/:id", async (context) => {
3701
+ const user = await viewer(context);
3702
+ if (!user) {
3703
+ return jsonResponse(
3704
+ apiErrorSchema,
3705
+ { error: "Authentication required." },
3706
+ { status: 401 }
3707
+ );
3708
+ }
3709
+ const params = taskParamsSchema.safeParse(context.req.param());
3710
+ if (!params.success) {
3711
+ return jsonResponse(
3712
+ apiErrorSchema,
3713
+ { error: "Invalid task." },
3714
+ { status: 400 }
3715
+ );
3716
+ }
3717
+ try {
3718
+ await deleteViewerTask(user, params.data.kind, params.data.id);
3719
+ return new Response(null, {
3720
+ headers: { "cache-control": "no-store" },
3721
+ status: 204
3722
+ });
3723
+ } catch (error) {
3724
+ if (error instanceof ViewerTaskNotFoundError) {
3725
+ return jsonResponse(
3726
+ apiErrorSchema,
3727
+ { error: error.message },
3728
+ { status: 404 }
3729
+ );
3730
+ }
3731
+ throw error;
3732
+ }
3733
+ });
3734
+ return app;
3735
+ }
3736
+
3336
3737
  // src/api/plugins.ts
3337
3738
  var plugins_default = defineApiRoute({
3338
3739
  method: "get",
@@ -3390,13 +3791,14 @@ var routes4 = [
3390
3791
  stats_default2
3391
3792
  ];
3392
3793
  function createJuniorApi() {
3393
- const app = new Hono6();
3794
+ const app = new Hono7();
3394
3795
  registerApiRoutes(app, routes4);
3395
3796
  app.route("/api/conversations", createConversationRoutes());
3396
3797
  app.route("/api/personal-tokens", createPersonalTokenRoutes());
3397
3798
  app.route("/api/people", createPeopleRoutes());
3398
3799
  app.route("/api/locations", createLocationRoutes());
3399
3800
  app.route("/api/user-pages", createUserPageRoutes());
3801
+ app.route("/api/tasks", createTaskRoutes());
3400
3802
  app.notFound(
3401
3803
  () => jsonResponse(
3402
3804
  apiErrorSchema,
package/dist/app.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  import { Hono } from "hono";
2
+ import { type SandboxResourceConfig } from "@/chat/sandbox/resources";
2
3
  import { type JuniorPluginSet } from "./plugins";
3
4
  import { type VercelConversationWorkCallbackOptions } from "@/chat/task-execution/vercel-callback";
4
5
  import type { WaitUntilFn } from "@/handlers/types";
@@ -22,7 +23,7 @@ export interface JuniorAppOptions {
22
23
  /** Direct plugin set override. Usually omitted when `juniorNitro()` uses a plugin module. */
23
24
  plugins?: JuniorPluginSet;
24
25
  /** Sandbox execution options. */
25
- sandbox?: {
26
+ sandbox?: SandboxResourceConfig & {
26
27
  /**
27
28
  * Egress domains allowed to carry Sentry trace propagation headers.
28
29
  * Entries may be exact domains or leading wildcard domains such as