@axiom-lattice/pg-stores 1.0.37 → 1.0.39

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/index.js CHANGED
@@ -31,11 +31,13 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  AddMessageParams: () => import_core4.AddMessageParams,
34
+ ChannelIdentityMappingStore: () => ChannelIdentityMappingStore,
34
35
  MigrationManager: () => MigrationManager,
35
36
  PendingMessage: () => import_core4.PendingMessage,
36
- Pool: () => import_pg13.Pool,
37
- PoolConfig: () => import_pg13.PoolConfig,
37
+ Pool: () => import_pg15.Pool,
38
+ PoolConfig: () => import_pg15.PoolConfig,
38
39
  PostgreSQLAssistantStore: () => PostgreSQLAssistantStore,
40
+ PostgreSQLChannelInstallationStore: () => PostgreSQLChannelInstallationStore,
39
41
  PostgreSQLDatabaseConfigStore: () => PostgreSQLDatabaseConfigStore,
40
42
  PostgreSQLMcpServerConfigStore: () => PostgreSQLMcpServerConfigStore,
41
43
  PostgreSQLMetricsServerConfigStore: () => PostgreSQLMetricsServerConfigStore,
@@ -57,6 +59,8 @@ __export(index_exports, {
57
59
  changeSkillPrimaryKey: () => changeSkillPrimaryKey,
58
60
  changeThreadPrimaryKey: () => changeThreadPrimaryKey,
59
61
  createAssistantsTable: () => createAssistantsTable,
62
+ createChannelIdentityMappingTables: () => createChannelIdentityMappingTables,
63
+ createChannelInstallationsTable: () => createChannelInstallationsTable,
60
64
  createDatabaseConfigsTable: () => createDatabaseConfigsTable,
61
65
  createMcpServerConfigsTable: () => createMcpServerConfigsTable,
62
66
  createMetricsConfigsTable: () => createMetricsConfigsTable,
@@ -71,7 +75,7 @@ __export(index_exports, {
71
75
  getThreadMessageQueueStore: () => getThreadMessageQueueStore
72
76
  });
73
77
  module.exports = __toCommonJS(index_exports);
74
- var import_pg13 = require("pg");
78
+ var import_pg15 = require("pg");
75
79
 
76
80
  // src/stores/PostgreSQLThreadStore.ts
77
81
  var import_pg = require("pg");
@@ -4084,6 +4088,90 @@ var createThreadMessageQueueTable = {
4084
4088
  }
4085
4089
  };
4086
4090
 
4091
+ // src/migrations/channel_identity_mapping_migration.ts
4092
+ var createChannelIdentityMappingTables = {
4093
+ version: 20,
4094
+ name: "create_channel_identity_mapping_tables",
4095
+ up: async (client) => {
4096
+ await client.query(`
4097
+ CREATE TABLE IF NOT EXISTS channel_identity_mappings (
4098
+ id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
4099
+ channel VARCHAR(50) NOT NULL,
4100
+ channel_app_id VARCHAR(255) NOT NULL,
4101
+ tenant_id VARCHAR(255) NOT NULL,
4102
+ assistant_id VARCHAR(255) NOT NULL,
4103
+ mapping_mode VARCHAR(20) NOT NULL CHECK (mapping_mode IN ('user', 'group', 'hybrid')),
4104
+ external_subject_type VARCHAR(20) NOT NULL CHECK (external_subject_type IN ('user', 'chat')),
4105
+ external_subject_key VARCHAR(512) NOT NULL,
4106
+ lark_open_id VARCHAR(255),
4107
+ lark_chat_id VARCHAR(255) NOT NULL,
4108
+ lark_message_id VARCHAR(255),
4109
+ thread_id VARCHAR(255) NOT NULL,
4110
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4111
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4112
+ last_activity_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4113
+ UNIQUE (channel, channel_app_id, tenant_id, assistant_id, external_subject_key)
4114
+ )
4115
+ `);
4116
+ await client.query(`
4117
+ CREATE INDEX IF NOT EXISTS idx_channel_identity_lookup
4118
+ ON channel_identity_mappings(channel, channel_app_id, tenant_id, assistant_id, external_subject_key)
4119
+ `);
4120
+ await client.query(`
4121
+ CREATE INDEX IF NOT EXISTS idx_channel_identity_thread
4122
+ ON channel_identity_mappings(thread_id, tenant_id)
4123
+ `);
4124
+ await client.query(`
4125
+ CREATE TABLE IF NOT EXISTS channel_inbound_message_receipts (
4126
+ channel VARCHAR(50) NOT NULL,
4127
+ channel_app_id VARCHAR(255) NOT NULL,
4128
+ external_message_id VARCHAR(255) NOT NULL,
4129
+ tenant_id VARCHAR(255) NOT NULL,
4130
+ status VARCHAR(20) NOT NULL DEFAULT 'processing' CHECK (status IN ('processing', 'completed', 'failed')),
4131
+ thread_id VARCHAR(255),
4132
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4133
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4134
+ PRIMARY KEY (channel, channel_app_id, external_message_id)
4135
+ )
4136
+ `);
4137
+ },
4138
+ down: async (client) => {
4139
+ await client.query("DROP TABLE IF EXISTS channel_inbound_message_receipts");
4140
+ await client.query("DROP INDEX IF EXISTS idx_channel_identity_thread");
4141
+ await client.query("DROP INDEX IF EXISTS idx_channel_identity_lookup");
4142
+ await client.query("DROP TABLE IF EXISTS channel_identity_mappings");
4143
+ }
4144
+ };
4145
+
4146
+ // src/migrations/channel_installation_migrations.ts
4147
+ var createChannelInstallationsTable = {
4148
+ version: 21,
4149
+ name: "create_channel_installations_table",
4150
+ up: async (client) => {
4151
+ await client.query(`
4152
+ CREATE TABLE IF NOT EXISTS lattice_channel_installations (
4153
+ id UUID PRIMARY KEY,
4154
+ tenant_id VARCHAR(255) NOT NULL,
4155
+ channel VARCHAR(50) NOT NULL,
4156
+ name VARCHAR(255),
4157
+ config JSONB NOT NULL,
4158
+ created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
4159
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
4160
+ )
4161
+ `);
4162
+ await client.query(`
4163
+ CREATE INDEX IF NOT EXISTS idx_channel_installations_tenant_channel
4164
+ ON lattice_channel_installations(tenant_id, channel)
4165
+ `);
4166
+ },
4167
+ down: async (client) => {
4168
+ await client.query(
4169
+ "DROP INDEX IF EXISTS idx_channel_installations_tenant_channel"
4170
+ );
4171
+ await client.query("DROP TABLE IF EXISTS lattice_channel_installations");
4172
+ }
4173
+ };
4174
+
4087
4175
  // src/stores/ThreadMessageQueueStore.ts
4088
4176
  var import_crypto = __toESM(require("crypto"));
4089
4177
  var import_core4 = require("@axiom-lattice/core");
@@ -4373,14 +4461,423 @@ var ThreadMessageQueueStore = class _ThreadMessageQueueStore {
4373
4461
  }
4374
4462
  };
