@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.
Files changed (62) hide show
  1. package/dist/{agent-hooks-NU5HK3PS.js → agent-hooks-FHHVLNPA.js} +12 -12
  2. package/dist/api/conversations/events.d.ts +1 -1
  3. package/dist/api/conversations/schema.d.ts +57 -6
  4. package/dist/api/schema.js +1 -1
  5. package/dist/api.js +108 -22
  6. package/dist/app.d.ts +1 -0
  7. package/dist/app.js +1481 -420
  8. package/dist/{catalog-runtime-FOFNPR3P.js → catalog-runtime-DMGJSLV2.js} +6 -4
  9. package/dist/chat/conversations/sql/store.d.ts +0 -7
  10. package/dist/chat/log-context.d.ts +40 -0
  11. package/dist/chat/logging.d.ts +3 -26
  12. package/dist/chat/runtime/slack-resume.d.ts +2 -2
  13. package/dist/chat/services/turn-session-record.d.ts +0 -2
  14. package/dist/chat/slack/reply.d.ts +7 -19
  15. package/dist/chat/state/conversation.d.ts +1 -0
  16. package/dist/chat/task-execution/slack-work.d.ts +2 -2
  17. package/dist/chunk-3SXUV423.js +10 -0
  18. package/dist/{chunk-3RGQLX2F.js → chunk-72OMGPDS.js} +1010 -26
  19. package/dist/{chunk-2XXEKR44.js → chunk-7Q6WCISF.js} +1 -1
  20. package/dist/{chunk-TE4QHJH4.js → chunk-FENLIFJD.js} +72 -591
  21. package/dist/{chunk-XKB7LGIW.js → chunk-FWJRXN4F.js} +3 -3
  22. package/dist/{chunk-PUAMO4PI.js → chunk-HHVY4SMP.js} +41 -7
  23. package/dist/{chunk-B5I5LMSP.js → chunk-HO5NT6OE.js} +5 -7
  24. package/dist/{chunk-O24R4DCK.js → chunk-ISMWX44P.js} +93 -55
  25. package/dist/{chunk-7FBGKXPE.js → chunk-IVVGFRQQ.js} +5 -0
  26. package/dist/{chunk-KPMPQ6AA.js → chunk-IXKSQGIO.js} +90 -100
  27. package/dist/{chunk-SS67LUOK.js → chunk-JNAVF45E.js} +6 -7
  28. package/dist/{chunk-DY7TRYB5.js → chunk-MGUMR35T.js} +1 -1
  29. package/dist/{chunk-A5CO2EHL.js → chunk-MXW4GL53.js} +11 -15
  30. package/dist/{chunk-RT5BUHR5.js → chunk-O3JMSZLI.js} +1 -1
  31. package/dist/chunk-OCD3OZRK.js +125 -0
  32. package/dist/{chunk-H3QYZL7K.js → chunk-OUHNWH46.js} +28 -3
  33. package/dist/{chunk-VIXFG2VC.js → chunk-PLB7MRCQ.js} +1 -2
  34. package/dist/{chunk-UD6THJ2I.js → chunk-QY636HZU.js} +114 -12
  35. package/dist/{chunk-VH6KWKG2.js → chunk-RGX4V75M.js} +3 -3
  36. package/dist/{chunk-B7PUBQQM.js → chunk-SYAQIR5Z.js} +1 -1
  37. package/dist/chunk-TMBRFULF.js +471 -0
  38. package/dist/{chunk-YIPD3L6L.js → chunk-TT6GMXNA.js} +8 -10
  39. package/dist/{chunk-YT72TOEK.js → chunk-WHMOBKT7.js} +2 -2
  40. package/dist/cli/chat.js +23 -23
  41. package/dist/cli/check.js +8 -6
  42. package/dist/cli/plugins.js +16 -16
  43. package/dist/cli/snapshot-warmup.js +10 -9
  44. package/dist/cli/upgrade.js +314 -3505
  45. package/dist/db/db.d.ts +1 -1
  46. package/dist/{db-AMRBAT5D.js → db-V3NU72O2.js} +8 -6
  47. package/dist/instrumentation.js +3 -2
  48. package/dist/nitro.js +5 -4
  49. package/dist/{runner-TQH5GAJ4.js → runner-JYBCQBLK.js} +17 -20
  50. package/dist/{skills-ITNHBARB.js → skills-U6MDAST7.js} +7 -5
  51. package/dist/{validation-AGQ46ZGV.js → validation-72N3JVRU.js} +7 -5
  52. package/dist/version.d.ts +2 -0
  53. package/dist/version.js +7 -0
  54. package/migrations/0006_drop_legacy_conversation_messages.sql +1 -0
  55. package/migrations/README.md +12 -9
  56. package/migrations/meta/0006_snapshot.json +948 -0
  57. package/migrations/meta/_journal.json +7 -0
  58. package/package.json +9 -5
  59. package/dist/chunk-AHJR2IFF.js +0 -115
  60. package/dist/chunk-G3E7SCME.js +0 -28
  61. package/dist/chunk-J3B3FPP2.js +0 -1061
  62. package/dist/chunk-TWINAEZQ.js +0 -1283
@@ -1,38 +1,36 @@
1
1
  import {
2
- createPluginLogger,
3
- createPluginState
4
- } from "./chunk-AHJR2IFF.js";
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-VH6KWKG2.js";
10
+ } from "./chunk-RGX4V75M.js";
14
11
  import {
15
12
  getDb
16
- } from "./chunk-TE4QHJH4.js";
13
+ } from "./chunk-FENLIFJD.js";
17
14
  import {
18
15
  botConfig,
19
16
  completeObject,
20
17
  embedTexts,
21
18
  standardModelId
22
- } from "./chunk-SS67LUOK.js";
19
+ } from "./chunk-JNAVF45E.js";
23
20
  import {
24
21
  isActorUserId,
25
22
  parseActorUserId
26
- } from "./chunk-VIXFG2VC.js";
23
+ } from "./chunk-PLB7MRCQ.js";
27
24
  import {
25
+ logException,
28
26
  logInfo,
29
27
  logWarn
30
- } from "./chunk-O24R4DCK.js";
28
+ } from "./chunk-ISMWX44P.js";
31
29
  import {
32
30
  parseSlackChannelReferenceId,
33
31
  parseSlackMessageTs,
34
32
  parseSlackTeamId
35
- } from "./chunk-7FBGKXPE.js";
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-SS67LUOK.js";
6
+ } from "./chunk-JNAVF45E.js";
7
7
  import {
8
8
  logWarn,
9
9
  setSpanAttributes,
10
10
  setSpanStatus,
11
11
  withSpan
12
- } from "./chunk-O24R4DCK.js";
12
+ } from "./chunk-ISMWX44P.js";
13
13
  import {
14
14
  parseSlackChannelReferenceId
15
- } from "./chunk-7FBGKXPE.js";
15
+ } from "./chunk-IVVGFRQQ.js";
16
16
 
17
17
  // src/chat/slack/client.ts
18
18
  import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  parseSlackChannelReferenceId,
3
3
  parseSlackTeamId
4
- } from "./chunk-7FBGKXPE.js";
4
+ } from "./chunk-IVVGFRQQ.js";
5
5
 
6
6
  // src/chat/destination.ts
7
7
  import {
@@ -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
+ };