@sentry/junior 0.108.0 → 0.109.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-NU5HK3PS.js → agent-hooks-FHHVLNPA.js} +12 -12
- package/dist/api/conversations/events.d.ts +1 -1
- package/dist/api/conversations/schema.d.ts +57 -6
- package/dist/api/schema.js +1 -1
- package/dist/api.js +108 -22
- package/dist/app.d.ts +1 -0
- package/dist/app.js +1481 -420
- package/dist/{catalog-runtime-FOFNPR3P.js → catalog-runtime-DMGJSLV2.js} +6 -4
- package/dist/chat/conversations/sql/store.d.ts +0 -7
- package/dist/chat/log-context.d.ts +40 -0
- package/dist/chat/logging.d.ts +3 -26
- package/dist/chat/runtime/slack-resume.d.ts +2 -2
- package/dist/chat/services/turn-session-record.d.ts +0 -2
- package/dist/chat/slack/reply.d.ts +7 -19
- package/dist/chat/state/conversation.d.ts +1 -0
- package/dist/chat/task-execution/slack-work.d.ts +2 -2
- package/dist/chunk-3SXUV423.js +10 -0
- package/dist/{chunk-3RGQLX2F.js → chunk-72OMGPDS.js} +1010 -26
- package/dist/{chunk-2XXEKR44.js → chunk-7Q6WCISF.js} +1 -1
- package/dist/{chunk-TE4QHJH4.js → chunk-FENLIFJD.js} +72 -591
- package/dist/{chunk-XKB7LGIW.js → chunk-FWJRXN4F.js} +3 -3
- package/dist/{chunk-PUAMO4PI.js → chunk-HHVY4SMP.js} +41 -7
- package/dist/{chunk-B5I5LMSP.js → chunk-HO5NT6OE.js} +5 -7
- package/dist/{chunk-O24R4DCK.js → chunk-ISMWX44P.js} +93 -55
- package/dist/{chunk-7FBGKXPE.js → chunk-IVVGFRQQ.js} +5 -0
- package/dist/{chunk-KPMPQ6AA.js → chunk-IXKSQGIO.js} +90 -100
- package/dist/{chunk-SS67LUOK.js → chunk-JNAVF45E.js} +6 -7
- package/dist/{chunk-DY7TRYB5.js → chunk-MGUMR35T.js} +1 -1
- package/dist/{chunk-A5CO2EHL.js → chunk-MXW4GL53.js} +11 -15
- package/dist/{chunk-RT5BUHR5.js → chunk-O3JMSZLI.js} +1 -1
- package/dist/chunk-OCD3OZRK.js +125 -0
- package/dist/{chunk-H3QYZL7K.js → chunk-OUHNWH46.js} +28 -3
- package/dist/{chunk-VIXFG2VC.js → chunk-PLB7MRCQ.js} +1 -2
- package/dist/{chunk-UD6THJ2I.js → chunk-QY636HZU.js} +114 -12
- package/dist/{chunk-VH6KWKG2.js → chunk-RGX4V75M.js} +3 -3
- package/dist/{chunk-B7PUBQQM.js → chunk-SYAQIR5Z.js} +1 -1
- package/dist/chunk-TMBRFULF.js +471 -0
- package/dist/{chunk-YIPD3L6L.js → chunk-TT6GMXNA.js} +8 -10
- package/dist/{chunk-YT72TOEK.js → chunk-WHMOBKT7.js} +2 -2
- package/dist/cli/chat.js +23 -23
- package/dist/cli/check.js +8 -6
- package/dist/cli/plugins.js +16 -16
- package/dist/cli/snapshot-warmup.js +10 -9
- package/dist/cli/upgrade.js +314 -3505
- package/dist/db/db.d.ts +1 -1
- package/dist/{db-AMRBAT5D.js → db-V3NU72O2.js} +8 -6
- package/dist/instrumentation.js +3 -2
- package/dist/nitro.js +5 -4
- package/dist/{runner-TQH5GAJ4.js → runner-JYBCQBLK.js} +17 -20
- package/dist/{skills-ITNHBARB.js → skills-U6MDAST7.js} +7 -5
- package/dist/{validation-AGQ46ZGV.js → validation-72N3JVRU.js} +7 -5
- package/dist/version.d.ts +2 -0
- package/dist/version.js +7 -0
- package/migrations/0006_drop_legacy_conversation_messages.sql +1 -0
- package/migrations/README.md +12 -9
- package/migrations/meta/0006_snapshot.json +948 -0
- package/migrations/meta/_journal.json +7 -0
- package/package.json +9 -5
- package/dist/chunk-AHJR2IFF.js +0 -115
- package/dist/chunk-G3E7SCME.js +0 -28
- package/dist/chunk-J3B3FPP2.js +0 -1061
- package/dist/chunk-TWINAEZQ.js +0 -1283
|
@@ -1,38 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
} from "./chunk-
|
|
5
|
-
import {
|
|
6
|
-
SANDBOX_WORKSPACE_ROOT
|
|
7
|
-
} from "./chunk-G3E7SCME.js";
|
|
2
|
+
SANDBOX_WORKSPACE_ROOT,
|
|
3
|
+
getStateAdapter
|
|
4
|
+
} from "./chunk-OUHNWH46.js";
|
|
8
5
|
import {
|
|
9
6
|
isConversationChannel,
|
|
10
7
|
isConversationScopedChannel,
|
|
11
8
|
isDmChannel,
|
|
12
9
|
normalizeSlackConversationId
|
|
13
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-RGX4V75M.js";
|
|
14
11
|
import {
|
|
15
12
|
getDb
|
|
16
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-FENLIFJD.js";
|
|
17
14
|
import {
|
|
18
15
|
botConfig,
|
|
19
16
|
completeObject,
|
|
20
17
|
embedTexts,
|
|
21
18
|
standardModelId
|
|
22
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-JNAVF45E.js";
|
|
23
20
|
import {
|
|
24
21
|
isActorUserId,
|
|
25
22
|
parseActorUserId
|
|
26
|
-
} from "./chunk-
|
|
23
|
+
} from "./chunk-PLB7MRCQ.js";
|
|
27
24
|
import {
|
|
25
|
+
logException,
|
|
28
26
|
logInfo,
|
|
29
27
|
logWarn
|
|
30
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-ISMWX44P.js";
|
|
31
29
|
import {
|
|
32
30
|
parseSlackChannelReferenceId,
|
|
33
31
|
parseSlackMessageTs,
|
|
34
32
|
parseSlackTeamId
|
|
35
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-IVVGFRQQ.js";
|
|
36
34
|
|
|
37
35
|
// src/chat/plugins/agent-hooks.ts
|
|
38
36
|
import {
|
|
@@ -40,6 +38,37 @@ import {
|
|
|
40
38
|
resourceEventSchema
|
|
41
39
|
} from "@sentry/junior-plugin-api";
|
|
42
40
|
|
|
41
|
+
// src/chat/plugins/logging.ts
|
|
42
|
+
function createPluginLogger(plugin) {
|
|
43
|
+
return {
|
|
44
|
+
info(message, metadata) {
|
|
45
|
+
logInfo(
|
|
46
|
+
"agent_plugin_log_info",
|
|
47
|
+
{},
|
|
48
|
+
{ "app.plugin.name": plugin, ...metadata },
|
|
49
|
+
message
|
|
50
|
+
);
|
|
51
|
+
},
|
|
52
|
+
warn(message, metadata) {
|
|
53
|
+
logWarn(
|
|
54
|
+
"agent_plugin_log_warn",
|
|
55
|
+
{},
|
|
56
|
+
{ "app.plugin.name": plugin, ...metadata },
|
|
57
|
+
message
|
|
58
|
+
);
|
|
59
|
+
},
|
|
60
|
+
error(message, metadata) {
|
|
61
|
+
logException(
|
|
62
|
+
new Error(message),
|
|
63
|
+
"agent_plugin_log_error",
|
|
64
|
+
{},
|
|
65
|
+
{ "app.plugin.name": plugin, ...metadata },
|
|
66
|
+
message
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
|
|
43
72
|
// src/chat/plugins/model.ts
|
|
44
73
|
function createPluginModel(pluginName, options = {}, runtime = {}) {
|
|
45
74
|
return {
|
|
@@ -77,6 +106,77 @@ function createPluginEmbedder(pluginName, runtime = {}) {
|
|
|
77
106
|
};
|
|
78
107
|
}
|
|
79
108
|
|
|
109
|
+
// src/chat/plugins/state.ts
|
|
110
|
+
import { createHash } from "crypto";
|
|
111
|
+
var MAX_PLUGIN_STATE_KEY_LENGTH = 512;
|
|
112
|
+
function hashKeyPart(value) {
|
|
113
|
+
return createHash("sha256").update(value).digest("hex").slice(0, 32);
|
|
114
|
+
}
|
|
115
|
+
function pluginStateKey(plugin, key) {
|
|
116
|
+
const pluginPrefix = `junior:${plugin}`;
|
|
117
|
+
if (key === pluginPrefix || key.startsWith(`${pluginPrefix}:`)) {
|
|
118
|
+
return key;
|
|
119
|
+
}
|
|
120
|
+
return `junior:plugin_state:${hashKeyPart(plugin)}:${hashKeyPart(key)}`;
|
|
121
|
+
}
|
|
122
|
+
function validatePluginStateKey(key) {
|
|
123
|
+
if (!key.trim()) {
|
|
124
|
+
throw new Error("Plugin state key is required");
|
|
125
|
+
}
|
|
126
|
+
if (key.length > MAX_PLUGIN_STATE_KEY_LENGTH) {
|
|
127
|
+
throw new Error("Plugin state key exceeds the maximum length");
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
function createPluginState(plugin, adapter) {
|
|
131
|
+
const getAdapter = () => adapter ?? getStateAdapter();
|
|
132
|
+
return {
|
|
133
|
+
async delete(key) {
|
|
134
|
+
validatePluginStateKey(key);
|
|
135
|
+
const state = getAdapter();
|
|
136
|
+
await state.connect();
|
|
137
|
+
await state.delete(pluginStateKey(plugin, key));
|
|
138
|
+
},
|
|
139
|
+
async get(key) {
|
|
140
|
+
validatePluginStateKey(key);
|
|
141
|
+
const state = getAdapter();
|
|
142
|
+
await state.connect();
|
|
143
|
+
const value = await state.get(pluginStateKey(plugin, key));
|
|
144
|
+
return value ?? void 0;
|
|
145
|
+
},
|
|
146
|
+
async set(key, value, ttlMs) {
|
|
147
|
+
validatePluginStateKey(key);
|
|
148
|
+
const state = getAdapter();
|
|
149
|
+
await state.connect();
|
|
150
|
+
await state.set(pluginStateKey(plugin, key), value, ttlMs);
|
|
151
|
+
},
|
|
152
|
+
async setIfNotExists(key, value, ttlMs) {
|
|
153
|
+
validatePluginStateKey(key);
|
|
154
|
+
const state = getAdapter();
|
|
155
|
+
await state.connect();
|
|
156
|
+
return await state.setIfNotExists(
|
|
157
|
+
pluginStateKey(plugin, key),
|
|
158
|
+
value,
|
|
159
|
+
ttlMs
|
|
160
|
+
);
|
|
161
|
+
},
|
|
162
|
+
async withLock(key, ttlMs, callback) {
|
|
163
|
+
validatePluginStateKey(key);
|
|
164
|
+
const state = getAdapter();
|
|
165
|
+
await state.connect();
|
|
166
|
+
const lockKey = pluginStateKey(plugin, key);
|
|
167
|
+
const lock = await state.acquireLock(lockKey, ttlMs);
|
|
168
|
+
if (!lock) {
|
|
169
|
+
throw new Error(`Could not acquire plugin state lock for ${key}`);
|
|
170
|
+
}
|
|
171
|
+
try {
|
|
172
|
+
return await callback();
|
|
173
|
+
} finally {
|
|
174
|
+
await state.releaseLock(lock);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
|
|
80
180
|
// src/chat/slack/dashboard-link.ts
|
|
81
181
|
var dashboardConversationLinkOptions;
|
|
82
182
|
function withHttps(host) {
|
|
@@ -1105,8 +1205,10 @@ function createPluginHookRunner(input = {}) {
|
|
|
1105
1205
|
}
|
|
1106
1206
|
|
|
1107
1207
|
export {
|
|
1208
|
+
createPluginLogger,
|
|
1108
1209
|
createPluginModel,
|
|
1109
1210
|
createPluginEmbedder,
|
|
1211
|
+
createPluginState,
|
|
1110
1212
|
setDashboardConversationLinkOptions,
|
|
1111
1213
|
getDashboardConversationLink,
|
|
1112
1214
|
getSlackToolContext,
|
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
} from "./chunk-4ZNGQH7C.js";
|
|
4
4
|
import {
|
|
5
5
|
getSlackBotToken
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-JNAVF45E.js";
|
|
7
7
|
import {
|
|
8
8
|
logWarn,
|
|
9
9
|
setSpanAttributes,
|
|
10
10
|
setSpanStatus,
|
|
11
11
|
withSpan
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-ISMWX44P.js";
|
|
13
13
|
import {
|
|
14
14
|
parseSlackChannelReferenceId
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-IVVGFRQQ.js";
|
|
16
16
|
|
|
17
17
|
// src/chat/slack/client.ts
|
|
18
18
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
@@ -0,0 +1,471 @@
|
|
|
1
|
+
import {
|
|
2
|
+
juniorDestinations,
|
|
3
|
+
timestamptz
|
|
4
|
+
} from "./chunk-VFUK3X5B.js";
|
|
5
|
+
|
|
6
|
+
// src/db/neon.ts
|
|
7
|
+
import { AsyncLocalStorage } from "async_hooks";
|
|
8
|
+
import {
|
|
9
|
+
Pool
|
|
10
|
+
} from "@neondatabase/serverless";
|
|
11
|
+
import { drizzle } from "drizzle-orm/neon-serverless";
|
|
12
|
+
import { migrate } from "drizzle-orm/neon-serverless/migrator";
|
|
13
|
+
|
|
14
|
+
// src/db/schema/conversation-events.ts
|
|
15
|
+
import {
|
|
16
|
+
foreignKey,
|
|
17
|
+
index as index3,
|
|
18
|
+
integer as integer2,
|
|
19
|
+
jsonb as jsonb3,
|
|
20
|
+
pgTable as pgTable4,
|
|
21
|
+
primaryKey,
|
|
22
|
+
text as text4,
|
|
23
|
+
uniqueIndex as uniqueIndex3
|
|
24
|
+
} from "drizzle-orm/pg-core";
|
|
25
|
+
import { sql as sql3 } from "drizzle-orm";
|
|
26
|
+
|
|
27
|
+
// src/db/schema/conversations.ts
|
|
28
|
+
import { sql as sql2 } from "drizzle-orm";
|
|
29
|
+
import {
|
|
30
|
+
index as index2,
|
|
31
|
+
integer,
|
|
32
|
+
jsonb as jsonb2,
|
|
33
|
+
pgTable as pgTable3,
|
|
34
|
+
text as text3
|
|
35
|
+
} from "drizzle-orm/pg-core";
|
|
36
|
+
|
|
37
|
+
// src/db/schema/identities.ts
|
|
38
|
+
import { sql } from "drizzle-orm";
|
|
39
|
+
import {
|
|
40
|
+
boolean,
|
|
41
|
+
index,
|
|
42
|
+
jsonb,
|
|
43
|
+
pgTable as pgTable2,
|
|
44
|
+
text as text2,
|
|
45
|
+
uniqueIndex as uniqueIndex2
|
|
46
|
+
} from "drizzle-orm/pg-core";
|
|
47
|
+
|
|
48
|
+
// src/db/schema/users.ts
|
|
49
|
+
import { text, pgTable, uniqueIndex } from "drizzle-orm/pg-core";
|
|
50
|
+
var juniorUsers = pgTable(
|
|
51
|
+
"junior_users",
|
|
52
|
+
{
|
|
53
|
+
id: text("id").primaryKey(),
|
|
54
|
+
primaryEmail: text("primary_email").notNull(),
|
|
55
|
+
primaryEmailNormalized: text("primary_email_normalized").notNull(),
|
|
56
|
+
displayName: text("display_name"),
|
|
57
|
+
createdAt: timestamptz("created_at").notNull(),
|
|
58
|
+
updatedAt: timestamptz("updated_at").notNull()
|
|
59
|
+
},
|
|
60
|
+
(table) => [
|
|
61
|
+
uniqueIndex("junior_users_primary_email_normalized_uidx").on(
|
|
62
|
+
table.primaryEmailNormalized
|
|
63
|
+
)
|
|
64
|
+
]
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
// src/db/schema/identities.ts
|
|
68
|
+
var juniorIdentities = pgTable2(
|
|
69
|
+
"junior_identities",
|
|
70
|
+
{
|
|
71
|
+
id: text2("id").primaryKey(),
|
|
72
|
+
kind: text2("kind").$type().notNull(),
|
|
73
|
+
provider: text2("provider").notNull(),
|
|
74
|
+
providerTenantId: text2("provider_tenant_id").notNull().default(""),
|
|
75
|
+
providerSubjectId: text2("provider_subject_id").notNull(),
|
|
76
|
+
displayName: text2("display_name"),
|
|
77
|
+
handle: text2("handle"),
|
|
78
|
+
email: text2("email"),
|
|
79
|
+
avatarUrl: text2("avatar_url"),
|
|
80
|
+
metadata: jsonb("metadata_json"),
|
|
81
|
+
createdAt: timestamptz("created_at").notNull(),
|
|
82
|
+
updatedAt: timestamptz("updated_at").notNull(),
|
|
83
|
+
userId: text2("user_id").references(() => juniorUsers.id),
|
|
84
|
+
emailNormalized: text2("email_normalized"),
|
|
85
|
+
emailVerified: boolean("email_verified").notNull().default(false)
|
|
86
|
+
},
|
|
87
|
+
(table) => [
|
|
88
|
+
uniqueIndex2("junior_identities_provider_subject_uidx").on(
|
|
89
|
+
table.provider,
|
|
90
|
+
table.providerTenantId,
|
|
91
|
+
table.providerSubjectId
|
|
92
|
+
),
|
|
93
|
+
index("junior_identities_user_idx").on(table.userId),
|
|
94
|
+
index("junior_identities_verified_email_idx").on(table.emailNormalized).where(
|
|
95
|
+
sql`${table.emailVerified} = true AND ${table.emailNormalized} IS NOT NULL`
|
|
96
|
+
),
|
|
97
|
+
index("junior_identities_kind_provider_idx").on(table.kind, table.provider)
|
|
98
|
+
]
|
|
99
|
+
);
|
|
100
|
+
|
|
101
|
+
// src/db/schema/conversations.ts
|
|
102
|
+
var juniorConversations = pgTable3(
|
|
103
|
+
"junior_conversations",
|
|
104
|
+
{
|
|
105
|
+
conversationId: text3("conversation_id").primaryKey(),
|
|
106
|
+
schemaVersion: integer("schema_version").notNull().default(1),
|
|
107
|
+
source: text3("source").$type(),
|
|
108
|
+
originType: text3("origin_type"),
|
|
109
|
+
originId: text3("origin_id"),
|
|
110
|
+
originRunId: text3("origin_run_id"),
|
|
111
|
+
destinationId: text3("destination_id").references(
|
|
112
|
+
() => juniorDestinations.id
|
|
113
|
+
),
|
|
114
|
+
destination: jsonb2("destination_json").$type(),
|
|
115
|
+
actorIdentityId: text3("actor_identity_id").references(
|
|
116
|
+
() => juniorIdentities.id
|
|
117
|
+
),
|
|
118
|
+
creatorIdentityId: text3("creator_identity_id").references(
|
|
119
|
+
() => juniorIdentities.id
|
|
120
|
+
),
|
|
121
|
+
credentialSubjectIdentityId: text3(
|
|
122
|
+
"credential_subject_identity_id"
|
|
123
|
+
).references(() => juniorIdentities.id),
|
|
124
|
+
actor: jsonb2("actor_json").$type(),
|
|
125
|
+
channelName: text3("channel_name"),
|
|
126
|
+
title: text3("title"),
|
|
127
|
+
createdAt: timestamptz("created_at").notNull(),
|
|
128
|
+
lastActivityAt: timestamptz("last_activity_at").notNull(),
|
|
129
|
+
updatedAt: timestamptz("updated_at").notNull(),
|
|
130
|
+
executionUpdatedAt: timestamptz("execution_updated_at"),
|
|
131
|
+
executionStatus: text3("execution_status").$type().notNull(),
|
|
132
|
+
runId: text3("run_id"),
|
|
133
|
+
lastCheckpointAt: timestamptz("last_checkpoint_at"),
|
|
134
|
+
lastEnqueuedAt: timestamptz("last_enqueued_at"),
|
|
135
|
+
// Subagent runs are child conversations; top-level listings filter
|
|
136
|
+
// parent_conversation_id IS NULL. Historical advisor children use this too.
|
|
137
|
+
parentConversationId: text3("parent_conversation_id").references(
|
|
138
|
+
() => juniorConversations.conversationId
|
|
139
|
+
),
|
|
140
|
+
transcriptPurgedAt: timestamptz("transcript_purged_at"),
|
|
141
|
+
durationMs: integer("duration_ms").notNull().default(0),
|
|
142
|
+
usage: jsonb2("usage_json").$type(),
|
|
143
|
+
executionDurationMs: integer("execution_duration_ms").notNull().default(0),
|
|
144
|
+
executionUsage: jsonb2("execution_usage_json").$type(),
|
|
145
|
+
metricRunId: text3("metric_run_id"),
|
|
146
|
+
archivedAt: timestamptz("archived_at")
|
|
147
|
+
},
|
|
148
|
+
(table) => [
|
|
149
|
+
index2("junior_conversations_last_activity_idx").on(
|
|
150
|
+
table.lastActivityAt.desc(),
|
|
151
|
+
table.conversationId
|
|
152
|
+
),
|
|
153
|
+
index2("junior_conversations_active_idx").using(
|
|
154
|
+
"btree",
|
|
155
|
+
sql2`coalesce(${table.executionUpdatedAt}, ${table.updatedAt})`,
|
|
156
|
+
table.conversationId
|
|
157
|
+
).where(sql2`${table.executionStatus} <> 'idle'`),
|
|
158
|
+
index2("junior_conversations_destination_activity_idx").on(
|
|
159
|
+
table.destinationId,
|
|
160
|
+
table.lastActivityAt.desc()
|
|
161
|
+
),
|
|
162
|
+
index2("junior_conversations_actor_activity_idx").on(
|
|
163
|
+
table.actorIdentityId,
|
|
164
|
+
table.lastActivityAt.desc()
|
|
165
|
+
),
|
|
166
|
+
index2("junior_conversations_origin_idx").on(
|
|
167
|
+
table.originType,
|
|
168
|
+
table.originId,
|
|
169
|
+
table.lastActivityAt.desc()
|
|
170
|
+
),
|
|
171
|
+
index2("junior_conversations_parent_idx").on(table.parentConversationId)
|
|
172
|
+
]
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
// src/db/schema/conversation-events.ts
|
|
176
|
+
var juniorConversationEvents = pgTable4(
|
|
177
|
+
"junior_conversation_events",
|
|
178
|
+
{
|
|
179
|
+
conversationId: text4("conversation_id").notNull(),
|
|
180
|
+
seq: integer2("seq").notNull(),
|
|
181
|
+
historyVersion: integer2("history_version").notNull(),
|
|
182
|
+
schemaVersion: integer2("schema_version").default(1).notNull(),
|
|
183
|
+
idempotencyKey: text4("idempotency_key"),
|
|
184
|
+
type: text4("type").notNull(),
|
|
185
|
+
payload: jsonb3("payload").$type().notNull(),
|
|
186
|
+
createdAt: timestamptz("created_at").notNull()
|
|
187
|
+
},
|
|
188
|
+
(table) => [
|
|
189
|
+
primaryKey({
|
|
190
|
+
name: "junior_conversation_events_conversation_id_seq_pk",
|
|
191
|
+
columns: [table.conversationId, table.seq]
|
|
192
|
+
}),
|
|
193
|
+
foreignKey({
|
|
194
|
+
name: "junior_conversation_events_conversation_id_junior_conversations_conversation_id_fk",
|
|
195
|
+
columns: [table.conversationId],
|
|
196
|
+
foreignColumns: [juniorConversations.conversationId]
|
|
197
|
+
}),
|
|
198
|
+
index3("junior_conversation_events_history_version_idx").on(
|
|
199
|
+
table.conversationId,
|
|
200
|
+
table.historyVersion,
|
|
201
|
+
table.seq
|
|
202
|
+
),
|
|
203
|
+
index3("junior_conversation_events_type_idx").on(
|
|
204
|
+
table.conversationId,
|
|
205
|
+
table.type,
|
|
206
|
+
table.seq
|
|
207
|
+
),
|
|
208
|
+
index3("junior_conversation_events_message_search_idx").using("gin", sql3`to_tsvector('english', ${table.payload}->>'text')`).where(sql3`${table.type} = 'message'`),
|
|
209
|
+
uniqueIndex3("junior_conversation_events_idempotency_idx").on(
|
|
210
|
+
table.conversationId,
|
|
211
|
+
table.idempotencyKey
|
|
212
|
+
)
|
|
213
|
+
]
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// src/db/schema.ts
|
|
217
|
+
var juniorSqlSchema = {
|
|
218
|
+
juniorConversationEvents,
|
|
219
|
+
juniorConversations,
|
|
220
|
+
juniorDestinations,
|
|
221
|
+
juniorIdentities,
|
|
222
|
+
juniorUsers
|
|
223
|
+
};
|
|
224
|
+
|
|
225
|
+
// src/db/neon.ts
|
|
226
|
+
var NeonExecutor = class {
|
|
227
|
+
constructor(pool) {
|
|
228
|
+
this.pool = pool;
|
|
229
|
+
}
|
|
230
|
+
pool;
|
|
231
|
+
transactionClient = new AsyncLocalStorage();
|
|
232
|
+
savepointId = 0;
|
|
233
|
+
db() {
|
|
234
|
+
return drizzle(this.queryClient(), {
|
|
235
|
+
schema: juniorSqlSchema
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
async execute(statement, params = []) {
|
|
239
|
+
await this.queryClient().query(statement, [...params]);
|
|
240
|
+
}
|
|
241
|
+
async query(statement, params = []) {
|
|
242
|
+
const result = await this.queryClient().query(statement, [
|
|
243
|
+
...params
|
|
244
|
+
]);
|
|
245
|
+
return result.rows;
|
|
246
|
+
}
|
|
247
|
+
async migrate(config) {
|
|
248
|
+
await migrate(
|
|
249
|
+
drizzle(this.queryClient(), { schema: juniorSqlSchema }),
|
|
250
|
+
config
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
async transaction(callback) {
|
|
254
|
+
const existingClient = this.transactionClient.getStore();
|
|
255
|
+
if (existingClient) {
|
|
256
|
+
const savepoint = `junior_savepoint_${++this.savepointId}`;
|
|
257
|
+
await existingClient.query(`SAVEPOINT ${savepoint}`);
|
|
258
|
+
try {
|
|
259
|
+
const result = await callback();
|
|
260
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
261
|
+
return result;
|
|
262
|
+
} catch (error) {
|
|
263
|
+
await existingClient.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
264
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
265
|
+
throw error;
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
const client = await this.pool.connect();
|
|
269
|
+
try {
|
|
270
|
+
await client.query("BEGIN");
|
|
271
|
+
const result = await this.transactionClient.run(client, callback);
|
|
272
|
+
await client.query("COMMIT");
|
|
273
|
+
return result;
|
|
274
|
+
} catch (error) {
|
|
275
|
+
await client.query("ROLLBACK");
|
|
276
|
+
throw error;
|
|
277
|
+
} finally {
|
|
278
|
+
client.release();
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async withLock(lockName, callback) {
|
|
282
|
+
if (!lockName) {
|
|
283
|
+
throw new Error("SQL lock name is required");
|
|
284
|
+
}
|
|
285
|
+
const existingClient = this.transactionClient.getStore();
|
|
286
|
+
if (existingClient) {
|
|
287
|
+
await existingClient.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
288
|
+
lockName
|
|
289
|
+
]);
|
|
290
|
+
return await callback();
|
|
291
|
+
}
|
|
292
|
+
const client = await this.pool.connect();
|
|
293
|
+
try {
|
|
294
|
+
await client.query("BEGIN");
|
|
295
|
+
return await this.transactionClient.run(client, async () => {
|
|
296
|
+
try {
|
|
297
|
+
await client.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
298
|
+
lockName
|
|
299
|
+
]);
|
|
300
|
+
const result = await callback();
|
|
301
|
+
await client.query("COMMIT");
|
|
302
|
+
return result;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
await client.query("ROLLBACK");
|
|
305
|
+
throw error;
|
|
306
|
+
}
|
|
307
|
+
});
|
|
308
|
+
} finally {
|
|
309
|
+
client.release();
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
async withMigrationLock(migrationTable, callback) {
|
|
313
|
+
const client = await this.pool.connect();
|
|
314
|
+
const lockName = `junior:migrate:${migrationTable}`;
|
|
315
|
+
try {
|
|
316
|
+
await client.query("SELECT pg_advisory_lock(hashtext($1))", [lockName]);
|
|
317
|
+
return await callback();
|
|
318
|
+
} finally {
|
|
319
|
+
client.release(true);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
async close() {
|
|
323
|
+
await this.pool.end();
|
|
324
|
+
}
|
|
325
|
+
queryClient() {
|
|
326
|
+
return this.transactionClient.getStore() ?? this.pool;
|
|
327
|
+
}
|
|
328
|
+
};
|
|
329
|
+
function createNeonJuniorSqlExecutor(args) {
|
|
330
|
+
return new NeonExecutor(
|
|
331
|
+
new Pool({
|
|
332
|
+
connectionString: args.connectionString,
|
|
333
|
+
max: 3
|
|
334
|
+
})
|
|
335
|
+
);
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
// src/db/postgres.ts
|
|
339
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
340
|
+
import pg from "pg";
|
|
341
|
+
import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
|
|
342
|
+
import { migrate as migrate2 } from "drizzle-orm/node-postgres/migrator";
|
|
343
|
+
var { Pool: Pool2 } = pg;
|
|
344
|
+
var PostgresExecutor = class {
|
|
345
|
+
constructor(pool) {
|
|
346
|
+
this.pool = pool;
|
|
347
|
+
}
|
|
348
|
+
pool;
|
|
349
|
+
transactionClient = new AsyncLocalStorage2();
|
|
350
|
+
savepointId = 0;
|
|
351
|
+
db() {
|
|
352
|
+
return drizzle2(this.queryClient(), {
|
|
353
|
+
schema: juniorSqlSchema
|
|
354
|
+
});
|
|
355
|
+
}
|
|
356
|
+
async execute(statement, params = []) {
|
|
357
|
+
await this.queryClient().query(statement, [...params]);
|
|
358
|
+
}
|
|
359
|
+
async query(statement, params = []) {
|
|
360
|
+
const result = await this.queryClient().query(statement, [
|
|
361
|
+
...params
|
|
362
|
+
]);
|
|
363
|
+
return result.rows;
|
|
364
|
+
}
|
|
365
|
+
async migrate(config) {
|
|
366
|
+
await migrate2(
|
|
367
|
+
drizzle2(this.queryClient(), { schema: juniorSqlSchema }),
|
|
368
|
+
config
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
async transaction(callback) {
|
|
372
|
+
const existingClient = this.transactionClient.getStore();
|
|
373
|
+
if (existingClient) {
|
|
374
|
+
const savepoint = `junior_savepoint_${++this.savepointId}`;
|
|
375
|
+
await existingClient.query(`SAVEPOINT ${savepoint}`);
|
|
376
|
+
try {
|
|
377
|
+
const result = await callback();
|
|
378
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
379
|
+
return result;
|
|
380
|
+
} catch (error) {
|
|
381
|
+
await existingClient.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
382
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
383
|
+
throw error;
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
const client = await this.pool.connect();
|
|
387
|
+
try {
|
|
388
|
+
await client.query("BEGIN");
|
|
389
|
+
const result = await this.transactionClient.run(client, callback);
|
|
390
|
+
await client.query("COMMIT");
|
|
391
|
+
return result;
|
|
392
|
+
} catch (error) {
|
|
393
|
+
await client.query("ROLLBACK");
|
|
394
|
+
throw error;
|
|
395
|
+
} finally {
|
|
396
|
+
client.release();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
async withLock(lockName, callback) {
|
|
400
|
+
if (!lockName) {
|
|
401
|
+
throw new Error("SQL lock name is required");
|
|
402
|
+
}
|
|
403
|
+
const existingClient = this.transactionClient.getStore();
|
|
404
|
+
if (existingClient) {
|
|
405
|
+
await existingClient.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
406
|
+
lockName
|
|
407
|
+
]);
|
|
408
|
+
return await callback();
|
|
409
|
+
}
|
|
410
|
+
const client = await this.pool.connect();
|
|
411
|
+
try {
|
|
412
|
+
await client.query("BEGIN");
|
|
413
|
+
return await this.transactionClient.run(client, async () => {
|
|
414
|
+
try {
|
|
415
|
+
await client.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
416
|
+
lockName
|
|
417
|
+
]);
|
|
418
|
+
const result = await callback();
|
|
419
|
+
await client.query("COMMIT");
|
|
420
|
+
return result;
|
|
421
|
+
} catch (error) {
|
|
422
|
+
await client.query("ROLLBACK");
|
|
423
|
+
throw error;
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
} finally {
|
|
427
|
+
client.release();
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
async withMigrationLock(migrationTable, callback) {
|
|
431
|
+
const client = await this.pool.connect();
|
|
432
|
+
const lockName = `junior:migrate:${migrationTable}`;
|
|
433
|
+
try {
|
|
434
|
+
await client.query("SELECT pg_advisory_lock(hashtext($1))", [lockName]);
|
|
435
|
+
return await callback();
|
|
436
|
+
} finally {
|
|
437
|
+
client.release(true);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
async close() {
|
|
441
|
+
await this.pool.end();
|
|
442
|
+
}
|
|
443
|
+
queryClient() {
|
|
444
|
+
return this.transactionClient.getStore() ?? this.pool;
|
|
445
|
+
}
|
|
446
|
+
};
|
|
447
|
+
function createPostgresJuniorSqlExecutor(args) {
|
|
448
|
+
return new PostgresExecutor(
|
|
449
|
+
new Pool2({
|
|
450
|
+
application_name: args.applicationName,
|
|
451
|
+
connectionString: args.connectionString,
|
|
452
|
+
max: 3
|
|
453
|
+
})
|
|
454
|
+
);
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// src/db/executor.ts
|
|
458
|
+
function createJuniorSqlExecutor(args) {
|
|
459
|
+
if (args.driver === "postgres") {
|
|
460
|
+
return createPostgresJuniorSqlExecutor(args);
|
|
461
|
+
}
|
|
462
|
+
return createNeonJuniorSqlExecutor(args);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
export {
|
|
466
|
+
juniorUsers,
|
|
467
|
+
juniorIdentities,
|
|
468
|
+
juniorConversations,
|
|
469
|
+
juniorConversationEvents,
|
|
470
|
+
createJuniorSqlExecutor
|
|
471
|
+
};
|