4375
4463
  var getThreadMessageQueueStore = () => ThreadMessageQueueStore.getInstance();
4464
+
4465
+ // src/stores/ChannelIdentityMappingStore.ts
4466
+ var import_pg13 = require("pg");
4467
+ var ChannelIdentityMappingStore = class {
4468
+ constructor(options) {
4469
+ this.initialized = false;
4470
+ this.initPromise = null;
4471
+ this.pool = typeof options.poolConfig === "string" ? new import_pg13.Pool({ connectionString: options.poolConfig }) : new import_pg13.Pool(options.poolConfig);
4472
+ this.migrationManager = new MigrationManager(this.pool);
4473
+ this.migrationManager.register(createChannelIdentityMappingTables);
4474
+ if (options.autoMigrate !== false) {
4475
+ this.initialize().catch((error) => {
4476
+ console.error("Failed to initialize ChannelIdentityMappingStore:", error);
4477
+ throw error;
4478
+ });
4479
+ }
4480
+ }
4481
+ async initialize() {
4482
+ if (this.initialized) {
4483
+ return;
4484
+ }
4485
+ if (this.initPromise) {
4486
+ return this.initPromise;
4487
+ }
4488
+ this.initPromise = (async () => {
4489
+ try {
4490
+ await this.migrationManager.migrate();
4491
+ this.initialized = true;
4492
+ } finally {
4493
+ this.initPromise = null;
4494
+ }
4495
+ })();
4496
+ return this.initPromise;
4497
+ }
4498
+ async createMapping(input) {
4499
+ await this.ensureInitialized();
4500
+ const result = await this.pool.query(
4501
+ `
4502
+ INSERT INTO channel_identity_mappings (
4503
+ channel,
4504
+ channel_app_id,
4505
+ tenant_id,
4506
+ assistant_id,
4507
+ mapping_mode,
4508
+ external_subject_type,
4509
+ external_subject_key,
4510
+ lark_open_id,
4511
+ lark_chat_id,
4512
+ lark_message_id,
4513
+ thread_id
4514
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
4515
+ RETURNING *
4516
+ `,
4517
+ [
4518
+ input.channel,
4519
+ input.channelAppId,
4520
+ input.tenantId,
4521
+ input.assistantId,
4522
+ input.mappingMode,
4523
+ input.externalSubjectType,
4524
+ input.externalSubjectKey,
4525
+ input.larkOpenId || null,
4526
+ input.larkChatId,
4527
+ input.larkMessageId || null,
4528
+ input.threadId
4529
+ ]
4530
+ );
4531
+ return mapRowToChannelIdentityMapping(result.rows[0]);
4532
+ }
4533
+ async getMappingBySubject(input) {
4534
+ await this.ensureInitialized();
4535
+ const result = await this.pool.query(
4536
+ `
4537
+ SELECT *
4538
+ FROM channel_identity_mappings
4539
+ WHERE channel = $1
4540
+ AND channel_app_id = $2
4541
+ AND tenant_id = $3
4542
+ AND assistant_id = $4
4543
+ AND external_subject_key = $5
4544
+ LIMIT 1
4545
+ `,
4546
+ [
4547
+ input.channel,
4548
+ input.channelAppId,
4549
+ input.tenantId,
4550
+ input.assistantId,
4551
+ input.externalSubjectKey
4552
+ ]
4553
+ );
4554
+ if (result.rows.length === 0) {
4555
+ return null;
4556
+ }
4557
+ return mapRowToChannelIdentityMapping(result.rows[0]);
4558
+ }
4559
+ async claimInboundReceipt(input) {
4560
+ await this.ensureInitialized();
4561
+ const result = await this.pool.query(
4562
+ `
4563
+ WITH existing AS (
4564
+ SELECT status
4565
+ FROM channel_inbound_message_receipts
4566
+ WHERE channel = $1
4567
+ AND channel_app_id = $2
4568
+ AND external_message_id = $3
4569
+ AND tenant_id = $4
4570
+ ),
4571
+ inserted AS (
4572
+ INSERT INTO channel_inbound_message_receipts (
4573
+ channel,
4574
+ channel_app_id,
4575
+ external_message_id,
4576
+ tenant_id,
4577
+ status
4578
+ )
4579
+ SELECT $1, $2, $3, $4, 'processing'
4580
+ WHERE NOT EXISTS (SELECT 1 FROM existing)
4581
+ RETURNING 'inserted'::text AS source, status
4582
+ ),
4583
+ retried AS (
4584
+ UPDATE channel_inbound_message_receipts
4585
+ SET status = 'processing', updated_at = CURRENT_TIMESTAMP
4586
+ WHERE channel = $1
4587
+ AND channel_app_id = $2
4588
+ AND external_message_id = $3
4589
+ AND tenant_id = $4
4590
+ AND EXISTS (SELECT 1 FROM existing WHERE status = 'failed')
4591
+ RETURNING 'retried'::text AS source, status
4592
+ )
4593
+ SELECT source, status FROM inserted
4594
+ UNION ALL
4595
+ SELECT source, status FROM retried
4596
+ UNION ALL
4597
+ SELECT 'existing'::text AS source, status FROM existing
4598
+ WHERE EXISTS (SELECT 1 FROM existing WHERE status IN ('processing', 'completed'))
4599
+ LIMIT 1
4600
+ `,
4601
+ [
4602
+ input.channel,
4603
+ input.channelAppId,
4604
+ input.externalMessageId,
4605
+ input.tenantId
4606
+ ]
4607
+ );
4608
+ const source = result.rows[0]?.source;
4609
+ const status = result.rows[0]?.status || "processing";
4610
+ if (source === "inserted" || source === "retried") {
4611
+ return { accepted: true, status: "processing" };
4612
+ }
4613
+ if (status === "completed") {
4614
+ return { accepted: false, status: "completed" };
4615
+ }
4616
+ return { accepted: false, status: "processing" };
4617
+ }
4618
+ async markInboundReceiptCompleted(input) {
4619
+ await this.ensureInitialized();
4620
+ await this.pool.query(
4621
+ `
4622
+ UPDATE channel_inbound_message_receipts
4623
+ SET status = 'completed', thread_id = $1, updated_at = CURRENT_TIMESTAMP
4624
+ WHERE channel = $2
4625
+ AND channel_app_id = $3
4626
+ AND external_message_id = $4
4627
+ AND tenant_id = $5
4628
+ `,
4629
+ [
4630
+ input.threadId,
4631
+ input.channel,
4632
+ input.channelAppId,
4633
+ input.externalMessageId,
4634
+ input.tenantId
4635
+ ]
4636
+ );
4637
+ }
4638
+ async markInboundReceiptFailed(input) {
4639
+ await this.ensureInitialized();
4640
+ await this.pool.query(
4641
+ `
4642
+ UPDATE channel_inbound_message_receipts
4643
+ SET status = 'failed', updated_at = CURRENT_TIMESTAMP
4644
+ WHERE channel = $1
4645
+ AND channel_app_id = $2
4646
+ AND external_message_id = $3
4647
+ AND tenant_id = $4
4648
+ `,
4649
+ [
4650
+ input.channel,
4651
+ input.channelAppId,
4652
+ input.externalMessageId,
4653
+ input.tenantId
4654
+ ]
4655
+ );
4656
+ }
4657
+ async ensureInitialized() {
4658
+ if (!this.initialized) {
4659
+ await this.initialize();
4660
+ }
4661
+ }
4662
+ };
4663
+ function mapRowToChannelIdentityMapping(row) {
4664
+ return {
4665
+ id: row.id,
4666
+ channel: row.channel,
4667
+ channelAppId: row.channel_app_id,
4668
+ tenantId: row.tenant_id,
4669
+ assistantId: row.assistant_id,
4670
+ mappingMode: row.mapping_mode,
4671
+ externalSubjectType: row.external_subject_type,
4672
+ externalSubjectKey: row.external_subject_key,
4673
+ larkOpenId: row.lark_open_id || void 0,
4674
+ larkChatId: row.lark_chat_id,
4675
+ larkMessageId: row.lark_message_id || void 0,
4676
+ threadId: row.thread_id,
4677
+ createdAt: row.created_at,
4678
+ updatedAt: row.updated_at,
4679
+ lastActivityAt: row.last_activity_at
4680
+ };
4681
+ }
4682
+
4683
+ // src/stores/PostgreSQLChannelInstallationStore.ts
4684
+ var import_pg14 = require("pg");
4685
+ var import_core5 = require("@axiom-lattice/core");
4686
+ var PostgreSQLChannelInstallationStore = class {
4687
+ constructor(options) {
4688
+ this.initialized = false;
4689
+ this.initPromise = null;
4690
+ this.pool = typeof options.poolConfig === "string" ? new import_pg14.Pool({ connectionString: options.poolConfig }) : new import_pg14.Pool(options.poolConfig);
4691
+ this.migrationManager = new MigrationManager(this.pool);
4692
+ this.migrationManager.register(createChannelInstallationsTable);
4693
+ if (options.autoMigrate !== false) {
4694
+ this.initialize().catch((error) => {
4695
+ console.error(
4696
+ "Failed to initialize PostgreSQLChannelInstallationStore:",
4697
+ error
4698
+ );
4699
+ throw error;
4700
+ });
4701
+ }
4702
+ }
4703
+ async initialize() {
4704
+ if (this.initialized) {
4705
+ return;
4706
+ }
4707
+ if (this.initPromise) {
4708
+ return this.initPromise;
4709
+ }
4710
+ this.initPromise = (async () => {
4711
+ try {
4712
+ await this.migrationManager.migrate();
4713
+ this.initialized = true;
4714
+ } finally {
4715
+ this.initPromise = null;
4716
+ }
4717
+ })();
4718
+ return this.initPromise;
4719
+ }
4720
+ async getInstallationById(installationId) {
4721
+ await this.ensureInitialized();
4722
+ const result = await this.pool.query(
4723
+ `
4724
+ SELECT id, tenant_id, channel, name, config, created_at, updated_at
4725
+ FROM lattice_channel_installations
4726
+ WHERE id = $1
4727
+ LIMIT 1
4728
+ `,
4729
+ [installationId]
4730
+ );
4731
+ if (result.rows.length === 0) {
4732
+ return null;
4733
+ }
4734
+ return this.mapRowToInstallation(result.rows[0]);
4735
+ }
4736
+ async getInstallationsByTenant(tenantId, channel) {
4737
+ await this.ensureInitialized();
4738
+ const result = channel ? await this.pool.query(
4739
+ `
4740
+ SELECT id, tenant_id, channel, name, config, created_at, updated_at
4741
+ FROM lattice_channel_installations
4742
+ WHERE tenant_id = $1 AND channel = $2
4743
+ ORDER BY created_at DESC
4744
+ `,
4745
+ [tenantId, channel]
4746
+ ) : await this.pool.query(
4747
+ `
4748
+ SELECT id, tenant_id, channel, name, config, created_at, updated_at
4749
+ FROM lattice_channel_installations
4750
+ WHERE tenant_id = $1
4751
+ ORDER BY created_at DESC
4752
+ `,
4753
+ [tenantId]
4754
+ );
4755
+ return result.rows.map((row) => this.mapRowToInstallation(row));
4756
+ }
4757
+ async createInstallation(tenantId, installationId, data) {
4758
+ await this.ensureInitialized();
4759
+ const now = /* @__PURE__ */ new Date();
4760
+ const encryptedConfig = this.encryptSecrets(data.config);
4761
+ await this.pool.query(
4762
+ `
4763
+ INSERT INTO lattice_channel_installations (
4764
+ id, tenant_id, channel, name, config, created_at, updated_at
4765
+ ) VALUES ($1, $2, $3, $4, $5, $6, $7)
4766
+ `,
4767
+ [
4768
+ installationId,
4769
+ tenantId,
4770
+ data.channel,
4771
+ data.name || null,
4772
+ JSON.stringify(encryptedConfig),
4773
+ now,
4774
+ now
4775
+ ]
4776
+ );
4777
+ return {
4778
+ id: installationId,
4779
+ tenantId,
4780
+ channel: data.channel,
4781
+ name: data.name,
4782
+ config: data.config,
4783
+ createdAt: now,
4784
+ updatedAt: now
4785
+ };
4786
+ }
4787
+ async updateInstallation(tenantId, installationId, updates) {
4788
+ await this.ensureInitialized();
4789
+ const existing = await this.getInstallationById(installationId);
4790
+ if (!existing || existing.tenantId !== tenantId) {
4791
+ return null;
4792
+ }
4793
+ const mergedConfig = {
4794
+ ...existing.config,
4795
+ ...updates.config || {}
4796
+ };
4797
+ const now = /* @__PURE__ */ new Date();
4798
+ await this.pool.query(
4799
+ `
4800
+ UPDATE lattice_channel_installations
4801
+ SET name = $1,
4802
+ config = $2,
4803
+ updated_at = $3
4804
+ WHERE tenant_id = $4 AND id = $5
4805
+ `,
4806
+ [
4807
+ updates.name ?? existing.name ?? null,
4808
+ JSON.stringify(this.encryptSecrets(mergedConfig)),
4809
+ now,
4810
+ tenantId,
4811
+ installationId
4812
+ ]
4813
+ );
4814
+ return {
4815
+ ...existing,
4816
+ name: updates.name ?? existing.name,
4817
+ config: mergedConfig,
4818
+ updatedAt: now
4819
+ };
4820
+ }
4821
+ async deleteInstallation(tenantId, installationId) {
4822
+ await this.ensureInitialized();
4823
+ const result = await this.pool.query(
4824
+ `
4825
+ DELETE FROM lattice_channel_installations
4826
+ WHERE tenant_id = $1 AND id = $2
4827
+ `,
4828
+ [tenantId, installationId]
4829
+ );
4830
+ return (result.rowCount || 0) > 0;
4831
+ }
4832
+ async ensureInitialized() {
4833
+ if (!this.initialized) {
4834
+ await this.initialize();
4835
+ }
4836
+ }
4837
+ mapRowToInstallation(row) {
4838
+ return {
4839
+ id: row.id,
4840
+ tenantId: row.tenant_id,
4841
+ channel: row.channel,
4842
+ name: row.name || void 0,
4843
+ config: this.decryptSecrets(
4844
+ typeof row.config === "string" ? JSON.parse(row.config) : row.config
4845
+ ),
4846
+ createdAt: row.created_at,
4847
+ updatedAt: row.updated_at
4848
+ };
4849
+ }
4850
+ encryptSecrets(config) {
4851
+ return {
4852
+ ...config,
4853
+ appSecret: typeof config.appSecret === "string" ? (0, import_core5.encrypt)(config.appSecret) : config.appSecret,
4854
+ verificationToken: typeof config.verificationToken === "string" ? (0, import_core5.encrypt)(config.verificationToken) : config.verificationToken,
4855
+ encryptKey: typeof config.encryptKey === "string" ? (0, import_core5.encrypt)(config.encryptKey) : config.encryptKey
4856
+ };
4857
+ }
4858
+ decryptSecrets(config) {
4859
+ return {
4860
+ appId: String(config.appId || ""),
4861
+ appSecret: typeof config.appSecret === "string" ? (0, import_core5.decrypt)(config.appSecret) : "",
4862
+ verificationToken: typeof config.verificationToken === "string" ? (0, import_core5.decrypt)(config.verificationToken) : void 0,
4863
+ encryptKey: typeof config.encryptKey === "string" ? (0, import_core5.decrypt)(config.encryptKey) : void 0,
4864
+ mappingMode: config.mappingMode === "user" || config.mappingMode === "group" || config.mappingMode === "hybrid" ? config.mappingMode : "hybrid",
4865
+ assistantId: String(config.assistantId || ""),
4866
+ workspaceId: typeof config.workspaceId === "string" ? config.workspaceId : void 0,
4867
+ projectId: typeof config.projectId === "string" ? config.projectId : void 0
4868
+ };
4869
+ }
4870
+ };
4376
4871
  // Annotate the CommonJS export names for ESM import in node:
4377
4872
  0 && (module.exports = {
4378
4873
  AddMessageParams,
4874
+ ChannelIdentityMappingStore,
4379
4875
  MigrationManager,
4380
4876
  PendingMessage,
4381
4877
  Pool,
4382
4878
  PoolConfig,
4383
4879
  PostgreSQLAssistantStore,
4880
+ PostgreSQLChannelInstallationStore,
4384
4881
  PostgreSQLDatabaseConfigStore,
4385
4882
  PostgreSQLMcpServerConfigStore,
4386
4883
  PostgreSQLMetricsServerConfigStore,
@@ -4402,6 +4899,8 @@ var getThreadMessageQueueStore = () => ThreadMessageQueueStore.getInstance();
4402
4899
  changeSkillPrimaryKey,
4403
4900
  changeThreadPrimaryKey,
4404
4901
  createAssistantsTable,
4902
+ createChannelIdentityMappingTables,
4903
+ createChannelInstallationsTable,
4405
4904
  createDatabaseConfigsTable,
4406
4905
  createMcpServerConfigsTable,
4407
4906
  createMetricsConfigsTable,