@sentry/junior 0.74.1 → 0.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. package/dist/agent-hooks-2HEB4C3Q.js +33 -0
  2. package/dist/api-reference.d.ts +1 -1
  3. package/dist/app.js +5211 -5316
  4. package/dist/build/copy-build-content.d.ts +1 -1
  5. package/dist/chat/agent-dispatch/context.d.ts +2 -3
  6. package/dist/chat/agent-dispatch/types.d.ts +2 -1
  7. package/dist/chat/config.d.ts +2 -0
  8. package/dist/chat/conversations/configured.d.ts +2 -0
  9. package/dist/chat/credentials/subject.d.ts +3 -3
  10. package/dist/chat/plugins/agent-hooks.d.ts +13 -13
  11. package/dist/chat/plugins/credential-hooks.d.ts +6 -6
  12. package/dist/chat/plugins/db.d.ts +31 -0
  13. package/dist/chat/plugins/logging.d.ts +2 -2
  14. package/dist/chat/plugins/package-discovery.d.ts +2 -1
  15. package/dist/chat/plugins/registry.d.ts +4 -0
  16. package/dist/chat/plugins/state.d.ts +3 -5
  17. package/dist/chat/plugins/types.d.ts +1 -0
  18. package/dist/chat/plugins/validation.d.ts +5 -0
  19. package/dist/chat/prompt.d.ts +11 -1
  20. package/dist/chat/respond.d.ts +10 -1
  21. package/dist/chat/runtime/slack-runtime.d.ts +6 -1
  22. package/dist/chat/sandbox/egress-credentials.d.ts +8 -8
  23. package/dist/chat/sandbox/sandbox.d.ts +2 -2
  24. package/dist/chat/sql/db.d.ts +3 -0
  25. package/dist/chat/sql/executor.d.ts +7 -0
  26. package/dist/chat/sql/neon.d.ts +2 -4
  27. package/dist/chat/sql/postgres.d.ts +6 -0
  28. package/dist/chat/task-execution/state.d.ts +7 -2
  29. package/dist/chat/task-execution/worker.d.ts +1 -1
  30. package/dist/chat/tools/agent-tools.d.ts +2 -2
  31. package/dist/chat/tools/types.d.ts +3 -0
  32. package/dist/{chunk-7Q5YOUUT.js → chunk-2RWFUS5F.js} +47 -10
  33. package/dist/{chunk-YRDS7VKO.js → chunk-62FUNJYS.js} +3 -54
  34. package/dist/{chunk-M4FLLXXD.js → chunk-74HO27II.js} +1 -1
  35. package/dist/chunk-BNJIEFQC.js +115 -0
  36. package/dist/{chunk-YOHFWWBV.js → chunk-C3AM4Z4J.js} +1 -103
  37. package/dist/chunk-D7NFH5GD.js +570 -0
  38. package/dist/chunk-EE6PJWY4.js +130 -0
  39. package/dist/{chunk-CYUI7JU5.js → chunk-EIYL7I4S.js} +1 -1
  40. package/dist/{chunk-GM7HTXYC.js → chunk-FCZO7LAR.js} +13 -2
  41. package/dist/{chunk-2LUZA3LY.js → chunk-JEELK46E.js} +5 -5
  42. package/dist/chunk-MCMROINU.js +12 -0
  43. package/dist/chunk-NPVUAXUE.js +694 -0
  44. package/dist/{chunk-OR6NQJ5E.js → chunk-OJODNL2P.js} +3 -3
  45. package/dist/{chunk-3BYAPS6B.js → chunk-OK4KKR7B.js} +1 -11
  46. package/dist/chunk-OZSPLAQ4.js +71 -0
  47. package/dist/{chunk-KVZL5NZS.js → chunk-Q3XNY442.js} +17 -7
  48. package/dist/{chunk-SQGMG7OD.js → chunk-TQ74BATR.js} +100 -58
  49. package/dist/{chunk-JL2SLRAT.js → chunk-UJ7OTHPO.js} +76 -312
  50. package/dist/{chunk-HYHKTFG2.js → chunk-VNTLUFTY.js} +80 -843
  51. package/dist/chunk-WBZ4M5N5.js +59 -0
  52. package/dist/{chunk-6UP2Z2RZ.js → chunk-XJHDZUGD.js} +7 -7
  53. package/dist/chunk-Y2CM7HXH.js +111 -0
  54. package/dist/{chunk-F6HWCPOC.js → chunk-ZNNTSPNF.js} +1 -1
  55. package/dist/cli/chat.js +52 -2
  56. package/dist/cli/check.js +6 -5
  57. package/dist/cli/snapshot-warmup.js +10 -9
  58. package/dist/cli/upgrade.js +256 -16
  59. package/dist/db-A3ILH67H.js +20 -0
  60. package/dist/handlers/sandbox-egress-route.d.ts +4 -0
  61. package/dist/handlers/slack-webhook.d.ts +4 -0
  62. package/dist/handlers/webhooks.d.ts +6 -13
  63. package/dist/nitro.js +34 -89
  64. package/dist/plugin-module.d.ts +21 -0
  65. package/dist/plugins-OMJKLRJ2.js +13 -0
  66. package/dist/plugins.d.ts +6 -4
  67. package/dist/registry-NLZFIW23.js +46 -0
  68. package/dist/reporting/conversations.d.ts +3 -3
  69. package/dist/reporting.d.ts +6 -5
  70. package/dist/reporting.js +23 -17
  71. package/dist/{runner-27NP2TEO.js → runner-LUQZ5G67.js} +18 -13
  72. package/dist/validation-VMCPP3YO.js +15 -0
  73. package/package.json +11 -9
