@sentry/junior 0.250.0 → 0.252.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/{admin-DMKyXi83.js → admin-C_-XEdym.js} +1 -1
- package/dist/{agent-hooks-CtZuJPTU.js → agent-hooks-DcoKnnxn.js} +36 -13
- package/dist/{agent-runner-CNiTpIpb.js → agent-runner-B-7S_DCS.js} +357 -99
- package/dist/api/schema.d.ts +46 -32
- package/dist/api/schema.js +2 -2
- package/dist/api.js +50 -65
- package/dist/app.js +52 -81
- package/dist/{assistant-reply-K5r1pcgJ.js → assistant-reply-DbPLvsnL.js} +1 -1
- package/dist/{briefs-8xyS3oeV.js → briefs-D4SMqc-r.js} +4 -4
- package/dist/{catalog-runtime-BQ3g3OX_.js → catalog-runtime-BQQiwwA7.js} +1 -1
- package/dist/cli/chat.js +15 -15
- package/dist/cli/check.js +3 -3
- package/dist/cli/main.js +2 -2
- package/dist/cli/plugins.js +4 -4
- package/dist/cli/snapshot-create.js +3 -3
- package/dist/cli/upgrade.js +3 -3
- package/dist/{client-Q27hki0Y.js → client-ROZeVjq0.js} +2 -2
- package/dist/{config-Cb--Qs-g.js → config-DNNkxfGS.js} +2 -2
- package/dist/{connections-DZ70JeSN.js → connections-DJV6mLrH.js} +9 -9
- package/dist/{conversation-NutPJ8S8.js → conversation-T18Xlkx9.js} +9 -1
- package/dist/{conversation-privacy-BIDN1sW3.js → conversation-privacy-B19umzIL.js} +1 -1
- package/dist/{credential-sync-CyAN-Gos.js → credential-sync-CEd2F5PS.js} +14 -14
- package/dist/{executor-D8y7v95s.js → executor-_4bdoCxe.js} +59 -19
- package/dist/{images-BkGhqKIK.js → images-BAN7DHuO.js} +3 -3
- package/dist/instrumentation.js +2 -2
- package/dist/{job-queue-uGq6Grnt.js → job-queue-DSQx1qFY.js} +1 -1
- package/dist/{logging-C22RdmU8.js → logging-COUsTFIL.js} +1 -1
- package/dist/{message-D0RPetp-.js → message-CtDDEwwV.js} +3 -3
- package/dist/nitro.js +3 -3
- package/dist/{oauth-callback-server-DF_Odkvh.js → oauth-callback-server-CCiKrS0s.js} +2 -2
- package/dist/{pending-auth-Bg3A1-pE.js → pending-auth-DDx3EU4M.js} +2 -2
- package/dist/{profile-DK9umvav.js → profile-DP4LKL6V.js} +4 -4
- package/dist/{prompt-kYP1FAX_.js → prompt-C04mP1hu.js} +1 -1
- package/dist/{registry-BvsLuoLK.js → registry-CeEpPna6.js} +1 -1
- package/dist/{resolve-C9btOXju.js → resolve-B5ma3igH.js} +2 -2
- package/dist/{result-CcdQ2iau.js → result-Da0RVuWG.js} +7 -7
- package/dist/{runner-Bem4DUHN.js → runner-se1W_jGZ.js} +10 -10
- package/dist/{sandbox-egress-signals-Bl-4cF7E.js → sandbox-egress-signals-CS959-wm.js} +1 -1
- package/dist/{schema-DELmAdjR.js → schema-C9Vnyb_f.js} +1 -1
- package/dist/{session-stop-DteRDRCi.js → session-stop-DlRDisF5.js} +11 -11
- package/dist/{skills-CVwSL6Gc.js → skills-CSzgs0EC.js} +2 -2
- package/dist/{spawn-CA0YYtzr.js → spawn-DT9fMjtd.js} +2 -2
- package/dist/{store-Dw3eBN9S.js → store-Dx1U69mm.js} +6 -6
- package/dist/{task-queue-C7cyjcVj.js → task-queue-BX9YrIsw.js} +3 -3
- package/dist/{task-runner-BbSyWmOq.js → task-runner-CO55Olal.js} +46 -13
- package/dist/{tasks-B8nH3ND_.js → tasks-DwGlFX9i.js} +166 -212
- package/dist/{thread-state-BTOLzCM-.js → thread-state-Ces6tXmB.js} +6 -6
- package/dist/{turn-failure-response-BwNfO8Xt.js → turn-failure-response-B4VCvEQf.js} +8 -8
- package/dist/{turn-lifecycle-DSN0xGW7.js → turn-lifecycle-B1VV58Yo.js} +1 -1
- package/dist/{turn-session-routing-BRKYIn6n.js → turn-session-routing-Dw2Kamg9.js} +1 -1
- package/dist/{validation-CBkyzKCP.js → validation-yJF9LKOv.js} +1 -1
- package/dist/{version-CkwwLVLb.js → version-CZYqvIFh.js} +1 -1
- package/dist/version.js +1 -1
- package/dist/{viewer-DdzigZQh.js → viewer-D96vo_42.js} +3 -3
- package/dist/{web-input-BjdnnpuN.js → web-input-5mls-41-.js} +105 -104
- package/dist/{work-qQEjtmlv.js → work-D2M2-zCO.js} +9 -9
- package/dist/{worker-C-CSZMy_.js → worker-BwCpf8tB.js} +5 -5
- package/migrations/0055_automations.sql +125 -0
- package/migrations/meta/0055_snapshot.json +3948 -0
- package/migrations/meta/_journal.json +8 -1
- package/package.json +5 -5
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
import { d as unwrapCurrentInstruction, f as escapeXml, i as completeText, o as resolveGatewayModel } from "./client-
|
|
2
|
-
import { d as logException, o as getActiveTraceId, p as logWarn, s as getLogContextAttributes, t as buildTurnFailureResponse, v as setSpanAttributes } from "./logging-
|
|
1
|
+
import { d as unwrapCurrentInstruction, f as escapeXml, i as completeText, o as resolveGatewayModel } from "./client-ROZeVjq0.js";
|
|
2
|
+
import { d as logException, o as getActiveTraceId, p as logWarn, s as getLogContextAttributes, t as buildTurnFailureResponse, v as setSpanAttributes } from "./logging-COUsTFIL.js";
|
|
3
3
|
import { n as captureMessage } from "./sentry-CgWZM_kV.js";
|
|
4
|
-
import { n as botConfig, v as normalizeSlackEmojiName } from "./config-
|
|
4
|
+
import { n as botConfig, v as normalizeSlackEmojiName } from "./config-DNNkxfGS.js";
|
|
5
5
|
import { c as toStoredSlackActor, f as parseSlackUserId, g as parseSlackMessageTs } from "./actor-BTtLaeWy.js";
|
|
6
|
-
import { c as getConversationEventStore, f as getSqlExecutor, m as withConversationEventLock, p as createSqlConversationEventStore, u as getConversationStore, v as startLocationThread, x as addAgentTurnUsage, y as bindProviderConversation } from "./viewer-
|
|
7
|
-
import { a as juniorSchedulerRuns, o as
|
|
6
|
+
import { c as getConversationEventStore, f as getSqlExecutor, m as withConversationEventLock, p as createSqlConversationEventStore, u as getConversationStore, v as startLocationThread, x as addAgentTurnUsage, y as bindProviderConversation } from "./viewer-D96vo_42.js";
|
|
7
|
+
import { a as juniorSchedulerRuns, o as juniorAutomationVersions, s as juniorAutomations } from "./executor-_4bdoCxe.js";
|
|
8
8
|
import { d as contextProvenance, f as instructionActors, n as agentHistoryItemSchema, p as instructionProvenanceFor } from "./history-9pO1Zd4Y.js";
|
|
9
|
-
import { p as credentialSubjectSchema } from "./registry-
|
|
10
|
-
import {
|
|
11
|
-
import { G as messageCardRef } from "./conversation-
|
|
12
|
-
import { D as fenceLock, O as withLock, T as MUTATION_LOCK_TTL_MS, k as sleep, w as getStateAdapter } from "./profile-
|
|
9
|
+
import { p as credentialSubjectSchema } from "./registry-CeEpPna6.js";
|
|
10
|
+
import { $t as authenticationUnlinkedEvent, Gt as normalizeSlackConversationId, Ht as getSlackClient, Qt as authenticationLinkedEvent, Rt as SlackActionError, Xt as JUNIOR_NATIVE_EVENT_NAMESPACE, Zt as agentsInstructionsUpdatedEvent, n as applyPluginFormatMarkdown, qt as withSlackRetries } from "./agent-hooks-DcoKnnxn.js";
|
|
11
|
+
import { G as messageCardRef } from "./conversation-T18Xlkx9.js";
|
|
12
|
+
import { D as fenceLock, O as withLock, T as MUTATION_LOCK_TTL_MS, k as sleep, w as getStateAdapter } from "./profile-DP4LKL6V.js";
|
|
13
13
|
import { A as eventAutomationSchema, D as scheduledRunSchema, E as scheduledAutomationSchema, S as automationVersionSchema } from "./automation-gznOMaQ2.js";
|
|
14
14
|
import { isDeepStrictEqual } from "node:util";
|
|
15
15
|
import { z } from "zod";
|
|
16
16
|
import { createHash } from "node:crypto";
|
|
17
|
-
import { and, asc, desc, eq, inArray, ne,
|
|
18
|
-
import { actorSchema, eventMatches,
|
|
17
|
+
import { and, asc, desc, eq, inArray, ne, or, sql } from "drizzle-orm";
|
|
18
|
+
import { actorSchema, eventMatches, sourceSchema } from "@sentry/junior-plugin-api";
|
|
19
19
|
//#region src/chat/pi/messages.ts
|
|
20
20
|
/** Permissive schema for durable Pi SDK messages whose content shape may evolve. */
|
|
21
21
|
const piMessageSchema = z.object({ role: z.string() }).passthrough().transform((value) => value);
|
|
@@ -444,12 +444,27 @@ function isHumanConversationMessage(message) {
|
|
|
444
444
|
function getConversationMessageSlackTs(message) {
|
|
445
445
|
return parseSlackMessageTs(message.meta?.slackTs);
|
|
446
446
|
}
|
|
447
|
+
const SOURCE_TEXT_MAX_LENGTH = {
|
|
448
|
+
conversation: 500,
|
|
449
|
+
run: 2e3,
|
|
450
|
+
task: 500
|
|
451
|
+
};
|
|
452
|
+
const SOURCE_LABELS = {
|
|
453
|
+
conversation: "First user message",
|
|
454
|
+
run: "Task input",
|
|
455
|
+
task: "Task instruction"
|
|
456
|
+
};
|
|
447
457
|
const TITLE_PROMPTS = {
|
|
448
458
|
conversation: [
|
|
449
459
|
"Generate a concise 5-8 word conversation title from the first user message below.",
|
|
450
460
|
"Capture the user's main request.",
|
|
451
461
|
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
452
462
|
],
|
|
463
|
+
run: [
|
|
464
|
+
"Generate a concise 5-8 word title for one task run from its task input below.",
|
|
465
|
+
"Capture what this run is about. Prefer the specific event or subject over the task wording.",
|
|
466
|
+
"Reply with ONLY the title, with no quotes or trailing punctuation."
|
|
467
|
+
],
|
|
453
468
|
task: [
|
|
454
469
|
"Generate a concise 5-8 word task title from the task instruction below.",
|
|
455
470
|
"Capture the task's main purpose.",
|
|
@@ -483,7 +498,7 @@ async function generateShortTitle(args) {
|
|
|
483
498
|
content: [
|
|
484
499
|
...TITLE_PROMPTS[args.kind],
|
|
485
500
|
"",
|
|
486
|
-
args.kind
|
|
501
|
+
`${SOURCE_LABELS[args.kind]}: ${sourceText.slice(0, SOURCE_TEXT_MAX_LENGTH[args.kind])}`
|
|
487
502
|
].join("\n"),
|
|
488
503
|
timestamp: Date.now()
|
|
489
504
|
}],
|
|
@@ -518,9 +533,10 @@ const inFlightTitles = /* @__PURE__ */ new Map();
|
|
|
518
533
|
* Set-once conversation title from the earliest human message.
|
|
519
534
|
*
|
|
520
535
|
* One automatic generation path for every surface. Starts only from durable
|
|
521
|
-
* transcript writes via `scheduleConversationTitle`.
|
|
522
|
-
*
|
|
523
|
-
*
|
|
536
|
+
* transcript writes via `scheduleConversationTitle`. A dispatched run, such as
|
|
537
|
+
* an automation run, has no human message, so its title comes from the run
|
|
538
|
+
* input. Returns a newly persisted title, or undefined when the conversation
|
|
539
|
+
* is already titled or generation does not apply.
|
|
524
540
|
*/
|
|
525
541
|
async function ensureConversationTitle(args) {
|
|
526
542
|
const pending = inFlightTitles.get(args.conversationId);
|
|
@@ -531,28 +547,37 @@ async function ensureConversationTitle(args) {
|
|
|
531
547
|
inFlightTitles.set(args.conversationId, work);
|
|
532
548
|
return work;
|
|
533
549
|
}
|
|
550
|
+
/** Return the earliest user message, which is the input of a dispatched run. */
|
|
551
|
+
function getRunInputMessage(conversation) {
|
|
552
|
+
let earliest;
|
|
553
|
+
for (const message of conversation.messages) if (message.role === "user" && (!earliest || message.createdAtMs < earliest.createdAtMs)) earliest = message;
|
|
554
|
+
return earliest;
|
|
555
|
+
}
|
|
534
556
|
async function ensureConversationTitleOnce(args) {
|
|
535
|
-
|
|
557
|
+
const humanMessage = getThreadTitleSourceMessage(args.conversation);
|
|
558
|
+
const runInputMessage = humanMessage ? void 0 : getRunInputMessage(args.conversation);
|
|
559
|
+
if (!humanMessage && !runInputMessage) return;
|
|
536
560
|
const store = args.conversationStore ?? getConversationStore();
|
|
537
561
|
try {
|
|
538
562
|
const stored = await store.get({ conversationId: args.conversationId });
|
|
539
563
|
if (stored?.title?.trim()) return;
|
|
540
564
|
if (stored?.parentConversationId) return;
|
|
541
|
-
const titleSourceMessage =
|
|
565
|
+
const titleSourceMessage = humanMessage ?? (stored?.source === "plugin" ? runInputMessage : void 0);
|
|
542
566
|
const sourceText = titleSourceMessage?.text.trim() ?? "";
|
|
543
567
|
if (!titleSourceMessage || !sourceText) return;
|
|
568
|
+
const kind = humanMessage ? "conversation" : "run";
|
|
544
569
|
let title;
|
|
545
570
|
try {
|
|
546
571
|
title = await generateShortTitle({
|
|
547
572
|
completeText,
|
|
548
|
-
kind
|
|
573
|
+
kind,
|
|
549
574
|
sourceText
|
|
550
|
-
})
|
|
575
|
+
});
|
|
551
576
|
} catch (error) {
|
|
552
577
|
logWarn("conversation.title.generation.failed", { "exception.message": error instanceof Error ? error.message : String(error) });
|
|
553
|
-
title = fallbackShortTitle(sourceText, "Conversation");
|
|
554
578
|
}
|
|
555
|
-
|
|
579
|
+
if (!title && kind === "conversation") title = fallbackShortTitle(sourceText, "Conversation");
|
|
580
|
+
const normalized = title?.trim();
|
|
556
581
|
if (!normalized) return;
|
|
557
582
|
const activityAtMs = titleSourceMessage.createdAtMs;
|
|
558
583
|
const nowMs = args.nowMs ?? Date.now();
|
|
@@ -574,7 +599,7 @@ async function ensureConversationTitleOnce(args) {
|
|
|
574
599
|
}
|
|
575
600
|
}
|
|
576
601
|
/**
|
|
577
|
-
* Start title work after durable
|
|
602
|
+
* Start title work after durable transcript writes. This is the only
|
|
578
603
|
* entry that starts generation; `settleConversationTitleWork` joins it.
|
|
579
604
|
*/
|
|
580
605
|
function scheduleConversationTitle(args) {
|
|
@@ -2829,26 +2854,31 @@ function sameDefinitionValue(left, right) {
|
|
|
2829
2854
|
* transaction and lock as the Automation write. Without `current`, the
|
|
2830
2855
|
* Automation is new, so the creator saves version 1.
|
|
2831
2856
|
*/
|
|
2832
|
-
async function recordAutomationVersion(db,
|
|
2857
|
+
async function recordAutomationVersion(db, task, current, editedBy) {
|
|
2833
2858
|
const definition = automationDefinition(task);
|
|
2834
2859
|
if (current && sameDefinitionValue(automationDefinition(current), definition)) return;
|
|
2835
2860
|
await db.insert(juniorAutomationVersions).values({
|
|
2836
|
-
kind,
|
|
2837
2861
|
automationId: task.id,
|
|
2838
2862
|
version: sql`(
|
|
2839
2863
|
SELECT coalesce(max(${juniorAutomationVersions.version}), 0) + 1
|
|
2840
2864
|
FROM ${juniorAutomationVersions}
|
|
2841
|
-
WHERE ${juniorAutomationVersions.
|
|
2842
|
-
AND ${juniorAutomationVersions.automationId} = ${task.id}
|
|
2865
|
+
WHERE ${juniorAutomationVersions.automationId} = ${task.id}
|
|
2843
2866
|
)`,
|
|
2844
2867
|
createdAtMs: Date.now(),
|
|
2845
2868
|
editedBy: editedBy ?? (current ? null : task.createdBy),
|
|
2846
2869
|
definition
|
|
2847
2870
|
});
|
|
2848
2871
|
}
|
|
2849
|
-
|
|
2872
|
+
const versionColumns = {
|
|
2873
|
+
createdAtMs: juniorAutomationVersions.createdAtMs,
|
|
2874
|
+
definition: juniorAutomationVersions.definition,
|
|
2875
|
+
editedBy: juniorAutomationVersions.editedBy,
|
|
2876
|
+
kind: juniorAutomations.kind,
|
|
2877
|
+
version: juniorAutomationVersions.version
|
|
2878
|
+
};
|
|
2879
|
+
function parseVersionRow(row) {
|
|
2850
2880
|
return automationVersionSchema.parse({
|
|
2851
|
-
kind,
|
|
2881
|
+
kind: row.kind,
|
|
2852
2882
|
version: row.version,
|
|
2853
2883
|
createdAt: new Date(row.createdAtMs).toISOString(),
|
|
2854
2884
|
editedBy: row.editedBy,
|
|
@@ -2856,13 +2886,13 @@ function parseVersionRow(kind, row) {
|
|
|
2856
2886
|
});
|
|
2857
2887
|
}
|
|
2858
2888
|
/** Read one saved definition. */
|
|
2859
|
-
async function readAutomationVersion(db,
|
|
2860
|
-
const [row] = await db.select().from(juniorAutomationVersions).
|
|
2861
|
-
return row ? parseVersionRow(
|
|
2889
|
+
async function readAutomationVersion(db, automationId, version) {
|
|
2890
|
+
const [row] = await db.select(versionColumns).from(juniorAutomationVersions).innerJoin(juniorAutomations, eq(juniorAutomations.id, juniorAutomationVersions.automationId)).where(and(eq(juniorAutomationVersions.automationId, automationId), eq(juniorAutomationVersions.version, version))).limit(1);
|
|
2891
|
+
return row ? parseVersionRow(row) : void 0;
|
|
2862
2892
|
}
|
|
2863
2893
|
/** Read saved definitions, newest first. */
|
|
2864
|
-
async function listAutomationVersions(db,
|
|
2865
|
-
return (await db.select().from(juniorAutomationVersions).
|
|
2894
|
+
async function listAutomationVersions(db, automationId, limit) {
|
|
2895
|
+
return (await db.select(versionColumns).from(juniorAutomationVersions).innerJoin(juniorAutomations, eq(juniorAutomations.id, juniorAutomationVersions.automationId)).where(eq(juniorAutomationVersions.automationId, automationId)).orderBy(desc(juniorAutomationVersions.version)).limit(limit)).map(parseVersionRow);
|
|
2866
2896
|
}
|
|
2867
2897
|
//#endregion
|
|
2868
2898
|
//#region src/chat/event-automations/run-limit.ts
|
|
@@ -2935,99 +2965,78 @@ async function clearEventAutomationRuns(automationId, state = getStateAdapter())
|
|
|
2935
2965
|
}
|
|
2936
2966
|
//#endregion
|
|
2937
2967
|
//#region src/chat/event-automations/store.ts
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
status:
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
|
|
2950
|
-
|
|
2951
|
-
|
|
2968
|
+
/**
|
|
2969
|
+
* Validate an event automation and split it into its SQL columns. Lifecycle
|
|
2970
|
+
* columns are written separately.
|
|
2971
|
+
*/
|
|
2972
|
+
function eventAutomationColumns(task) {
|
|
2973
|
+
const { status: _status, statusReason: _statusReason, title, ...definition } = task;
|
|
2974
|
+
const { createdAtMs: _createdAtMs, id: _id, ...record } = eventAutomationSchema.parse(definition);
|
|
2975
|
+
return {
|
|
2976
|
+
channelId: record.destination.channelId,
|
|
2977
|
+
creatorSlackUserId: record.createdBy.slackUserId,
|
|
2978
|
+
identifier: record.trigger.identifier,
|
|
2979
|
+
instruction: record.task.text,
|
|
2980
|
+
namespace: record.trigger.namespace,
|
|
2981
|
+
record,
|
|
2982
|
+
teamId: record.destination.teamId,
|
|
2983
|
+
title: title?.trim() || null
|
|
2984
|
+
};
|
|
2952
2985
|
}
|
|
2953
|
-
/** Decode
|
|
2986
|
+
/** Decode an event Automation row with its SQL-backed fields. */
|
|
2954
2987
|
function parseEventAutomationRow(row) {
|
|
2955
|
-
const
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
}];
|
|
2961
|
-
const retained = retainedEventAutomationSchema.parse(raw);
|
|
2962
|
-
const { threadTs: _threadTs, ...destination } = retained.destination;
|
|
2988
|
+
const task = eventAutomationSchema.parse({
|
|
2989
|
+
...row.record,
|
|
2990
|
+
createdAtMs: row.createdAtMs,
|
|
2991
|
+
id: row.id
|
|
2992
|
+
});
|
|
2963
2993
|
const title = row.title?.trim();
|
|
2964
2994
|
return {
|
|
2965
|
-
...
|
|
2966
|
-
|
|
2967
|
-
outcomes: retained.outcomes.map((outcome) => {
|
|
2968
|
-
const { threadTs: _threadTs, ...destination } = outcome.destination;
|
|
2969
|
-
return {
|
|
2970
|
-
...outcome,
|
|
2971
|
-
destination
|
|
2972
|
-
};
|
|
2973
|
-
}),
|
|
2974
|
-
status: row.status ?? "active",
|
|
2995
|
+
...task,
|
|
2996
|
+
status: row.status,
|
|
2975
2997
|
...row.statusReason ? { statusReason: row.statusReason } : void 0,
|
|
2976
2998
|
...title ? { title } : void 0
|
|
2977
2999
|
};
|
|
2978
3000
|
}
|
|
3001
|
+
function eventAutomationWhere(id) {
|
|
3002
|
+
return and(eq(juniorAutomations.id, id), eq(juniorAutomations.kind, "event"));
|
|
3003
|
+
}
|
|
2979
3004
|
function activeEventAutomationWhere() {
|
|
2980
|
-
return ne(
|
|
3005
|
+
return and(eq(juniorAutomations.kind, "event"), ne(juniorAutomations.status, "deleted"));
|
|
2981
3006
|
}
|
|
2982
3007
|
/** Read one event automation by id, including deleted rows when present. */
|
|
2983
3008
|
async function getEventAutomation(db, id) {
|
|
2984
|
-
const rows = await db.select(
|
|
3009
|
+
const rows = await db.select().from(juniorAutomations).where(eventAutomationWhere(id)).limit(1);
|
|
2985
3010
|
return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
|
|
2986
3011
|
}
|
|
2987
3012
|
/** Create one retry-stable event automation, or revive a deleted row with the new payload. */
|
|
2988
3013
|
async function createEventAutomation(db, task) {
|
|
2989
|
-
const
|
|
2990
|
-
|
|
2991
|
-
if ((await getEventAutomation(db, parsed.id))?.status === "deleted") await clearEventAutomationRuns(parsed.id);
|
|
3014
|
+
const columns = eventAutomationColumns(task);
|
|
3015
|
+
if ((await getEventAutomation(db, task.id))?.status === "deleted") await clearEventAutomationRuns(task.id);
|
|
2992
3016
|
return db.transaction(async (tx) => {
|
|
2993
|
-
const inserted = await tx.insert(
|
|
2994
|
-
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
title,
|
|
3001
|
-
task: parsed
|
|
3002
|
-
}).onConflictDoNothing().returning({ ...eventAutomationRowColumns });
|
|
3017
|
+
const inserted = await tx.insert(juniorAutomations).values({
|
|
3018
|
+
...columns,
|
|
3019
|
+
createdAtMs: task.createdAtMs,
|
|
3020
|
+
id: task.id,
|
|
3021
|
+
kind: "event",
|
|
3022
|
+
status: "active"
|
|
3023
|
+
}).onConflictDoNothing().returning();
|
|
3003
3024
|
if (inserted[0]) {
|
|
3004
3025
|
const created = parseEventAutomationRow(inserted[0]);
|
|
3005
|
-
await recordAutomationVersion(tx,
|
|
3026
|
+
await recordAutomationVersion(tx, created, void 0);
|
|
3006
3027
|
return created;
|
|
3007
3028
|
}
|
|
3008
|
-
const existing = await getEventAutomation(tx,
|
|
3009
|
-
if (!existing)
|
|
3010
|
-
...parsed,
|
|
3011
|
-
status: "active",
|
|
3012
|
-
...title ? { title } : void 0
|
|
3013
|
-
};
|
|
3029
|
+
const existing = await getEventAutomation(tx, task.id);
|
|
3030
|
+
if (!existing) throw new Error(`Automation ${task.id} already exists with another kind.`);
|
|
3014
3031
|
if (existing.status !== "deleted") return existing;
|
|
3015
|
-
const rows = await tx.update(
|
|
3016
|
-
|
|
3017
|
-
namespace: parsed.trigger.namespace,
|
|
3018
|
-
identifier: parsed.trigger.identifier,
|
|
3019
|
-
status: "active",
|
|
3020
|
-
statusReason: null,
|
|
3021
|
-
title,
|
|
3022
|
-
task: parsed
|
|
3023
|
-
}).where(and(eq(juniorEventAutomations.id, parsed.id), eq(juniorEventAutomations.status, "deleted"))).returning({ ...eventAutomationRowColumns });
|
|
3024
|
-
if (!rows[0]) return await getEventAutomation(tx, parsed.id) ?? {
|
|
3025
|
-
...parsed,
|
|
3032
|
+
const rows = await tx.update(juniorAutomations).set({
|
|
3033
|
+
...columns,
|
|
3026
3034
|
status: "active",
|
|
3027
|
-
|
|
3028
|
-
};
|
|
3035
|
+
statusReason: null
|
|
3036
|
+
}).where(and(eventAutomationWhere(task.id), eq(juniorAutomations.status, "deleted"))).returning();
|
|
3037
|
+
if (!rows[0]) return await getEventAutomation(tx, task.id);
|
|
3029
3038
|
const revived = parseEventAutomationRow(rows[0]);
|
|
3030
|
-
await recordAutomationVersion(tx,
|
|
3039
|
+
await recordAutomationVersion(tx, revived, void 0);
|
|
3031
3040
|
return revived;
|
|
3032
3041
|
});
|
|
3033
3042
|
}
|
|
@@ -3036,31 +3045,25 @@ async function createEventAutomation(db, task) {
|
|
|
3036
3045
|
* Pass `editedBy` when a person changes the definition so its version names them.
|
|
3037
3046
|
*/
|
|
3038
3047
|
async function saveEventAutomation(db, task, expectedRevision, editedBy) {
|
|
3039
|
-
const
|
|
3040
|
-
const title = task.title?.trim() || null;
|
|
3048
|
+
const columns = eventAutomationColumns(task);
|
|
3041
3049
|
return db.transaction(async (tx) => {
|
|
3042
|
-
const rows = await tx.select(
|
|
3050
|
+
const rows = await tx.select().from(juniorAutomations).where(eventAutomationWhere(task.id)).for("update");
|
|
3043
3051
|
const current = rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
|
|
3044
3052
|
if (expectedRevision !== void 0) requireAutomationRevision(current, expectedRevision);
|
|
3045
3053
|
if (!current || current.status === "deleted") return void 0;
|
|
3046
|
-
const saved = parseEventAutomationRow((await tx.update(
|
|
3047
|
-
|
|
3048
|
-
identifier: parsed.trigger.identifier,
|
|
3049
|
-
title,
|
|
3050
|
-
task: parsed
|
|
3051
|
-
}).where(eq(juniorEventAutomations.id, parsed.id)).returning({ ...eventAutomationRowColumns }))[0]);
|
|
3052
|
-
await recordAutomationVersion(tx, "event", saved, current, editedBy);
|
|
3054
|
+
const saved = parseEventAutomationRow((await tx.update(juniorAutomations).set(columns).where(eventAutomationWhere(task.id)).returning())[0]);
|
|
3055
|
+
await recordAutomationVersion(tx, saved, current, editedBy);
|
|
3053
3056
|
return saved;
|
|
3054
3057
|
});
|
|
3055
3058
|
}
|
|
3056
3059
|
/** Mark one existing event automation deleted while retaining the row for history. */
|
|
3057
3060
|
async function deleteEventAutomation(db, id) {
|
|
3058
|
-
const rows = await db.update(
|
|
3061
|
+
const rows = await db.update(juniorAutomations).set({ status: "deleted" }).where(and(eq(juniorAutomations.id, id), activeEventAutomationWhere())).returning();
|
|
3059
3062
|
return rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
|
|
3060
3063
|
}
|
|
3061
3064
|
/** List live event automations in one Slack workspace. */
|
|
3062
3065
|
async function listEventAutomationsForTeam(db, teamId) {
|
|
3063
|
-
return (await db.select(
|
|
3066
|
+
return (await db.select().from(juniorAutomations).where(and(eq(juniorAutomations.teamId, teamId), activeEventAutomationWhere())).orderBy(asc(juniorAutomations.createdAtMs), asc(juniorAutomations.id))).map(parseEventAutomationRow);
|
|
3064
3067
|
}
|
|
3065
3068
|
function viewerSlackIdentities(user) {
|
|
3066
3069
|
return user.identities.filter((identity) => identity.provider === "slack" && Boolean(identity.providerTenantId) && Boolean(identity.providerSubjectId));
|
|
@@ -3075,9 +3078,9 @@ function eventAutomationBelongsToUser(task, user) {
|
|
|
3075
3078
|
*/
|
|
3076
3079
|
async function listDeletedEventAutomationsCreatedBy(db, user, limit) {
|
|
3077
3080
|
const identities = viewerSlackIdentities(user);
|
|
3078
|
-
const ownership = or(...identities.map((identity) => and(eq(
|
|
3081
|
+
const ownership = or(...identities.map((identity) => and(eq(juniorAutomations.teamId, identity.providerTenantId), eq(juniorAutomations.creatorSlackUserId, identity.providerSubjectId))));
|
|
3079
3082
|
if (!ownership) return [];
|
|
3080
|
-
return (await db.select(
|
|
3083
|
+
return (await db.select().from(juniorAutomations).where(and(ownership, eq(juniorAutomations.kind, "event"), eq(juniorAutomations.status, "deleted"))).orderBy(desc(juniorAutomations.createdAtMs), desc(juniorAutomations.id)).limit(limit)).map(parseEventAutomationRow);
|
|
3081
3084
|
}
|
|
3082
3085
|
/**
|
|
3083
3086
|
* Collect match keys from live event automations for these identifiers and event types.
|
|
@@ -3087,7 +3090,7 @@ async function collectEventAutomationMatchKeys(db, input) {
|
|
|
3087
3090
|
const eventTypes = new Set(input.eventTypes.map((eventType) => eventType.trim()).filter(Boolean));
|
|
3088
3091
|
const identifiers = [...new Set(input.identifiers.map((value) => value.trim()).filter(Boolean))];
|
|
3089
3092
|
if (eventTypes.size === 0 || identifiers.length === 0) return [];
|
|
3090
|
-
const rows = await db.select(
|
|
3093
|
+
const rows = await db.select().from(juniorAutomations).where(and(eq(juniorAutomations.kind, "event"), eq(juniorAutomations.teamId, input.teamId), eq(juniorAutomations.namespace, input.namespace), inArray(juniorAutomations.identifier, identifiers), eq(juniorAutomations.status, "active"))).orderBy(asc(juniorAutomations.createdAtMs), asc(juniorAutomations.id));
|
|
3091
3094
|
const keys = /* @__PURE__ */ new Set();
|
|
3092
3095
|
for (const row of rows) {
|
|
3093
3096
|
const task = parseEventAutomationRow(row);
|
|
@@ -3098,7 +3101,7 @@ async function collectEventAutomationMatchKeys(db, input) {
|
|
|
3098
3101
|
}
|
|
3099
3102
|
/** Find every live task matching one normalized event. */
|
|
3100
3103
|
async function findMatchingEventAutomations(db, event, teamId) {
|
|
3101
|
-
return (await db.select(
|
|
3104
|
+
return (await db.select().from(juniorAutomations).where(and(eq(juniorAutomations.kind, "event"), eq(juniorAutomations.teamId, teamId), eq(juniorAutomations.namespace, event.namespace), eq(juniorAutomations.identifier, event.identifier), eq(juniorAutomations.status, "active"))).orderBy(asc(juniorAutomations.createdAtMs), asc(juniorAutomations.id))).map(parseEventAutomationRow).filter((task) => task.trigger.events.includes(event.eventType) && eventMatches(task.trigger.match, event.data));
|
|
3102
3105
|
}
|
|
3103
3106
|
/**
|
|
3104
3107
|
* Change lifecycle under the same row lock as edits, without changing
|
|
@@ -3109,7 +3112,7 @@ async function findMatchingEventAutomations(db, event, teamId) {
|
|
|
3109
3112
|
async function setEventAutomationStatus(db, id, status, revision) {
|
|
3110
3113
|
if (status === "active" && (await getEventAutomation(db, id))?.status !== "active") await clearEventAutomationRuns(id);
|
|
3111
3114
|
return db.transaction(async (tx) => {
|
|
3112
|
-
const rows = await tx.select().from(
|
|
3115
|
+
const rows = await tx.select().from(juniorAutomations).where(eventAutomationWhere(id)).for("update");
|
|
3113
3116
|
const current = rows[0] ? parseEventAutomationRow(rows[0]) : void 0;
|
|
3114
3117
|
requireAutomationRevision(current, revision);
|
|
3115
3118
|
if (!current || current.status === "deleted") throw new Error("Automation no longer exists.");
|
|
@@ -3123,10 +3126,10 @@ async function setEventAutomationStatus(db, id, status, revision) {
|
|
|
3123
3126
|
status,
|
|
3124
3127
|
statusReason: void 0
|
|
3125
3128
|
};
|
|
3126
|
-
await tx.update(
|
|
3129
|
+
await tx.update(juniorAutomations).set({
|
|
3127
3130
|
status: next.status,
|
|
3128
3131
|
statusReason: next.statusReason ?? null
|
|
3129
|
-
}).where(
|
|
3132
|
+
}).where(eventAutomationWhere(id));
|
|
3130
3133
|
const { statusReason: _statusReason, ...rest } = current;
|
|
3131
3134
|
return {
|
|
3132
3135
|
...rest,
|
|
@@ -3144,65 +3147,31 @@ async function setEventAutomationStatus(db, id, status, revision) {
|
|
|
3144
3147
|
* an automation that the dashboard shows as paused.
|
|
3145
3148
|
*/
|
|
3146
3149
|
async function blockEventAutomation(db, id, reason) {
|
|
3147
|
-
return (await db.update(
|
|
3148
|
-
status: sql`case when ${
|
|
3150
|
+
return (await db.update(juniorAutomations).set({
|
|
3151
|
+
status: sql`case when ${juniorAutomations.status} = 'active' then 'blocked' else ${juniorAutomations.status} end`,
|
|
3149
3152
|
statusReason: reason
|
|
3150
|
-
}).where(and(
|
|
3153
|
+
}).where(and(eventAutomationWhere(id), or(eq(juniorAutomations.status, "active"), and(eq(juniorAutomations.status, "paused"), sql`${juniorAutomations.statusReason} is distinct from ${reason}`)))).returning({ status: juniorAutomations.status }))[0]?.status === "blocked";
|
|
3151
3154
|
}
|
|
3152
3155
|
//#endregion
|
|
3153
3156
|
//#region src/chat/scheduled-automations/tasks.ts
|
|
3154
3157
|
const SCHEDULER_KEY_PREFIX = "junior:scheduler";
|
|
3155
|
-
|
|
3156
|
-
creatorIdentityId: true,
|
|
3157
|
-
title: true
|
|
3158
|
-
}).extend({
|
|
3159
|
-
destination: slackDestinationSchema,
|
|
3160
|
-
outcomes: z.array(taskOutcomeSchema).max(5),
|
|
3161
|
-
version: z.number().optional()
|
|
3162
|
-
}).strict();
|
|
3163
|
-
/** Decode a retained scheduler task row and reject invalid routing context. */
|
|
3158
|
+
/** Decode a Scheduled automation row. Returns undefined for an invalid row. */
|
|
3164
3159
|
function parseScheduledAutomationRow(row) {
|
|
3165
|
-
const
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
} : retained;
|
|
3175
|
-
const parsed = retainedScheduledAutomationSchema.safeParse(current);
|
|
3176
|
-
if (!parsed.success) return void 0;
|
|
3177
|
-
const { status, version: _version, ...retainedTask } = parsed.data;
|
|
3178
|
-
const destination = {
|
|
3179
|
-
platform: "slack",
|
|
3180
|
-
teamId: retainedTask.destination.teamId,
|
|
3181
|
-
channelId: retainedTask.destination.channelId
|
|
3182
|
-
};
|
|
3183
|
-
const task = {
|
|
3184
|
-
...retainedTask,
|
|
3185
|
-
destination,
|
|
3186
|
-
outcomes: retainedTask.outcomes.map((outcome) => ({
|
|
3187
|
-
...outcome,
|
|
3188
|
-
destination: {
|
|
3189
|
-
platform: "slack",
|
|
3190
|
-
teamId: outcome.destination.teamId,
|
|
3191
|
-
channelId: outcome.destination.channelId
|
|
3192
|
-
}
|
|
3193
|
-
}))
|
|
3194
|
-
};
|
|
3195
|
-
const fallbackIdentity = row.creatorIdentityId === null ? z.string().safeParse(legacyCreatorIdentityId) : void 0;
|
|
3196
|
-
const creatorIdentityId = row.creatorIdentityId ?? (fallbackIdentity?.success ? fallbackIdentity.data : void 0);
|
|
3197
|
-
if (creatorIdentityId === void 0) return void 0;
|
|
3198
|
-
const fallbackTitle = row.title === null ? z.string().safeParse(legacyTitle) : void 0;
|
|
3199
|
-
const title = (row.title !== null ? row.title : fallbackTitle?.success ? fallbackTitle.data : void 0)?.trim() || void 0;
|
|
3200
|
-
return {
|
|
3201
|
-
...task,
|
|
3202
|
-
creatorIdentityId,
|
|
3203
|
-
status,
|
|
3204
|
-
...title ? { title } : void 0
|
|
3160
|
+
const columns = {
|
|
3161
|
+
createdAtMs: row.createdAtMs,
|
|
3162
|
+
creatorIdentityId: row.creatorIdentityId,
|
|
3163
|
+
id: row.id,
|
|
3164
|
+
nextRunAtMs: row.nextRunAtMs,
|
|
3165
|
+
runNowAtMs: row.runNowAtMs,
|
|
3166
|
+
status: row.status,
|
|
3167
|
+
statusReason: row.statusReason,
|
|
3168
|
+
title: row.title
|
|
3205
3169
|
};
|
|
3170
|
+
const parsed = scheduledAutomationSchema.safeParse({
|
|
3171
|
+
...row.record,
|
|
3172
|
+
...Object.fromEntries(Object.entries(columns).filter(([, value]) => value !== null))
|
|
3173
|
+
});
|
|
3174
|
+
return parsed.success ? parsed.data : void 0;
|
|
3206
3175
|
}
|
|
3207
3176
|
/** Keep scan paths from returning current or legacy tombstones. */
|
|
3208
3177
|
function isListedScheduledAutomation(task) {
|
|
@@ -3229,53 +3198,38 @@ function requireStoredTask(task) {
|
|
|
3229
3198
|
...normalizedTitle ? { title: normalizedTitle } : void 0
|
|
3230
3199
|
};
|
|
3231
3200
|
}
|
|
3232
|
-
function scheduledAutomationJsonRecord(task) {
|
|
3233
|
-
const { title: _title, ...record } = task;
|
|
3234
|
-
return record;
|
|
3235
|
-
}
|
|
3236
3201
|
async function upsertScheduledAutomation(db, task) {
|
|
3237
|
-
const title = task
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3244
|
-
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3202
|
+
const { createdAtMs, creatorIdentityId, id, nextRunAtMs, runNowAtMs, status, statusReason, title, ...record } = task;
|
|
3203
|
+
const columns = {
|
|
3204
|
+
channelId: record.destination.channelId,
|
|
3205
|
+
createdAtMs,
|
|
3206
|
+
creatorIdentityId,
|
|
3207
|
+
creatorSlackUserId: record.createdBy.slackUserId,
|
|
3208
|
+
instruction: record.task.text,
|
|
3209
|
+
nextRunAtMs: nextRunAtMs ?? null,
|
|
3210
|
+
record,
|
|
3211
|
+
runNowAtMs: runNowAtMs ?? null,
|
|
3212
|
+
status,
|
|
3213
|
+
statusReason: statusReason ?? null,
|
|
3214
|
+
teamId: record.destination.teamId,
|
|
3215
|
+
title: title?.trim() || null
|
|
3216
|
+
};
|
|
3217
|
+
await db.insert(juniorAutomations).values({
|
|
3218
|
+
...columns,
|
|
3219
|
+
id,
|
|
3220
|
+
kind: "scheduled"
|
|
3249
3221
|
}).onConflictDoUpdate({
|
|
3250
|
-
target:
|
|
3251
|
-
set:
|
|
3252
|
-
createdAtMs: sql`excluded.created_at_ms`,
|
|
3253
|
-
creatorIdentityId: sql`excluded.creator_identity_id`,
|
|
3254
|
-
creatorSlackUserId: sql`excluded.creator_slack_user_id`,
|
|
3255
|
-
nextRunAtMs: sql`excluded.next_run_at_ms`,
|
|
3256
|
-
record: sql`excluded.record`,
|
|
3257
|
-
runNowAtMs: sql`excluded.run_now_at_ms`,
|
|
3258
|
-
status: sql`excluded.status`,
|
|
3259
|
-
teamId: sql`excluded.team_id`,
|
|
3260
|
-
title: sql`excluded.title`
|
|
3261
|
-
}
|
|
3222
|
+
target: juniorAutomations.id,
|
|
3223
|
+
set: columns
|
|
3262
3224
|
});
|
|
3263
3225
|
}
|
|
3264
3226
|
/** Read and decode one scheduled automation. */
|
|
3265
3227
|
async function readScheduledAutomation(db, taskId) {
|
|
3266
|
-
const rows = await db.select(
|
|
3267
|
-
creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
|
|
3268
|
-
record: juniorSchedulerTasks.record,
|
|
3269
|
-
title: juniorSchedulerTasks.title
|
|
3270
|
-
}).from(juniorSchedulerTasks).where(eq(juniorSchedulerTasks.id, taskId)).limit(1);
|
|
3228
|
+
const rows = await db.select().from(juniorAutomations).where(and(eq(juniorAutomations.id, taskId), eq(juniorAutomations.kind, "scheduled"))).limit(1);
|
|
3271
3229
|
return rows[0] ? parseScheduledAutomationRow(rows[0]) : void 0;
|
|
3272
3230
|
}
|
|
3273
3231
|
async function readListedScheduledAutomations(db, teamId) {
|
|
3274
|
-
return (await db.select(
|
|
3275
|
-
creatorIdentityId: juniorSchedulerTasks.creatorIdentityId,
|
|
3276
|
-
record: juniorSchedulerTasks.record,
|
|
3277
|
-
title: juniorSchedulerTasks.title
|
|
3278
|
-
}).from(juniorSchedulerTasks).where(and(notInArray(juniorSchedulerTasks.status, ["deleted"]), teamId === void 0 ? void 0 : eq(juniorSchedulerTasks.teamId, teamId))).orderBy(asc(juniorSchedulerTasks.createdAtMs), asc(juniorSchedulerTasks.id))).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
|
|
3232
|
+
return (await db.select().from(juniorAutomations).where(and(eq(juniorAutomations.kind, "scheduled"), ne(juniorAutomations.status, "deleted"), teamId === void 0 ? void 0 : eq(juniorAutomations.teamId, teamId))).orderBy(asc(juniorAutomations.createdAtMs), asc(juniorAutomations.id))).map(parseScheduledAutomationRow).filter(isListedScheduledAutomation);
|
|
3279
3233
|
}
|
|
3280
3234
|
/** List decoded scheduled automations in stable creation order. */
|
|
3281
3235
|
async function listScheduledAutomations(db) {
|
|
@@ -3289,7 +3243,7 @@ async function writeScheduledAutomation(db, task, current, editedBy) {
|
|
|
3289
3243
|
if (current?.status === "blocked" && task.status === "active" && typeof task.nextRunAtMs === "number" && Number.isFinite(task.nextRunAtMs)) await db.delete(juniorSchedulerRuns).where(and(eq(juniorSchedulerRuns.id, scheduledRunId(task.id, task.nextRunAtMs)), eq(juniorSchedulerRuns.status, "blocked")));
|
|
3290
3244
|
if (task.status === "deleted" && current?.status !== "deleted") await skipPendingRunsForDeletedTask(db, task);
|
|
3291
3245
|
await upsertScheduledAutomation(db, task);
|
|
3292
|
-
await recordAutomationVersion(db,
|
|
3246
|
+
await recordAutomationVersion(db, task, current, editedBy);
|
|
3293
3247
|
}
|
|
3294
3248
|
async function skipPendingRunsForDeletedTask(db, task) {
|
|
3295
3249
|
const errorMessage = `Scheduled automation ${task.id} was deleted before the run started.`;
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { I as isRecord, L as toOptionalNumber, R as toOptionalString } from "./logging-
|
|
2
|
-
import { d as getDb } from "./viewer-
|
|
1
|
+
import { I as isRecord, L as toOptionalNumber, R as toOptionalString } from "./logging-COUsTFIL.js";
|
|
2
|
+
import { d as getDb } from "./viewer-D96vo_42.js";
|
|
3
3
|
import { d as juniorDestinations } from "./agent-invocations-D_YoNnAn.js";
|
|
4
|
-
import {
|
|
5
|
-
import { Kt as persistConversationMessages } from "./tasks-
|
|
6
|
-
import {
|
|
7
|
-
import { w as getStateAdapter } from "./profile-
|
|
4
|
+
import { u as juniorLocationConfigurations } from "./executor-_4bdoCxe.js";
|
|
5
|
+
import { Kt as persistConversationMessages } from "./tasks-DwGlFX9i.js";
|
|
6
|
+
import { it as JUNIOR_THREAD_STATE_TTL_MS } from "./agent-hooks-DcoKnnxn.js";
|
|
7
|
+
import { w as getStateAdapter } from "./profile-DP4LKL6V.js";
|
|
8
8
|
import { z } from "zod";
|
|
9
9
|
import { randomUUID } from "node:crypto";
|
|
10
10
|
import { and, eq, sql } from "drizzle-orm";
|