@sentry/junior 0.108.0 → 0.110.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-ELT4ODFF.js} +12 -13
- package/dist/api/conversations/access.d.ts +9 -0
- package/dist/api/conversations/aggregate.d.ts +12 -1
- package/dist/api/conversations/archive.d.ts +3 -5
- package/dist/api/conversations/detail.d.ts +156 -7
- package/dist/api/conversations/events.d.ts +2 -2
- package/dist/api/conversations/list.d.ts +57 -6
- package/dist/api/conversations/projection.d.ts +6 -7
- package/dist/api/conversations/reporting.d.ts +10 -4
- package/dist/api/conversations/routes.d.ts +2 -1
- package/dist/api/conversations/shared.d.ts +1 -1
- package/dist/api/conversations/stats.d.ts +37 -6
- package/dist/api/conversations/stats.query.d.ts +1 -1
- package/dist/api/conversations/usage.d.ts +9 -0
- package/dist/api/http.d.ts +7 -0
- package/dist/api/locations/detail.d.ts +102 -6
- package/dist/api/locations/list.d.ts +43 -5
- package/dist/api/locations/query.d.ts +4 -2
- package/dist/api/locations/routes.d.ts +2 -1
- package/dist/api/people/list.d.ts +28 -6
- package/dist/api/people/list.query.d.ts +1 -1
- package/dist/api/people/profile.d.ts +96 -7
- package/dist/api/people/profile.query.d.ts +4 -2
- package/dist/api/people/routes.d.ts +2 -1
- package/dist/api/people/shared.d.ts +1219 -2
- package/dist/api/route.d.ts +18 -4
- package/dist/api/schema/common.d.ts +6 -0
- package/dist/api/{conversations/schema.d.ts → schema/conversation.d.ts} +88 -9
- package/dist/api/{locations/schema.d.ts → schema/location.d.ts} +5 -0
- package/dist/api/{people/schema.d.ts → schema/person.d.ts} +37 -45
- package/dist/api/schema.d.ts +8 -22
- package/dist/api/schema.js +10 -2
- package/dist/api.d.ts +5 -1
- package/dist/api.js +838 -369
- package/dist/app.d.ts +1 -0
- package/dist/app.js +1564 -486
- package/dist/catalog-runtime-4GI22PXK.js +16 -0
- package/dist/chat/agent/resume.d.ts +11 -12
- package/dist/chat/conversations/history.d.ts +3 -0
- package/dist/chat/conversations/sql/privacy.d.ts +3 -15
- 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/pi/messages.d.ts +2 -2
- package/dist/chat/pi/sql-model-usage.d.ts +4 -1
- package/dist/chat/runtime/slack-resume.d.ts +2 -2
- package/dist/chat/services/auth-pause.d.ts +4 -0
- package/dist/chat/services/context-compaction.d.ts +1 -0
- 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/queue-signing.d.ts +10 -8
- package/dist/chat/task-execution/queue.d.ts +9 -7
- package/dist/chat/task-execution/slack-work.d.ts +6 -6
- package/dist/{chunk-UD6THJ2I.js → chunk-2T7TIEXI.js} +197 -12
- package/dist/{chunk-CEA3A3UA.js → chunk-2ZTTXTSZ.js} +24 -1
- package/dist/{chunk-XKB7LGIW.js → chunk-3S7YYHBI.js} +3 -139
- package/dist/chunk-3TV7OEHL.js +10 -0
- package/dist/{chunk-A5CO2EHL.js → chunk-3UBQI73J.js} +11 -15
- package/dist/{chunk-7FBGKXPE.js → chunk-42WRQLJ6.js} +10 -33
- package/dist/{chunk-TE4QHJH4.js → chunk-4QU44P7Q.js} +135 -595
- package/dist/{chunk-RT5BUHR5.js → chunk-6Y5L4BOM.js} +3 -5
- package/dist/{chunk-VIXFG2VC.js → chunk-C4MZ3GP5.js} +1 -2
- package/dist/{chunk-3RGQLX2F.js → chunk-C5XAFTHY.js} +1011 -29
- package/dist/{chunk-PUAMO4PI.js → chunk-FPK7XY3F.js} +139 -99
- package/dist/{chunk-H3QYZL7K.js → chunk-GK47NBDE.js} +28 -3
- package/dist/{chunk-O24R4DCK.js → chunk-IYKPU7H6.js} +94 -56
- package/dist/chunk-JQFJO5WH.js +477 -0
- package/dist/{chunk-VH6KWKG2.js → chunk-L5XQPJ7T.js} +3 -3
- package/dist/{chunk-2XXEKR44.js → chunk-MIAKQNYX.js} +43 -31
- package/dist/{chunk-KPMPQ6AA.js → chunk-RHHRKSPI.js} +249 -223
- package/dist/{chunk-YT72TOEK.js → chunk-SBOBTS27.js} +2 -2
- package/dist/{chunk-B5I5LMSP.js → chunk-W6RJZG7F.js} +5 -7
- package/dist/chunk-W75ZPAGG.js +44 -0
- package/dist/{chunk-SS67LUOK.js → chunk-WNOVRQ67.js} +6 -7
- package/dist/{chunk-YIPD3L6L.js → chunk-Y3H2DN6F.js} +8 -10
- package/dist/{chunk-DY7TRYB5.js → chunk-Y5FK3CNG.js} +1 -1
- package/dist/chunk-ZKIOWEFL.js +125 -0
- package/dist/cli/chat.js +23 -24
- package/dist/cli/check.js +9 -7
- package/dist/cli/plugins.js +16 -17
- package/dist/cli/snapshot-warmup.js +11 -10
- package/dist/cli/upgrade.js +314 -3505
- package/dist/db/db.d.ts +1 -1
- package/dist/db/schema/conversations.d.ts +17 -0
- package/dist/db/schema.d.ts +17 -0
- package/dist/{db-AMRBAT5D.js → db-Y6W6CWWW.js} +8 -7
- package/dist/instrumentation.js +4 -3
- package/dist/nitro.js +4 -4
- package/dist/reporting-schema.d.ts +46 -0
- package/dist/{runner-TQH5GAJ4.js → runner-BBFV5GLR.js} +17 -21
- package/dist/{skills-ITNHBARB.js → skills-AR4AF32L.js} +8 -6
- package/dist/{validation-AGQ46ZGV.js → validation-FBIEPTC2.js} +8 -6
- 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/0007_thick_sugar_man.sql +23 -0
- package/migrations/README.md +12 -9
- package/migrations/meta/0006_snapshot.json +948 -0
- package/migrations/meta/0007_snapshot.json +1013 -0
- package/migrations/meta/_journal.json +14 -0
- package/package.json +9 -5
- package/dist/catalog-runtime-FOFNPR3P.js +0 -14
- package/dist/chunk-AHJR2IFF.js +0 -115
- package/dist/chunk-B7PUBQQM.js +0 -53
- package/dist/chunk-G3E7SCME.js +0 -28
- package/dist/chunk-J3B3FPP2.js +0 -1061
- package/dist/chunk-OB42YVAE.js +0 -16
- package/dist/chunk-TWINAEZQ.js +0 -1283
|
@@ -0,0 +1,477 @@
|
|
|
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
|
+
// Roots reference themselves; descendants reference the root whose actor
|
|
141
|
+
// and destination own their privacy boundary.
|
|
142
|
+
rootConversationId: text3("root_conversation_id").references(
|
|
143
|
+
() => juniorConversations.conversationId
|
|
144
|
+
),
|
|
145
|
+
transcriptPurgedAt: timestamptz("transcript_purged_at"),
|
|
146
|
+
durationMs: integer("duration_ms").notNull().default(0),
|
|
147
|
+
usage: jsonb2("usage_json").$type(),
|
|
148
|
+
executionDurationMs: integer("execution_duration_ms").notNull().default(0),
|
|
149
|
+
executionUsage: jsonb2("execution_usage_json").$type(),
|
|
150
|
+
metricRunId: text3("metric_run_id"),
|
|
151
|
+
archivedAt: timestamptz("archived_at")
|
|
152
|
+
},
|
|
153
|
+
(table) => [
|
|
154
|
+
index2("junior_conversations_last_activity_idx").on(
|
|
155
|
+
table.lastActivityAt.desc(),
|
|
156
|
+
table.conversationId
|
|
157
|
+
),
|
|
158
|
+
index2("junior_conversations_active_idx").using(
|
|
159
|
+
"btree",
|
|
160
|
+
sql2`coalesce(${table.executionUpdatedAt}, ${table.updatedAt})`,
|
|
161
|
+
table.conversationId
|
|
162
|
+
).where(sql2`${table.executionStatus} <> 'idle'`),
|
|
163
|
+
index2("junior_conversations_destination_activity_idx").on(
|
|
164
|
+
table.destinationId,
|
|
165
|
+
table.lastActivityAt.desc()
|
|
166
|
+
),
|
|
167
|
+
index2("junior_conversations_actor_activity_idx").on(
|
|
168
|
+
table.actorIdentityId,
|
|
169
|
+
table.lastActivityAt.desc()
|
|
170
|
+
),
|
|
171
|
+
index2("junior_conversations_origin_idx").on(
|
|
172
|
+
table.originType,
|
|
173
|
+
table.originId,
|
|
174
|
+
table.lastActivityAt.desc()
|
|
175
|
+
),
|
|
176
|
+
index2("junior_conversations_parent_idx").on(table.parentConversationId),
|
|
177
|
+
index2("junior_conversations_root_idx").on(table.rootConversationId)
|
|
178
|
+
]
|
|
179
|
+
);
|
|
180
|
+
|
|
181
|
+
// src/db/schema/conversation-events.ts
|
|
182
|
+
var juniorConversationEvents = pgTable4(
|
|
183
|
+
"junior_conversation_events",
|
|
184
|
+
{
|
|
185
|
+
conversationId: text4("conversation_id").notNull(),
|
|
186
|
+
seq: integer2("seq").notNull(),
|
|
187
|
+
historyVersion: integer2("history_version").notNull(),
|
|
188
|
+
schemaVersion: integer2("schema_version").default(1).notNull(),
|
|
189
|
+
idempotencyKey: text4("idempotency_key"),
|
|
190
|
+
type: text4("type").notNull(),
|
|
191
|
+
payload: jsonb3("payload").$type().notNull(),
|
|
192
|
+
createdAt: timestamptz("created_at").notNull()
|
|
193
|
+
},
|
|
194
|
+
(table) => [
|
|
195
|
+
primaryKey({
|
|
196
|
+
name: "junior_conversation_events_conversation_id_seq_pk",
|
|
197
|
+
columns: [table.conversationId, table.seq]
|
|
198
|
+
}),
|
|
199
|
+
foreignKey({
|
|
200
|
+
name: "junior_conversation_events_conversation_id_junior_conversations_conversation_id_fk",
|
|
201
|
+
columns: [table.conversationId],
|
|
202
|
+
foreignColumns: [juniorConversations.conversationId]
|
|
203
|
+
}),
|
|
204
|
+
index3("junior_conversation_events_history_version_idx").on(
|
|
205
|
+
table.conversationId,
|
|
206
|
+
table.historyVersion,
|
|
207
|
+
table.seq
|
|
208
|
+
),
|
|
209
|
+
index3("junior_conversation_events_type_idx").on(
|
|
210
|
+
table.conversationId,
|
|
211
|
+
table.type,
|
|
212
|
+
table.seq
|
|
213
|
+
),
|
|
214
|
+
index3("junior_conversation_events_message_search_idx").using("gin", sql3`to_tsvector('english', ${table.payload}->>'text')`).where(sql3`${table.type} = 'message'`),
|
|
215
|
+
uniqueIndex3("junior_conversation_events_idempotency_idx").on(
|
|
216
|
+
table.conversationId,
|
|
217
|
+
table.idempotencyKey
|
|
218
|
+
)
|
|
219
|
+
]
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// src/db/schema.ts
|
|
223
|
+
var juniorSqlSchema = {
|
|
224
|
+
juniorConversationEvents,
|
|
225
|
+
juniorConversations,
|
|
226
|
+
juniorDestinations,
|
|
227
|
+
juniorIdentities,
|
|
228
|
+
juniorUsers
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
// src/db/neon.ts
|
|
232
|
+
var NeonExecutor = class {
|
|
233
|
+
constructor(pool) {
|
|
234
|
+
this.pool = pool;
|
|
235
|
+
}
|
|
236
|
+
pool;
|
|
237
|
+
transactionClient = new AsyncLocalStorage();
|
|
238
|
+
savepointId = 0;
|
|
239
|
+
db() {
|
|
240
|
+
return drizzle(this.queryClient(), {
|
|
241
|
+
schema: juniorSqlSchema
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
async execute(statement, params = []) {
|
|
245
|
+
await this.queryClient().query(statement, [...params]);
|
|
246
|
+
}
|
|
247
|
+
async query(statement, params = []) {
|
|
248
|
+
const result = await this.queryClient().query(statement, [
|
|
249
|
+
...params
|
|
250
|
+
]);
|
|
251
|
+
return result.rows;
|
|
252
|
+
}
|
|
253
|
+
async migrate(config) {
|
|
254
|
+
await migrate(
|
|
255
|
+
drizzle(this.queryClient(), { schema: juniorSqlSchema }),
|
|
256
|
+
config
|
|
257
|
+
);
|
|
258
|
+
}
|
|
259
|
+
async transaction(callback) {
|
|
260
|
+
const existingClient = this.transactionClient.getStore();
|
|
261
|
+
if (existingClient) {
|
|
262
|
+
const savepoint = `junior_savepoint_${++this.savepointId}`;
|
|
263
|
+
await existingClient.query(`SAVEPOINT ${savepoint}`);
|
|
264
|
+
try {
|
|
265
|
+
const result = await callback();
|
|
266
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
267
|
+
return result;
|
|
268
|
+
} catch (error) {
|
|
269
|
+
await existingClient.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
270
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
271
|
+
throw error;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const client = await this.pool.connect();
|
|
275
|
+
try {
|
|
276
|
+
await client.query("BEGIN");
|
|
277
|
+
const result = await this.transactionClient.run(client, callback);
|
|
278
|
+
await client.query("COMMIT");
|
|
279
|
+
return result;
|
|
280
|
+
} catch (error) {
|
|
281
|
+
await client.query("ROLLBACK");
|
|
282
|
+
throw error;
|
|
283
|
+
} finally {
|
|
284
|
+
client.release();
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
async withLock(lockName, callback) {
|
|
288
|
+
if (!lockName) {
|
|
289
|
+
throw new Error("SQL lock name is required");
|
|
290
|
+
}
|
|
291
|
+
const existingClient = this.transactionClient.getStore();
|
|
292
|
+
if (existingClient) {
|
|
293
|
+
await existingClient.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
294
|
+
lockName
|
|
295
|
+
]);
|
|
296
|
+
return await callback();
|
|
297
|
+
}
|
|
298
|
+
const client = await this.pool.connect();
|
|
299
|
+
try {
|
|
300
|
+
await client.query("BEGIN");
|
|
301
|
+
return await this.transactionClient.run(client, async () => {
|
|
302
|
+
try {
|
|
303
|
+
await client.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
304
|
+
lockName
|
|
305
|
+
]);
|
|
306
|
+
const result = await callback();
|
|
307
|
+
await client.query("COMMIT");
|
|
308
|
+
return result;
|
|
309
|
+
} catch (error) {
|
|
310
|
+
await client.query("ROLLBACK");
|
|
311
|
+
throw error;
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
} finally {
|
|
315
|
+
client.release();
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
async withMigrationLock(migrationTable, callback) {
|
|
319
|
+
const client = await this.pool.connect();
|
|
320
|
+
const lockName = `junior:migrate:${migrationTable}`;
|
|
321
|
+
try {
|
|
322
|
+
await client.query("SELECT pg_advisory_lock(hashtext($1))", [lockName]);
|
|
323
|
+
return await callback();
|
|
324
|
+
} finally {
|
|
325
|
+
client.release(true);
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
async close() {
|
|
329
|
+
await this.pool.end();
|
|
330
|
+
}
|
|
331
|
+
queryClient() {
|
|
332
|
+
return this.transactionClient.getStore() ?? this.pool;
|
|
333
|
+
}
|
|
334
|
+
};
|
|
335
|
+
function createNeonJuniorSqlExecutor(args) {
|
|
336
|
+
return new NeonExecutor(
|
|
337
|
+
new Pool({
|
|
338
|
+
connectionString: args.connectionString,
|
|
339
|
+
max: 3
|
|
340
|
+
})
|
|
341
|
+
);
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
// src/db/postgres.ts
|
|
345
|
+
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
346
|
+
import pg from "pg";
|
|
347
|
+
import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
|
|
348
|
+
import { migrate as migrate2 } from "drizzle-orm/node-postgres/migrator";
|
|
349
|
+
var { Pool: Pool2 } = pg;
|
|
350
|
+
var PostgresExecutor = class {
|
|
351
|
+
constructor(pool) {
|
|
352
|
+
this.pool = pool;
|
|
353
|
+
}
|
|
354
|
+
pool;
|
|
355
|
+
transactionClient = new AsyncLocalStorage2();
|
|
356
|
+
savepointId = 0;
|
|
357
|
+
db() {
|
|
358
|
+
return drizzle2(this.queryClient(), {
|
|
359
|
+
schema: juniorSqlSchema
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
async execute(statement, params = []) {
|
|
363
|
+
await this.queryClient().query(statement, [...params]);
|
|
364
|
+
}
|
|
365
|
+
async query(statement, params = []) {
|
|
366
|
+
const result = await this.queryClient().query(statement, [
|
|
367
|
+
...params
|
|
368
|
+
]);
|
|
369
|
+
return result.rows;
|
|
370
|
+
}
|
|
371
|
+
async migrate(config) {
|
|
372
|
+
await migrate2(
|
|
373
|
+
drizzle2(this.queryClient(), { schema: juniorSqlSchema }),
|
|
374
|
+
config
|
|
375
|
+
);
|
|
376
|
+
}
|
|
377
|
+
async transaction(callback) {
|
|
378
|
+
const existingClient = this.transactionClient.getStore();
|
|
379
|
+
if (existingClient) {
|
|
380
|
+
const savepoint = `junior_savepoint_${++this.savepointId}`;
|
|
381
|
+
await existingClient.query(`SAVEPOINT ${savepoint}`);
|
|
382
|
+
try {
|
|
383
|
+
const result = await callback();
|
|
384
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
385
|
+
return result;
|
|
386
|
+
} catch (error) {
|
|
387
|
+
await existingClient.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
|
|
388
|
+
await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
|
|
389
|
+
throw error;
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
const client = await this.pool.connect();
|
|
393
|
+
try {
|
|
394
|
+
await client.query("BEGIN");
|
|
395
|
+
const result = await this.transactionClient.run(client, callback);
|
|
396
|
+
await client.query("COMMIT");
|
|
397
|
+
return result;
|
|
398
|
+
} catch (error) {
|
|
399
|
+
await client.query("ROLLBACK");
|
|
400
|
+
throw error;
|
|
401
|
+
} finally {
|
|
402
|
+
client.release();
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
async withLock(lockName, callback) {
|
|
406
|
+
if (!lockName) {
|
|
407
|
+
throw new Error("SQL lock name is required");
|
|
408
|
+
}
|
|
409
|
+
const existingClient = this.transactionClient.getStore();
|
|
410
|
+
if (existingClient) {
|
|
411
|
+
await existingClient.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
412
|
+
lockName
|
|
413
|
+
]);
|
|
414
|
+
return await callback();
|
|
415
|
+
}
|
|
416
|
+
const client = await this.pool.connect();
|
|
417
|
+
try {
|
|
418
|
+
await client.query("BEGIN");
|
|
419
|
+
return await this.transactionClient.run(client, async () => {
|
|
420
|
+
try {
|
|
421
|
+
await client.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
|
|
422
|
+
lockName
|
|
423
|
+
]);
|
|
424
|
+
const result = await callback();
|
|
425
|
+
await client.query("COMMIT");
|
|
426
|
+
return result;
|
|
427
|
+
} catch (error) {
|
|
428
|
+
await client.query("ROLLBACK");
|
|
429
|
+
throw error;
|
|
430
|
+
}
|
|
431
|
+
});
|
|
432
|
+
} finally {
|
|
433
|
+
client.release();
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
async withMigrationLock(migrationTable, callback) {
|
|
437
|
+
const client = await this.pool.connect();
|
|
438
|
+
const lockName = `junior:migrate:${migrationTable}`;
|
|
439
|
+
try {
|
|
440
|
+
await client.query("SELECT pg_advisory_lock(hashtext($1))", [lockName]);
|
|
441
|
+
return await callback();
|
|
442
|
+
} finally {
|
|
443
|
+
client.release(true);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
async close() {
|
|
447
|
+
await this.pool.end();
|
|
448
|
+
}
|
|
449
|
+
queryClient() {
|
|
450
|
+
return this.transactionClient.getStore() ?? this.pool;
|
|
451
|
+
}
|
|
452
|
+
};
|
|
453
|
+
function createPostgresJuniorSqlExecutor(args) {
|
|
454
|
+
return new PostgresExecutor(
|
|
455
|
+
new Pool2({
|
|
456
|
+
application_name: args.applicationName,
|
|
457
|
+
connectionString: args.connectionString,
|
|
458
|
+
max: 3
|
|
459
|
+
})
|
|
460
|
+
);
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// src/db/executor.ts
|
|
464
|
+
function createJuniorSqlExecutor(args) {
|
|
465
|
+
if (args.driver === "postgres") {
|
|
466
|
+
return createPostgresJuniorSqlExecutor(args);
|
|
467
|
+
}
|
|
468
|
+
return createNeonJuniorSqlExecutor(args);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export {
|
|
472
|
+
juniorUsers,
|
|
473
|
+
juniorIdentities,
|
|
474
|
+
juniorConversations,
|
|
475
|
+
juniorConversationEvents,
|
|
476
|
+
createJuniorSqlExecutor
|
|
477
|
+
};
|
|
@@ -3,16 +3,16 @@ import {
|
|
|
3
3
|
} from "./chunk-4ZNGQH7C.js";
|
|
4
4
|
import {
|
|
5
5
|
getSlackBotToken
|
|
6
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-WNOVRQ67.js";
|
|
7
7
|
import {
|
|
8
8
|
logWarn,
|
|
9
9
|
setSpanAttributes,
|
|
10
10
|
setSpanStatus,
|
|
11
11
|
withSpan
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-IYKPU7H6.js";
|
|
13
13
|
import {
|
|
14
14
|
parseSlackChannelReferenceId
|
|
15
|
-
} from "./chunk-
|
|
15
|
+
} from "./chunk-42WRQLJ6.js";
|
|
16
16
|
|
|
17
17
|
// src/chat/slack/client.ts
|
|
18
18
|
import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
|
|
@@ -1,16 +1,39 @@
|
|
|
1
1
|
import {
|
|
2
2
|
createVercelQueueClient
|
|
3
3
|
} from "./chunk-KNFROR7R.js";
|
|
4
|
-
import {
|
|
5
|
-
destinationKey,
|
|
6
|
-
parseDestination
|
|
7
|
-
} from "./chunk-B7PUBQQM.js";
|
|
8
4
|
|
|
9
5
|
// src/chat/task-execution/queue-signing.ts
|
|
10
6
|
import { createHmac, timingSafeEqual } from "crypto";
|
|
11
|
-
|
|
12
|
-
|
|
7
|
+
import { z as z2 } from "zod";
|
|
8
|
+
|
|
9
|
+
// src/chat/task-execution/queue.ts
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
var conversationQueueMessageSchema = z.object({
|
|
12
|
+
conversationId: z.string().trim().min(1)
|
|
13
|
+
}).strict();
|
|
14
|
+
var ConversationQueueMessageRejectedError = class extends Error {
|
|
15
|
+
conversationId;
|
|
16
|
+
reason;
|
|
17
|
+
constructor(reason, message, options = {}) {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "ConversationQueueMessageRejectedError";
|
|
20
|
+
this.reason = reason;
|
|
21
|
+
this.conversationId = options.conversationId;
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
|
+
function isConversationQueueMessageRejectedError(error) {
|
|
25
|
+
return error instanceof ConversationQueueMessageRejectedError;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/chat/task-execution/queue-signing.ts
|
|
29
|
+
var CONVERSATION_WORK_QUEUE_SIGNATURE_CONTEXT = "junior.conversation_work_queue.v2";
|
|
30
|
+
var CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION = "v2";
|
|
13
31
|
var CONVERSATION_WORK_QUEUE_SIGNATURE_MAX_SKEW_MS = 60 * 60 * 1e3;
|
|
32
|
+
var signedConversationQueueMessageSchema = conversationQueueMessageSchema.extend({
|
|
33
|
+
signature: z2.string().trim().min(1),
|
|
34
|
+
signatureVersion: z2.literal(CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION),
|
|
35
|
+
signedAtMs: z2.number().finite()
|
|
36
|
+
}).strict();
|
|
14
37
|
function getConversationWorkQueueSecret() {
|
|
15
38
|
return process.env.JUNIOR_SECRET?.trim() || void 0;
|
|
16
39
|
}
|
|
@@ -18,12 +41,11 @@ function buildSignedPayload(message, signedAtMs) {
|
|
|
18
41
|
return [
|
|
19
42
|
CONVERSATION_WORK_QUEUE_SIGNATURE_CONTEXT,
|
|
20
43
|
signedAtMs,
|
|
21
|
-
message.conversationId
|
|
22
|
-
destinationKey(message.destination)
|
|
44
|
+
message.conversationId
|
|
23
45
|
].join(":");
|
|
24
46
|
}
|
|
25
|
-
function signPayload(
|
|
26
|
-
return createHmac("sha256", secret).update(
|
|
47
|
+
function signPayload(payload, secret) {
|
|
48
|
+
return createHmac("sha256", secret).update(payload).digest("hex");
|
|
27
49
|
}
|
|
28
50
|
function timingSafeMatch(expected, actual) {
|
|
29
51
|
const expectedBuffer = Buffer.from(expected);
|
|
@@ -34,21 +56,8 @@ function timingSafeMatch(expected, actual) {
|
|
|
34
56
|
return timingSafeEqual(expectedBuffer, actualBuffer);
|
|
35
57
|
}
|
|
36
58
|
function parseSignedConversationQueueMessage(value) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
40
|
-
const record = value;
|
|
41
|
-
const destination = parseDestination(record.destination);
|
|
42
|
-
if (typeof record.conversationId !== "string" || !record.conversationId.trim() || !destination || record.signatureVersion !== CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION || typeof record.signedAtMs !== "number" || !Number.isFinite(record.signedAtMs) || typeof record.signature !== "string" || !record.signature.trim()) {
|
|
43
|
-
return void 0;
|
|
44
|
-
}
|
|
45
|
-
return {
|
|
46
|
-
conversationId: record.conversationId,
|
|
47
|
-
destination,
|
|
48
|
-
signature: record.signature,
|
|
49
|
-
signatureVersion: CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION,
|
|
50
|
-
signedAtMs: record.signedAtMs
|
|
51
|
-
};
|
|
59
|
+
const parsed = signedConversationQueueMessageSchema.safeParse(value);
|
|
60
|
+
return parsed.success ? parsed.data : void 0;
|
|
52
61
|
}
|
|
53
62
|
function signConversationQueueMessage(message, nowMs = Date.now()) {
|
|
54
63
|
const secret = getConversationWorkQueueSecret();
|
|
@@ -61,7 +70,7 @@ function signConversationQueueMessage(message, nowMs = Date.now()) {
|
|
|
61
70
|
...message,
|
|
62
71
|
signedAtMs: nowMs,
|
|
63
72
|
signatureVersion: CONVERSATION_WORK_QUEUE_SIGNATURE_VERSION,
|
|
64
|
-
signature: signPayload(message, nowMs, secret)
|
|
73
|
+
signature: signPayload(buildSignedPayload(message, nowMs), secret)
|
|
65
74
|
};
|
|
66
75
|
}
|
|
67
76
|
function verifyConversationQueueMessage(value, nowMs = Date.now()) {
|
|
@@ -79,16 +88,16 @@ function verifyConversationQueueMessage(value, nowMs = Date.now()) {
|
|
|
79
88
|
if (Math.abs(nowMs - message.signedAtMs) > CONVERSATION_WORK_QUEUE_SIGNATURE_MAX_SKEW_MS) {
|
|
80
89
|
return { status: "rejected", reason: "expired" };
|
|
81
90
|
}
|
|
82
|
-
const expected = signPayload(
|
|
91
|
+
const expected = signPayload(
|
|
92
|
+
buildSignedPayload(message, message.signedAtMs),
|
|
93
|
+
secret
|
|
94
|
+
);
|
|
83
95
|
if (!timingSafeMatch(expected, message.signature)) {
|
|
84
96
|
return { status: "rejected", reason: "signature_mismatch" };
|
|
85
97
|
}
|
|
86
98
|
return {
|
|
87
99
|
status: "verified",
|
|
88
|
-
message: {
|
|
89
|
-
conversationId: message.conversationId,
|
|
90
|
-
destination: message.destination
|
|
91
|
-
}
|
|
100
|
+
message: { conversationId: message.conversationId }
|
|
92
101
|
};
|
|
93
102
|
}
|
|
94
103
|
|
|
@@ -130,6 +139,9 @@ function getVercelConversationWorkQueue() {
|
|
|
130
139
|
}
|
|
131
140
|
|
|
132
141
|
export {
|
|
142
|
+
conversationQueueMessageSchema,
|
|
143
|
+
ConversationQueueMessageRejectedError,
|
|
144
|
+
isConversationQueueMessageRejectedError,
|
|
133
145
|
verifyConversationQueueMessage,
|
|
134
146
|
resolveConversationWorkQueueTopic,
|
|
135
147
|
getVercelConversationWorkQueue
|