@@ -0,0 +1,570 @@
1
+ import {
2
+ getChatConfig
3
+ } from "./chunk-FCZO7LAR.js";
4
+
5
+ // src/chat/plugins/db.ts
6
+ import { createHash } from "crypto";
7
+ import { readdirSync, readFileSync, statSync } from "fs";
8
+ import path from "path";
9
+ import { z } from "zod";
10
+
11
+ // src/chat/sql/neon.ts
12
+ import { AsyncLocalStorage } from "async_hooks";
13
+ import {
14
+ Pool
15
+ } from "@neondatabase/serverless";
16
+ import { drizzle } from "drizzle-orm/neon-serverless";
17
+
18
+ // src/chat/conversations/sql/schema/conversations.ts
19
+ import { sql } from "drizzle-orm";
20
+ import { index as index3, integer, jsonb as jsonb3, pgTable as pgTable3, text as text3 } from "drizzle-orm/pg-core";
21
+
22
+ // src/chat/conversations/sql/schema/destinations.ts
23
+ import { index, jsonb, pgTable, text, uniqueIndex } from "drizzle-orm/pg-core";
24
+
25
+ // src/chat/conversations/sql/schema/timestamps.ts
26
+ import { timestamp } from "drizzle-orm/pg-core";
27
+ var timestamptz = (name) => timestamp(name, { withTimezone: true });
28
+
29
+ // src/chat/conversations/sql/schema/destinations.ts
30
+ var juniorDestinations = pgTable(
31
+ "junior_destinations",
32
+ {
33
+ id: text("id").primaryKey(),
34
+ provider: text("provider").notNull(),
35
+ providerTenantId: text("provider_tenant_id").notNull().default(""),
36
+ providerDestinationId: text("provider_destination_id").notNull(),
37
+ kind: text("kind").$type().notNull(),
38
+ parentDestinationId: text("parent_destination_id"),
39
+ displayName: text("display_name"),
40
+ visibility: text("visibility").$type().notNull().default("unknown"),
41
+ metadata: jsonb("metadata_json"),
42
+ createdAt: timestamptz("created_at").notNull(),
43
+ updatedAt: timestamptz("updated_at").notNull()
44
+ },
45
+ (table) => [
46
+ uniqueIndex("junior_destinations_provider_destination_uidx").on(
47
+ table.provider,
48
+ table.providerTenantId,
49
+ table.providerDestinationId
50
+ ),
51
+ index("junior_destinations_provider_kind_idx").on(
52
+ table.provider,
53
+ table.kind
54
+ )
55
+ ]
56
+ );
57
+
58
+ // src/chat/conversations/sql/schema/identities.ts
59
+ import { index as index2, jsonb as jsonb2, pgTable as pgTable2, text as text2, uniqueIndex as uniqueIndex2 } from "drizzle-orm/pg-core";
60
+ var juniorIdentities = pgTable2(
61
+ "junior_identities",
62
+ {
63
+ id: text2("id").primaryKey(),
64
+ kind: text2("kind").$type().notNull(),
65
+ provider: text2("provider").notNull(),
66
+ providerTenantId: text2("provider_tenant_id").notNull().default(""),
67
+ providerSubjectId: text2("provider_subject_id").notNull(),
68
+ displayName: text2("display_name"),
69
+ handle: text2("handle"),
70
+ email: text2("email"),
71
+ avatarUrl: text2("avatar_url"),
72
+ metadata: jsonb2("metadata_json"),
73
+ createdAt: timestamptz("created_at").notNull(),
74
+ updatedAt: timestamptz("updated_at").notNull()
75
+ },
76
+ (table) => [
77
+ uniqueIndex2("junior_identities_provider_subject_uidx").on(
78
+ table.provider,
79
+ table.providerTenantId,
80
+ table.providerSubjectId
81
+ ),
82
+ index2("junior_identities_kind_provider_idx").on(table.kind, table.provider)
83
+ ]
84
+ );
85
+
86
+ // src/chat/conversations/sql/schema/conversations.ts
87
+ var juniorConversations = pgTable3(
88
+ "junior_conversations",
89
+ {
90
+ conversationId: text3("conversation_id").primaryKey(),
91
+ schemaVersion: integer("schema_version").notNull().default(1),
92
+ source: text3("source").$type(),
93
+ originType: text3("origin_type"),
94
+ originId: text3("origin_id"),
95
+ originRunId: text3("origin_run_id"),
96
+ destinationId: text3("destination_id").references(
97
+ () => juniorDestinations.id
98
+ ),
99
+ destination: jsonb3("destination_json").$type(),
100
+ actorIdentityId: text3("actor_identity_id").references(
101
+ () => juniorIdentities.id
102
+ ),
103
+ requesterIdentityId: text3("requester_identity_id").references(
104
+ () => juniorIdentities.id
105
+ ),
106
+ creatorIdentityId: text3("creator_identity_id").references(
107
+ () => juniorIdentities.id
108
+ ),
109
+ credentialSubjectIdentityId: text3(
110
+ "credential_subject_identity_id"
111
+ ).references(() => juniorIdentities.id),
112
+ requester: jsonb3("requester_json").$type(),
113
+ channelName: text3("channel_name"),
114
+ title: text3("title"),
115
+ createdAt: timestamptz("created_at").notNull(),
116
+ lastActivityAt: timestamptz("last_activity_at").notNull(),
117
+ updatedAt: timestamptz("updated_at").notNull(),
118
+ executionUpdatedAt: timestamptz("execution_updated_at"),
119
+ executionStatus: text3("execution_status").$type().notNull(),
120
+ runId: text3("run_id"),
121
+ lastCheckpointAt: timestamptz("last_checkpoint_at"),
122
+ lastEnqueuedAt: timestamptz("last_enqueued_at")
123
+ },
124
+ (table) => [
125
+ index3("junior_conversations_last_activity_idx").on(
126
+ table.lastActivityAt.desc(),
127
+ table.conversationId
128
+ ),
129
+ index3("junior_conversations_active_idx").using(
130
+ "btree",
131
+ sql`coalesce(${table.executionUpdatedAt}, ${table.updatedAt})`,
132
+ table.conversationId
133
+ ).where(sql`${table.executionStatus} <> 'idle'`),
134
+ index3("junior_conversations_destination_activity_idx").on(
135
+ table.destinationId,
136
+ table.lastActivityAt.desc()
137
+ ),
138
+ index3("junior_conversations_actor_activity_idx").on(
139
+ table.actorIdentityId,
140
+ table.lastActivityAt.desc()
141
+ ),
142
+ index3("junior_conversations_requester_activity_idx").on(
143
+ table.requesterIdentityId,
144
+ table.lastActivityAt.desc()
145
+ ),
146
+ index3("junior_conversations_origin_idx").on(
147
+ table.originType,
148
+ table.originId,
149
+ table.lastActivityAt.desc()
150
+ )
151
+ ]
152
+ );
153
+
154
+ // src/chat/conversations/sql/schema/migrations.ts
155
+ import { pgTable as pgTable4, text as text4 } from "drizzle-orm/pg-core";
156
+ var juniorSchemaMigrations = pgTable4("junior_schema_migrations", {
157
+ id: text4("id").primaryKey(),
158
+ checksum: text4("checksum").notNull(),
159
+ appliedAt: timestamptz("applied_at").notNull().defaultNow()
160
+ });
161
+
162
+ // src/chat/conversations/sql/schema.ts
163
+ var schema = {
164
+ juniorConversations,
165
+ juniorDestinations,
166
+ juniorIdentities,
167
+ juniorSchemaMigrations
168
+ };
169
+
170
+ // src/chat/sql/schema.ts
171
+ var juniorSqlSchema = {
172
+ ...schema
173
+ };
174
+
175
+ // src/chat/sql/neon.ts
176
+ var NeonExecutor = class {
177
+ constructor(pool) {
178
+ this.pool = pool;
179
+ }
180
+ pool;
181
+ transactionClient = new AsyncLocalStorage();
182
+ savepointId = 0;
183
+ db() {
184
+ return drizzle(this.queryClient(), {
185
+ schema: juniorSqlSchema
186
+ });
187
+ }
188
+ async execute(statement, params = []) {
189
+ await this.queryClient().query(statement, [...params]);
190
+ }
191
+ async query(statement, params = []) {
192
+ const result = await this.queryClient().query(statement, [
193
+ ...params
194
+ ]);
195
+ return result.rows;
196
+ }
197
+ async transaction(callback) {
198
+ const existingClient = this.transactionClient.getStore();
199
+ if (existingClient) {
200
+ const savepoint = `junior_savepoint_${++this.savepointId}`;
201
+ await existingClient.query(`SAVEPOINT ${savepoint}`);
202
+ try {
203
+ const result = await callback();
204
+ await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
205
+ return result;
206
+ } catch (error) {
207
+ await existingClient.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
208
+ await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
209
+ throw error;
210
+ }
211
+ }
212
+ const client = await this.pool.connect();
213
+ try {
214
+ await client.query("BEGIN");
215
+ const result = await this.transactionClient.run(client, callback);
216
+ await client.query("COMMIT");
217
+ return result;
218
+ } catch (error) {
219
+ await client.query("ROLLBACK");
220
+ throw error;
221
+ } finally {
222
+ client.release();
223
+ }
224
+ }
225
+ async withLock(lockName, callback) {
226
+ if (!lockName) {
227
+ throw new Error("SQL lock name is required");
228
+ }
229
+ const existingClient = this.transactionClient.getStore();
230
+ if (existingClient) {
231
+ await existingClient.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
232
+ lockName
233
+ ]);
234
+ return await callback();
235
+ }
236
+ const client = await this.pool.connect();
237
+ try {
238
+ await client.query("BEGIN");
239
+ return await this.transactionClient.run(client, async () => {
240
+ try {
241
+ await client.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
242
+ lockName
243
+ ]);
244
+ const result = await callback();
245
+ await client.query("COMMIT");
246
+ return result;
247
+ } catch (error) {
248
+ await client.query("ROLLBACK");
249
+ throw error;
250
+ }
251
+ });
252
+ } finally {
253
+ client.release();
254
+ }
255
+ }
256
+ async close() {
257
+ await this.pool.end();
258
+ }
259
+ queryClient() {
260
+ return this.transactionClient.getStore() ?? this.pool;
261
+ }
262
+ };
263
+ function createNeonJuniorSqlExecutor(args) {
264
+ return new NeonExecutor(
265
+ new Pool({
266
+ connectionString: args.connectionString,
267
+ max: 3
268
+ })
269
+ );
270
+ }
271
+
272
+ // src/chat/sql/postgres.ts
273
+ import { AsyncLocalStorage as AsyncLocalStorage2 } from "async_hooks";
274
+ import pg from "pg";
275
+ import { drizzle as drizzle2 } from "drizzle-orm/node-postgres";
276
+ var { Pool: Pool2 } = pg;
277
+ var PostgresExecutor = class {
278
+ constructor(pool) {
279
+ this.pool = pool;
280
+ }
281
+ pool;
282
+ transactionClient = new AsyncLocalStorage2();
283
+ savepointId = 0;
284
+ db() {
285
+ return drizzle2(this.queryClient(), {
286
+ schema: juniorSqlSchema
287
+ });
288
+ }
289
+ async execute(statement, params = []) {
290
+ await this.queryClient().query(statement, [...params]);
291
+ }
292
+ async query(statement, params = []) {
293
+ const result = await this.queryClient().query(statement, [
294
+ ...params
295
+ ]);
296
+ return result.rows;
297
+ }
298
+ async transaction(callback) {
299
+ const existingClient = this.transactionClient.getStore();
300
+ if (existingClient) {
301
+ const savepoint = `junior_savepoint_${++this.savepointId}`;
302
+ await existingClient.query(`SAVEPOINT ${savepoint}`);
303
+ try {
304
+ const result = await callback();
305
+ await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
306
+ return result;
307
+ } catch (error) {
308
+ await existingClient.query(`ROLLBACK TO SAVEPOINT ${savepoint}`);
309
+ await existingClient.query(`RELEASE SAVEPOINT ${savepoint}`);
310
+ throw error;
311
+ }
312
+ }
313
+ const client = await this.pool.connect();
314
+ try {
315
+ await client.query("BEGIN");
316
+ const result = await this.transactionClient.run(client, callback);
317
+ await client.query("COMMIT");
318
+ return result;
319
+ } catch (error) {
320
+ await client.query("ROLLBACK");
321
+ throw error;
322
+ } finally {
323
+ client.release();
324
+ }
325
+ }
326
+ async withLock(lockName, callback) {
327
+ if (!lockName) {
328
+ throw new Error("SQL lock name is required");
329
+ }
330
+ const existingClient = this.transactionClient.getStore();
331
+ if (existingClient) {
332
+ await existingClient.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
333
+ lockName
334
+ ]);
335
+ return await callback();
336
+ }
337
+ const client = await this.pool.connect();
338
+ try {
339
+ await client.query("BEGIN");
340
+ return await this.transactionClient.run(client, async () => {
341
+ try {
342
+ await client.query("SELECT pg_advisory_xact_lock(hashtext($1))", [
343
+ lockName
344
+ ]);
345
+ const result = await callback();
346
+ await client.query("COMMIT");
347
+ return result;
348
+ } catch (error) {
349
+ await client.query("ROLLBACK");
350
+ throw error;
351
+ }
352
+ });
353
+ } finally {
354
+ client.release();
355
+ }
356
+ }
357
+ async close() {
358
+ await this.pool.end();
359
+ }
360
+ queryClient() {
361
+ return this.transactionClient.getStore() ?? this.pool;
362
+ }
363
+ };
364
+ function createPostgresJuniorSqlExecutor(args) {
365
+ return new PostgresExecutor(
366
+ new Pool2({
367
+ application_name: args.applicationName,
368
+ connectionString: args.connectionString,
369
+ max: 3
370
+ })
371
+ );
372
+ }
373
+
374
+ // src/chat/sql/executor.ts
375
+ function createJuniorSqlExecutor(args) {
376
+ if (args.driver === "postgres") {
377
+ return createPostgresJuniorSqlExecutor(args);
378
+ }
379
+ return createNeonJuniorSqlExecutor(args);
380
+ }
381
+
382
+ // src/chat/plugins/db.ts
383
+ var PLUGIN_SCHEMA_LOCK_NAME = "junior_plugin_schema";
384
+ var MIGRATION_FILENAME_RE = /^[0-9]{4}_[a-z0-9_]+\.sql$/;
385
+ var migrationRecordSchema = z.object({
386
+ id: z.string().min(1),
387
+ checksum: z.string().min(1)
388
+ }).strict();
389
+ var configuredPluginDb;
390
+ function checksumSql(sql2) {
391
+ return createHash("sha256").update(sql2).digest("hex");
392
+ }
393
+ function parseStoredMigrationRecord(value) {
394
+ return migrationRecordSchema.parse(value);
395
+ }
396
+ function assertMigrationFilename(filename) {
397
+ if (!filename || filename !== path.basename(filename) || !MIGRATION_FILENAME_RE.test(filename)) {
398
+ throw new Error(`Plugin migration filename "${filename}" is invalid`);
399
+ }
400
+ }
401
+ function assertUniqueMigrationIds(migrations) {
402
+ const seen = /* @__PURE__ */ new Set();
403
+ for (const migration of migrations) {
404
+ if (seen.has(migration.id)) {
405
+ throw new Error(`Duplicate plugin migration id ${migration.id}`);
406
+ }
407
+ seen.add(migration.id);
408
+ }
409
+ }
410
+ function migrationId(pluginName, filename) {
411
+ return `plugin:${pluginName}/${filename}`;
412
+ }
413
+ function createMigrationTableSql() {
414
+ return `
415
+ CREATE TABLE IF NOT EXISTS junior_schema_migrations (
416
+ id TEXT PRIMARY KEY,
417
+ checksum TEXT NOT NULL,
418
+ applied_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP
419
+ )
420
+ `;
421
+ }
422
+ function createPluginDb(executor) {
423
+ const db = executor.db();
424
+ const pluginDb = {
425
+ delete: db.delete.bind(db),
426
+ execute: (statement, params) => executor.execute(statement, params),
427
+ insert: db.insert.bind(db),
428
+ query: (statement, params) => executor.query(statement, params),
429
+ select: db.select.bind(db),
430
+ transaction: async (callback) => await executor.transaction(
431
+ async () => await callback(createPluginDb(executor))
432
+ ),
433
+ update: db.update.bind(db)
434
+ };
435
+ return pluginDb;
436
+ }
437
+ function getConfiguredPluginDb() {
438
+ const databaseUrl = getChatConfig().sql.databaseUrl;
439
+ const driver = getChatConfig().sql.driver;
440
+ if (!databaseUrl) {
441
+ return void 0;
442
+ }
443
+ if (configuredPluginDb?.databaseUrl !== databaseUrl || configuredPluginDb.driver !== driver) {
444
+ void configuredPluginDb?.executor.close().catch(() => void 0);
445
+ const executor = createJuniorSqlExecutor({
446
+ connectionString: databaseUrl,
447
+ driver
448
+ });
449
+ configuredPluginDb = {
450
+ databaseUrl,
451
+ driver,
452
+ executor,
453
+ db: createPluginDb(executor)
454
+ };
455
+ }
456
+ return configuredPluginDb.db;
457
+ }
458
+ async function closeConfiguredPluginDb() {
459
+ const current = configuredPluginDb;
460
+ configuredPluginDb = void 0;
461
+ await current?.executor.close();
462
+ }
463
+ async function listAppliedMigrations(executor) {
464
+ const rows = await executor.query(
465
+ "SELECT id, checksum FROM junior_schema_migrations ORDER BY id ASC"
466
+ );
467
+ const records = /* @__PURE__ */ new Map();
468
+ for (const row of rows) {
469
+ const record = parseStoredMigrationRecord(row);
470
+ records.set(record.id, record);
471
+ }
472
+ return records;
473
+ }
474
+ async function applyPluginMigration(executor, migration) {
475
+ await executor.transaction(async () => {
476
+ await executor.execute(migration.sql);
477
+ await executor.execute(
478
+ "INSERT INTO junior_schema_migrations (id, checksum) VALUES ($1, $2)",
479
+ [migration.id, migration.checksum]
480
+ );
481
+ });
482
+ }
483
+ function createPluginDbForExecutor(executor) {
484
+ return createPluginDb(executor);
485
+ }
486
+ function getPluginDbForRegistration(registration) {
487
+ if (!registration.database) {
488
+ return void 0;
489
+ }
490
+ return getConfiguredPluginDb();
491
+ }
492
+ function validatePluginDatabaseRequirements(registrations) {
493
+ if (getChatConfig().sql.databaseUrl) {
494
+ return;
495
+ }
496
+ const databasePlugins = registrations.filter((registration) => registration.database).map((registration) => registration.manifest.name);
497
+ if (databasePlugins.length > 0) {
498
+ throw new Error(
499
+ `Plugin database access requires JUNIOR_DATABASE_URL or DATABASE_URL for: ${databasePlugins.join(", ")}`
500
+ );
501
+ }
502
+ }
503
+ function readPluginMigrations(root) {
504
+ const migrationsDir = root.dir;
505
+ let stat;
506
+ try {
507
+ stat = statSync(migrationsDir);
508
+ } catch {
509
+ return [];
510
+ }
511
+ if (!stat.isDirectory()) {
512
+ throw new Error(
513
+ `Plugin "${root.pluginName}" migrations path is not a directory`
514
+ );
515
+ }
516
+ return readdirSync(migrationsDir).filter((filename) => filename.endsWith(".sql")).sort((left, right) => left.localeCompare(right)).map((filename) => {
517
+ assertMigrationFilename(filename);
518
+ const sql2 = readFileSync(path.join(migrationsDir, filename), "utf8");
519
+ if (!sql2.trim()) {
520
+ throw new Error(
521
+ `Plugin "${root.pluginName}" migration "${filename}" is empty`
522
+ );
523
+ }
524
+ return {
525
+ checksum: checksumSql(sql2),
526
+ filename,
527
+ id: migrationId(root.pluginName, filename),
528
+ pluginName: root.pluginName,
529
+ sql: sql2
530
+ };
531
+ });
532
+ }
533
+ async function migratePluginSchemas(executor, migrations) {
534
+ assertUniqueMigrationIds(migrations);
535
+ const result = {
536
+ existing: 0,
537
+ migrated: 0,
538
+ scanned: migrations.length
539
+ };
540
+ await executor.withLock(PLUGIN_SCHEMA_LOCK_NAME, async () => {
541
+ await executor.execute(createMigrationTableSql());
542
+ const applied = await listAppliedMigrations(executor);
543
+ for (const migration of migrations) {
544
+ const existing = applied.get(migration.id);
545
+ if (existing) {
546
+ if (existing.checksum !== migration.checksum) {
547
+ throw new Error(`Plugin migration ${migration.id} checksum changed`);
548
+ }
549
+ result.existing++;
550
+ continue;
551
+ }
552
+ await applyPluginMigration(executor, migration);
553
+ result.migrated++;
554
+ }
555
+ });
556
+ return result;
557
+ }
558
+
559
+ export {
560
+ juniorDestinations,
561
+ juniorIdentities,
562
+ juniorConversations,
563
+ createJuniorSqlExecutor,
564
+ closeConfiguredPluginDb,
565
+ createPluginDbForExecutor,
566
+ getPluginDbForRegistration,
567
+ validatePluginDatabaseRequirements,
568
+ readPluginMigrations,
569
+ migratePluginSchemas
570
+ };
@@ -0,0 +1,130 @@
1
+ // src/plugins.ts
2
+ function cloneManifests(manifests) {
3
+ return manifests ? structuredClone(manifests) : void 0;
4
+ }
5
+ function cloneInlineManifests(registrations) {
6
+ const inlineManifests = registrations.flatMap(
7
+ (plugin) => plugin.manifest ? [
8
+ {
9
+ manifest: {
10
+ ...structuredClone(plugin.manifest),
11
+ capabilities: plugin.manifest.capabilities?.map(
12
+ (capability) => capability.includes(".") ? capability : `${plugin.manifest.name}.${capability}`
13
+ ) ?? [],
14
+ configKeys: plugin.manifest.configKeys?.map(
15
+ (key) => key.includes(".") ? key : `${plugin.manifest.name}.${key}`
16
+ ) ?? [],
17
+ ...plugin.manifest.target ? {
18
+ target: {
19
+ ...plugin.manifest.target,
20
+ configKey: plugin.manifest.target.configKey.includes(".") ? plugin.manifest.target.configKey : `${plugin.manifest.name}.${plugin.manifest.target.configKey}`
21
+ }
22
+ } : {}
23
+ },
24
+ ...plugin.packageName ? { packageName: plugin.packageName } : {}
25
+ }
26
+ ] : []
27
+ );
28
+ return inlineManifests.length > 0 ? inlineManifests : void 0;
29
+ }
30
+ function assertUniquePluginNames(registrations) {
31
+ const seen = /* @__PURE__ */ new Set();
32
+ for (const plugin of registrations) {
33
+ const name = plugin.manifest.name;
34
+ if (seen.has(name)) {
35
+ throw new Error(`Duplicate plugin registration name "${name}"`);
36
+ }
37
+ seen.add(name);
38
+ }
39
+ }
40
+ function assertUniquePackageNames(packageNames) {
41
+ const seen = /* @__PURE__ */ new Set();
42
+ for (const packageName of packageNames) {
43
+ if (seen.has(packageName)) {
44
+ throw new Error(`Duplicate plugin package name "${packageName}"`);
45
+ }
46
+ seen.add(packageName);
47
+ }
48
+ }
49
+ function normalizePluginInput(input) {
50
+ if (typeof input === "string") {
51
+ return { packageName: input };
52
+ }
53
+ return { registration: input };
54
+ }
55
+ function defineJuniorPlugins(inputs, options = {}) {
56
+ const normalized = inputs.map(normalizePluginInput);
57
+ const packageNames = normalized.flatMap(
58
+ (input) => input.packageName ? [input.packageName] : []
59
+ );
60
+ const registrations = normalized.flatMap(
61
+ (input) => input.registration ? [input.registration] : []
62
+ );
63
+ assertUniquePackageNames(packageNames);
64
+ assertUniquePluginNames(registrations);
65
+ const manifests = cloneManifests(options.manifests);
66
+ return {
67
+ packageNames,
68
+ registrations: registrations.map((plugin) => ({ ...plugin })),
69
+ ...manifests ? { manifests } : {}
70
+ };
71
+ }
72
+ function pluginCatalogConfigFromPluginSet(pluginSet) {
73
+ if (!pluginSet) {
74
+ return void 0;
75
+ }
76
+ const packages = [
77
+ .../* @__PURE__ */ new Set([
78
+ ...pluginSet.packageNames,
79
+ ...pluginSet.registrations.flatMap(
80
+ (plugin) => plugin.packageName ? [plugin.packageName] : []
81
+ )
82
+ ])
83
+ ];
84
+ const manifests = cloneManifests(pluginSet.manifests);
85
+ const inlineManifests = cloneInlineManifests(pluginSet.registrations);
86
+ if (packages.length === 0 && !manifests && !inlineManifests) {
87
+ return void 0;
88
+ }
89
+ return {
90
+ ...inlineManifests ? { inlineManifests } : {},
91
+ ...packages.length > 0 ? { packages } : {},
92
+ ...manifests ? { manifests } : {}
93
+ };
94
+ }
95
+ function readEnvPluginPackages(env = process.env) {
96
+ const value = env.JUNIOR_PLUGIN_PACKAGES;
97
+ if (!value) {
98
+ return void 0;
99
+ }
100
+ let parsed;
101
+ try {
102
+ parsed = JSON.parse(value);
103
+ } catch (error) {
104
+ throw new Error("JUNIOR_PLUGIN_PACKAGES must be valid JSON", {
105
+ cause: error
106
+ });
107
+ }
108
+ if (!Array.isArray(parsed) || parsed.some((item) => typeof item !== "string" || !item.trim())) {
109
+ throw new Error(
110
+ "JUNIOR_PLUGIN_PACKAGES must be a JSON array of package names"
111
+ );
112
+ }
113
+ return parsed;
114
+ }
115
+ function pluginCatalogConfigFromEnv(env = process.env) {
116
+ const packages = readEnvPluginPackages(env);
117
+ return packages ? { packages } : void 0;
118
+ }
119
+ function pluginHookRegistrationsFromPluginSet(pluginSet) {
120
+ return pluginSet?.registrations.filter(
121
+ (plugin) => plugin.database || plugin.hooks
122
+ ) ?? [];
123
+ }
124
+
125
+ export {
126
+ defineJuniorPlugins,
127
+ pluginCatalogConfigFromPluginSet,
128
+ pluginCatalogConfigFromEnv,
129
+ pluginHookRegistrationsFromPluginSet
130
+ };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isSlackTeamId
3
- } from "./chunk-3BYAPS6B.js";
3
+ } from "./chunk-MCMROINU.js";
4
4
 
5
5
  // src/chat/requester.ts
6
6
  import { z } from "zod";