@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/.turbo/turbo-build.log +10 -10
- package/CHANGELOG.md +16 -0
- package/dist/index.d.mts +103 -3
- package/dist/index.d.ts +103 -3
- package/dist/index.js +502 -3
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +498 -3
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
- package/src/__tests__/ChannelIdentityMappingStore.test.ts +219 -0
- package/src/__tests__/PostgreSQLChannelInstallationStore.test.ts +54 -0
- package/src/index.ts +11 -0
- package/src/migrations/channel_identity_mapping_migration.ts +59 -0
- package/src/migrations/channel_installation_migrations.ts +31 -0
- package/src/stores/ChannelIdentityMappingStore.ts +334 -0
- package/src/stores/PostgreSQLChannelInstallationStore.ts +304 -0
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import { Pool as
|
|
2
|
+
import { Pool as Pool15, PoolConfig as PoolConfig15 } from "pg";
|
|
3
3
|
|
|
4
4
|
// src/stores/PostgreSQLThreadStore.ts
|
|
5
5
|
import { Pool } from "pg";
|
|
@@ -4014,6 +4014,90 @@ var createThreadMessageQueueTable = {
|
|
|
4014
4014
|
}
|
|
4015
4015
|
};
|
|
4016
4016
|
|
|
4017
|
+
// src/migrations/channel_identity_mapping_migration.ts
|
|
4018
|
+
var createChannelIdentityMappingTables = {
|
|
4019
|
+
version: 20,
|
|
4020
|
+
name: "create_channel_identity_mapping_tables",
|
|
4021
|
+
up: async (client) => {
|
|
4022
|
+
await client.query(`
|
|
4023
|
+
CREATE TABLE IF NOT EXISTS channel_identity_mappings (
|
|
4024
|
+
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
|
|
4025
|
+
channel VARCHAR(50) NOT NULL,
|
|
4026
|
+
channel_app_id VARCHAR(255) NOT NULL,
|
|
4027
|
+
tenant_id VARCHAR(255) NOT NULL,
|
|
4028
|
+
assistant_id VARCHAR(255) NOT NULL,
|
|
4029
|
+
mapping_mode VARCHAR(20) NOT NULL CHECK (mapping_mode IN ('user', 'group', 'hybrid')),
|
|
4030
|
+
external_subject_type VARCHAR(20) NOT NULL CHECK (external_subject_type IN ('user', 'chat')),
|
|
4031
|
+
external_subject_key VARCHAR(512) NOT NULL,
|
|
4032
|
+
lark_open_id VARCHAR(255),
|
|
4033
|
+
lark_chat_id VARCHAR(255) NOT NULL,
|
|
4034
|
+
lark_message_id VARCHAR(255),
|
|
4035
|
+
thread_id VARCHAR(255) NOT NULL,
|
|
4036
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
4037
|
+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
4038
|
+
last_activity_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
4039
|
+
UNIQUE (channel, channel_app_id, tenant_id, assistant_id, external_subject_key)
|
|
4040
|
+
)
|
|
4041
|
+
`);
|
|
4042
|
+
await client.query(`
|
|
4043
|
+
CREATE INDEX IF NOT EXISTS idx_channel_identity_lookup
|
|
4044
|
+
ON channel_identity_mappings(channel, channel_app_id, tenant_id, assistant_id, external_subject_key)
|
|
4045
|
+
`);
|
|
4046
|
+
await client.query(`
|
|
4047
|
+
CREATE INDEX IF NOT EXISTS idx_channel_identity_thread
|
|
4048
|
+
ON channel_identity_mappings(thread_id, tenant_id)
|
|
4049
|
+
`);
|
|
4050
|
+
await client.query(`
|
|
4051
|
+
CREATE TABLE IF NOT EXISTS channel_inbound_message_receipts (
|
|
4052
|
+
channel VARCHAR(50) NOT NULL,
|
|
4053
|
+
channel_app_id VARCHAR(255) NOT NULL,
|
|
4054
|
+
external_message_id VARCHAR(255) NOT NULL,
|
|
4055
|
+
tenant_id VARCHAR(255) NOT NULL,
|
|
4056
|
+
status VARCHAR(20) NOT NULL DEFAULT 'processing' CHECK (status IN ('processing', 'completed', 'failed')),
|
|
4057
|
+
thread_id VARCHAR(255),
|
|
4058
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
4059
|
+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
4060
|
+
PRIMARY KEY (channel, channel_app_id, external_message_id)
|
|
4061
|
+
)
|
|
4062
|
+
`);
|
|
4063
|
+
},
|
|
4064
|
+
down: async (client) => {
|
|
4065
|
+
await client.query("DROP TABLE IF EXISTS channel_inbound_message_receipts");
|
|
4066
|
+
await client.query("DROP INDEX IF EXISTS idx_channel_identity_thread");
|
|
4067
|
+
await client.query("DROP INDEX IF EXISTS idx_channel_identity_lookup");
|
|
4068
|
+
await client.query("DROP TABLE IF EXISTS channel_identity_mappings");
|
|
4069
|
+
}
|
|
4070
|
+
};
|
|
4071
|
+
|
|
4072
|
+
// src/migrations/channel_installation_migrations.ts
|
|
4073
|
+
var createChannelInstallationsTable = {
|
|
4074
|
+
version: 21,
|
|
4075
|
+
name: "create_channel_installations_table",
|
|
4076
|
+
up: async (client) => {
|
|
4077
|
+
await client.query(`
|
|
4078
|
+
CREATE TABLE IF NOT EXISTS lattice_channel_installations (
|
|
4079
|
+
id UUID PRIMARY KEY,
|
|
4080
|
+
tenant_id VARCHAR(255) NOT NULL,
|
|
4081
|
+
channel VARCHAR(50) NOT NULL,
|
|
4082
|
+
name VARCHAR(255),
|
|
4083
|
+
config JSONB NOT NULL,
|
|
4084
|
+
created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
|
4085
|
+
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
|
|
4086
|
+
)
|
|
4087
|
+
`);
|
|
4088
|
+
await client.query(`
|
|
4089
|
+
CREATE INDEX IF NOT EXISTS idx_channel_installations_tenant_channel
|
|
4090
|
+
ON lattice_channel_installations(tenant_id, channel)
|
|
4091
|
+
`);
|
|
4092
|
+
},
|
|
4093
|
+
down: async (client) => {
|
|
4094
|
+
await client.query(
|
|
4095
|
+
"DROP INDEX IF EXISTS idx_channel_installations_tenant_channel"
|
|
4096
|
+
);
|
|
4097
|
+
await client.query("DROP TABLE IF EXISTS lattice_channel_installations");
|
|
4098
|
+
}
|
|
4099
|
+
};
|
|
4100
|
+
|
|
4017
4101
|
// src/stores/ThreadMessageQueueStore.ts
|
|
4018
4102
|
import crypto from "crypto";
|
|
4019
4103
|
import {
|
|
@@ -4307,13 +4391,422 @@ var ThreadMessageQueueStore = class _ThreadMessageQueueStore {
|
|
|
4307
4391
|
}
|
|
4308
4392
|
};
|
|
4309
4393
|
var getThreadMessageQueueStore = () => ThreadMessageQueueStore.getInstance();
|
|
4394
|
+
|
|
4395
|
+
// src/stores/ChannelIdentityMappingStore.ts
|
|
4396
|
+
import { Pool as Pool13 } from "pg";
|
|
4397
|
+
var ChannelIdentityMappingStore = class {
|
|
4398
|
+
constructor(options) {
|
|
4399
|
+
this.initialized = false;
|
|
4400
|
+
this.initPromise = null;
|
|
4401
|
+
this.pool = typeof options.poolConfig === "string" ? new Pool13({ connectionString: options.poolConfig }) : new Pool13(options.poolConfig);
|
|
4402
|
+
this.migrationManager = new MigrationManager(this.pool);
|
|
4403
|
+
this.migrationManager.register(createChannelIdentityMappingTables);
|
|
4404
|
+
if (options.autoMigrate !== false) {
|
|
4405
|
+
this.initialize().catch((error) => {
|
|
4406
|
+
console.error("Failed to initialize ChannelIdentityMappingStore:", error);
|
|
4407
|
+
throw error;
|
|
4408
|
+
});
|
|
4409
|
+
}
|
|
4410
|
+
}
|
|
4411
|
+
async initialize() {
|
|
4412
|
+
if (this.initialized) {
|
|
4413
|
+
return;
|
|
4414
|
+
}
|
|
4415
|
+
if (this.initPromise) {
|
|
4416
|
+
return this.initPromise;
|
|
4417
|
+
}
|
|
4418
|
+
this.initPromise = (async () => {
|
|
4419
|
+
try {
|
|
4420
|
+
await this.migrationManager.migrate();
|
|
4421
|
+
this.initialized = true;
|
|
4422
|
+
} finally {
|
|
4423
|
+
this.initPromise = null;
|
|
4424
|
+
}
|
|
4425
|
+
})();
|
|
4426
|
+
return this.initPromise;
|
|
4427
|
+
}
|
|
4428
|
+
async createMapping(input) {
|
|
4429
|
+
await this.ensureInitialized();
|
|
4430
|
+
const result = await this.pool.query(
|
|
4431
|
+
`
|
|
4432
|
+
INSERT INTO channel_identity_mappings (
|
|
4433
|
+
channel,
|
|
4434
|
+
channel_app_id,
|
|
4435
|
+
tenant_id,
|
|
4436
|
+
assistant_id,
|
|
4437
|
+
mapping_mode,
|
|
4438
|
+
external_subject_type,
|
|
4439
|
+
external_subject_key,
|
|
4440
|
+
lark_open_id,
|
|
4441
|
+
lark_chat_id,
|
|
4442
|
+
lark_message_id,
|
|
4443
|
+
thread_id
|
|
4444
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)
|
|
4445
|
+
RETURNING *
|
|
4446
|
+
`,
|
|
4447
|
+
[
|
|
4448
|
+
input.channel,
|
|
4449
|
+
input.channelAppId,
|
|
4450
|
+
input.tenantId,
|
|
4451
|
+
input.assistantId,
|
|
4452
|
+
input.mappingMode,
|
|
4453
|
+
input.externalSubjectType,
|
|
4454
|
+
input.externalSubjectKey,
|
|
4455
|
+
input.larkOpenId || null,
|
|
4456
|
+
input.larkChatId,
|
|
4457
|
+
input.larkMessageId || null,
|
|
4458
|
+
input.threadId
|
|
4459
|
+
]
|
|
4460
|
+
);
|
|
4461
|
+
return mapRowToChannelIdentityMapping(result.rows[0]);
|
|
4462
|
+
}
|
|
4463
|
+
async getMappingBySubject(input) {
|
|
4464
|
+
await this.ensureInitialized();
|
|
4465
|
+
const result = await this.pool.query(
|
|
4466
|
+
`
|
|
4467
|
+
SELECT *
|
|
4468
|
+
FROM channel_identity_mappings
|
|
4469
|
+
WHERE channel = $1
|
|
4470
|
+
AND channel_app_id = $2
|
|
4471
|
+
AND tenant_id = $3
|
|
4472
|
+
AND assistant_id = $4
|
|
4473
|
+
AND external_subject_key = $5
|
|
4474
|
+
LIMIT 1
|
|
4475
|
+
`,
|
|
4476
|
+
[
|
|
4477
|
+
input.channel,
|
|
4478
|
+
input.channelAppId,
|
|
4479
|
+
input.tenantId,
|
|
4480
|
+
input.assistantId,
|
|
4481
|
+
input.externalSubjectKey
|
|
4482
|
+
]
|
|
4483
|
+
);
|
|
4484
|
+
if (result.rows.length === 0) {
|
|
4485
|
+
return null;
|
|
4486
|
+
}
|
|
4487
|
+
return mapRowToChannelIdentityMapping(result.rows[0]);
|
|
4488
|
+
}
|
|
4489
|
+
async claimInboundReceipt(input) {
|
|
4490
|
+
await this.ensureInitialized();
|
|
4491
|
+
const result = await this.pool.query(
|
|
4492
|
+
`
|
|
4493
|
+
WITH existing AS (
|
|
4494
|
+
SELECT status
|
|
4495
|
+
FROM channel_inbound_message_receipts
|
|
4496
|
+
WHERE channel = $1
|
|
4497
|
+
AND channel_app_id = $2
|
|
4498
|
+
AND external_message_id = $3
|
|
4499
|
+
AND tenant_id = $4
|
|
4500
|
+
),
|
|
4501
|
+
inserted AS (
|
|
4502
|
+
INSERT INTO channel_inbound_message_receipts (
|
|
4503
|
+
channel,
|
|
4504
|
+
channel_app_id,
|
|
4505
|
+
external_message_id,
|
|
4506
|
+
tenant_id,
|
|
4507
|
+
status
|
|
4508
|
+
)
|
|
4509
|
+
SELECT $1, $2, $3, $4, 'processing'
|
|
4510
|
+
WHERE NOT EXISTS (SELECT 1 FROM existing)
|
|
4511
|
+
RETURNING 'inserted'::text AS source, status
|
|
4512
|
+
),
|
|
4513
|
+
retried AS (
|
|
4514
|
+
UPDATE channel_inbound_message_receipts
|
|
4515
|
+
SET status = 'processing', updated_at = CURRENT_TIMESTAMP
|
|
4516
|
+
WHERE channel = $1
|
|
4517
|
+
AND channel_app_id = $2
|
|
4518
|
+
AND external_message_id = $3
|
|
4519
|
+
AND tenant_id = $4
|
|
4520
|
+
AND EXISTS (SELECT 1 FROM existing WHERE status = 'failed')
|
|
4521
|
+
RETURNING 'retried'::text AS source, status
|
|
4522
|
+
)
|
|
4523
|
+
SELECT source, status FROM inserted
|
|
4524
|
+
UNION ALL
|
|
4525
|
+
SELECT source, status FROM retried
|
|
4526
|
+
UNION ALL
|
|
4527
|
+
SELECT 'existing'::text AS source, status FROM existing
|
|
4528
|
+
WHERE EXISTS (SELECT 1 FROM existing WHERE status IN ('processing', 'completed'))
|
|
4529
|
+
LIMIT 1
|
|
4530
|
+
`,
|
|
4531
|
+
[
|
|
4532
|
+
input.channel,
|
|
4533
|
+
input.channelAppId,
|
|
4534
|
+
input.externalMessageId,
|
|
4535
|
+
input.tenantId
|
|
4536
|
+
]
|
|
4537
|
+
);
|
|
4538
|
+
const source = result.rows[0]?.source;
|
|
4539
|
+
const status = result.rows[0]?.status || "processing";
|
|
4540
|
+
if (source === "inserted" || source === "retried") {
|
|
4541
|
+
return { accepted: true, status: "processing" };
|
|
4542
|
+
}
|
|
4543
|
+
if (status === "completed") {
|
|
4544
|
+
return { accepted: false, status: "completed" };
|
|
4545
|
+
}
|
|
4546
|
+
return { accepted: false, status: "processing" };
|
|
4547
|
+
}
|
|
4548
|
+
async markInboundReceiptCompleted(input) {
|
|
4549
|
+
await this.ensureInitialized();
|
|
4550
|
+
await this.pool.query(
|
|
4551
|
+
`
|
|
4552
|
+
UPDATE channel_inbound_message_receipts
|
|
4553
|
+
SET status = 'completed', thread_id = $1, updated_at = CURRENT_TIMESTAMP
|
|
4554
|
+
WHERE channel = $2
|
|
4555
|
+
AND channel_app_id = $3
|
|
4556
|
+
AND external_message_id = $4
|
|
4557
|
+
AND tenant_id = $5
|
|
4558
|
+
`,
|
|
4559
|
+
[
|
|
4560
|
+
input.threadId,
|
|
4561
|
+
input.channel,
|
|
4562
|
+
input.channelAppId,
|
|
4563
|
+
input.externalMessageId,
|
|
4564
|
+
input.tenantId
|
|
4565
|
+
]
|
|
4566
|
+
);
|
|
4567
|
+
}
|
|
4568
|
+
async markInboundReceiptFailed(input) {
|
|
4569
|
+
await this.ensureInitialized();
|
|
4570
|
+
await this.pool.query(
|
|
4571
|
+
`
|
|
4572
|
+
UPDATE channel_inbound_message_receipts
|
|
4573
|
+
SET status = 'failed', updated_at = CURRENT_TIMESTAMP
|
|
4574
|
+
WHERE channel = $1
|
|
4575
|
+
AND channel_app_id = $2
|
|
4576
|
+
AND external_message_id = $3
|
|
4577
|
+
AND tenant_id = $4
|
|
4578
|
+
`,
|
|
4579
|
+
[
|
|
4580
|
+
input.channel,
|
|
4581
|
+
input.channelAppId,
|
|
4582
|
+
input.externalMessageId,
|
|
4583
|
+
input.tenantId
|
|
4584
|
+
]
|
|
4585
|
+
);
|
|
4586
|
+
}
|
|
4587
|
+
async ensureInitialized() {
|
|
4588
|
+
if (!this.initialized) {
|
|
4589
|
+
await this.initialize();
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
};
|
|
4593
|
+
function mapRowToChannelIdentityMapping(row) {
|
|
4594
|
+
return {
|
|
4595
|
+
id: row.id,
|
|
4596
|
+
channel: row.channel,
|
|
4597
|
+
channelAppId: row.channel_app_id,
|
|
4598
|
+
tenantId: row.tenant_id,
|
|
4599
|
+
assistantId: row.assistant_id,
|
|
4600
|
+
mappingMode: row.mapping_mode,
|
|
4601
|
+
externalSubjectType: row.external_subject_type,
|
|
4602
|
+
externalSubjectKey: row.external_subject_key,
|
|
4603
|
+
larkOpenId: row.lark_open_id || void 0,
|
|
4604
|
+
larkChatId: row.lark_chat_id,
|
|
4605
|
+
larkMessageId: row.lark_message_id || void 0,
|
|
4606
|
+
threadId: row.thread_id,
|
|
4607
|
+
createdAt: row.created_at,
|
|
4608
|
+
updatedAt: row.updated_at,
|
|
4609
|
+
lastActivityAt: row.last_activity_at
|
|
4610
|
+
};
|
|
4611
|
+
}
|
|
4612
|
+
|
|
4613
|
+
// src/stores/PostgreSQLChannelInstallationStore.ts
|
|
4614
|
+
import { Pool as Pool14 } from "pg";
|
|
4615
|
+
import { decrypt as decrypt4, encrypt as encrypt4 } from "@axiom-lattice/core";
|
|
4616
|
+
var PostgreSQLChannelInstallationStore = class {
|
|
4617
|
+
constructor(options) {
|
|
4618
|
+
this.initialized = false;
|
|
4619
|
+
this.initPromise = null;
|
|
4620
|
+
this.pool = typeof options.poolConfig === "string" ? new Pool14({ connectionString: options.poolConfig }) : new Pool14(options.poolConfig);
|
|
4621
|
+
this.migrationManager = new MigrationManager(this.pool);
|
|
4622
|
+
this.migrationManager.register(createChannelInstallationsTable);
|
|
4623
|
+
if (options.autoMigrate !== false) {
|
|
4624
|
+
this.initialize().catch((error) => {
|
|
4625
|
+
console.error(
|
|
4626
|
+
"Failed to initialize PostgreSQLChannelInstallationStore:",
|
|
4627
|
+
error
|
|
4628
|
+
);
|
|
4629
|
+
throw error;
|
|
4630
|
+
});
|
|
4631
|
+
}
|
|
4632
|
+
}
|
|
4633
|
+
async initialize() {
|
|
4634
|
+
if (this.initialized) {
|
|
4635
|
+
return;
|
|
4636
|
+
}
|
|
4637
|
+
if (this.initPromise) {
|
|
4638
|
+
return this.initPromise;
|
|
4639
|
+
}
|
|
4640
|
+
this.initPromise = (async () => {
|
|
4641
|
+
try {
|
|
4642
|
+
await this.migrationManager.migrate();
|
|
4643
|
+
this.initialized = true;
|
|
4644
|
+
} finally {
|
|
4645
|
+
this.initPromise = null;
|
|
4646
|
+
}
|
|
4647
|
+
})();
|
|
4648
|
+
return this.initPromise;
|
|
4649
|
+
}
|
|
4650
|
+
async getInstallationById(installationId) {
|
|
4651
|
+
await this.ensureInitialized();
|
|
4652
|
+
const result = await this.pool.query(
|
|
4653
|
+
`
|
|
4654
|
+
SELECT id, tenant_id, channel, name, config, created_at, updated_at
|
|
4655
|
+
FROM lattice_channel_installations
|
|
4656
|
+
WHERE id = $1
|
|
4657
|
+
LIMIT 1
|
|
4658
|
+
`,
|
|
4659
|
+
[installationId]
|
|
4660
|
+
);
|
|
4661
|
+
if (result.rows.length === 0) {
|
|
4662
|
+
return null;
|
|
4663
|
+
}
|
|
4664
|
+
return this.mapRowToInstallation(result.rows[0]);
|
|
4665
|
+
}
|
|
4666
|
+
async getInstallationsByTenant(tenantId, channel) {
|
|
4667
|
+
await this.ensureInitialized();
|
|
4668
|
+
const result = channel ? await this.pool.query(
|
|
4669
|
+
`
|
|
4670
|
+
SELECT id, tenant_id, channel, name, config, created_at, updated_at
|
|
4671
|
+
FROM lattice_channel_installations
|
|
4672
|
+
WHERE tenant_id = $1 AND channel = $2
|
|
4673
|
+
ORDER BY created_at DESC
|
|
4674
|
+
`,
|
|
4675
|
+
[tenantId, channel]
|
|
4676
|
+
) : await this.pool.query(
|
|
4677
|
+
`
|
|
4678
|
+
SELECT id, tenant_id, channel, name, config, created_at, updated_at
|
|
4679
|
+
FROM lattice_channel_installations
|
|
4680
|
+
WHERE tenant_id = $1
|
|
4681
|
+
ORDER BY created_at DESC
|
|
4682
|
+
`,
|
|
4683
|
+
[tenantId]
|
|
4684
|
+
);
|
|
4685
|
+
return result.rows.map((row) => this.mapRowToInstallation(row));
|
|
4686
|
+
}
|
|
4687
|
+
async createInstallation(tenantId, installationId, data) {
|
|
4688
|
+
await this.ensureInitialized();
|
|
4689
|
+
const now = /* @__PURE__ */ new Date();
|
|
4690
|
+
const encryptedConfig = this.encryptSecrets(data.config);
|
|
4691
|
+
await this.pool.query(
|
|
4692
|
+
`
|
|
4693
|
+
INSERT INTO lattice_channel_installations (
|
|
4694
|
+
id, tenant_id, channel, name, config, created_at, updated_at
|
|
4695
|
+
) VALUES ($1, $2, $3, $4, $5, $6, $7)
|
|
4696
|
+
`,
|
|
4697
|
+
[
|
|
4698
|
+
installationId,
|
|
4699
|
+
tenantId,
|
|
4700
|
+
data.channel,
|
|
4701
|
+
data.name || null,
|
|
4702
|
+
JSON.stringify(encryptedConfig),
|
|
4703
|
+
now,
|
|
4704
|
+
now
|
|
4705
|
+
]
|
|
4706
|
+
);
|
|
4707
|
+
return {
|
|
4708
|
+
id: installationId,
|
|
4709
|
+
tenantId,
|
|
4710
|
+
channel: data.channel,
|
|
4711
|
+
name: data.name,
|
|
4712
|
+
config: data.config,
|
|
4713
|
+
createdAt: now,
|
|
4714
|
+
updatedAt: now
|
|
4715
|
+
};
|
|
4716
|
+
}
|
|
4717
|
+
async updateInstallation(tenantId, installationId, updates) {
|
|
4718
|
+
await this.ensureInitialized();
|
|
4719
|
+
const existing = await this.getInstallationById(installationId);
|
|
4720
|
+
if (!existing || existing.tenantId !== tenantId) {
|
|
4721
|
+
return null;
|
|
4722
|
+
}
|
|
4723
|
+
const mergedConfig = {
|
|
4724
|
+
...existing.config,
|
|
4725
|
+
...updates.config || {}
|
|
4726
|
+
};
|
|
4727
|
+
const now = /* @__PURE__ */ new Date();
|
|
4728
|
+
await this.pool.query(
|
|
4729
|
+
`
|
|
4730
|
+
UPDATE lattice_channel_installations
|
|
4731
|
+
SET name = $1,
|
|
4732
|
+
config = $2,
|
|
4733
|
+
updated_at = $3
|
|
4734
|
+
WHERE tenant_id = $4 AND id = $5
|
|
4735
|
+
`,
|
|
4736
|
+
[
|
|
4737
|
+
updates.name ?? existing.name ?? null,
|
|
4738
|
+
JSON.stringify(this.encryptSecrets(mergedConfig)),
|
|
4739
|
+
now,
|
|
4740
|
+
tenantId,
|
|
4741
|
+
installationId
|
|
4742
|
+
]
|
|
4743
|
+
);
|
|
4744
|
+
return {
|
|
4745
|
+
...existing,
|
|
4746
|
+
name: updates.name ?? existing.name,
|
|
4747
|
+
config: mergedConfig,
|
|
4748
|
+
updatedAt: now
|
|
4749
|
+
};
|
|
4750
|
+
}
|
|
4751
|
+
async deleteInstallation(tenantId, installationId) {
|
|
4752
|
+
await this.ensureInitialized();
|
|
4753
|
+
const result = await this.pool.query(
|
|
4754
|
+
`
|
|
4755
|
+
DELETE FROM lattice_channel_installations
|
|
4756
|
+
WHERE tenant_id = $1 AND id = $2
|
|
4757
|
+
`,
|
|
4758
|
+
[tenantId, installationId]
|
|
4759
|
+
);
|
|
4760
|
+
return (result.rowCount || 0) > 0;
|
|
4761
|
+
}
|
|
4762
|
+
async ensureInitialized() {
|
|
4763
|
+
if (!this.initialized) {
|
|
4764
|
+
await this.initialize();
|
|
4765
|
+
}
|
|
4766
|
+
}
|
|
4767
|
+
mapRowToInstallation(row) {
|
|
4768
|
+
return {
|
|
4769
|
+
id: row.id,
|
|
4770
|
+
tenantId: row.tenant_id,
|
|
4771
|
+
channel: row.channel,
|
|
4772
|
+
name: row.name || void 0,
|
|
4773
|
+
config: this.decryptSecrets(
|
|
4774
|
+
typeof row.config === "string" ? JSON.parse(row.config) : row.config
|
|
4775
|
+
),
|
|
4776
|
+
createdAt: row.created_at,
|
|
4777
|
+
updatedAt: row.updated_at
|
|
4778
|
+
};
|
|
4779
|
+
}
|
|
4780
|
+
encryptSecrets(config) {
|
|
4781
|
+
return {
|
|
4782
|
+
...config,
|
|
4783
|
+
appSecret: typeof config.appSecret === "string" ? encrypt4(config.appSecret) : config.appSecret,
|
|
4784
|
+
verificationToken: typeof config.verificationToken === "string" ? encrypt4(config.verificationToken) : config.verificationToken,
|
|
4785
|
+
encryptKey: typeof config.encryptKey === "string" ? encrypt4(config.encryptKey) : config.encryptKey
|
|
4786
|
+
};
|
|
4787
|
+
}
|
|
4788
|
+
decryptSecrets(config) {
|
|
4789
|
+
return {
|
|
4790
|
+
appId: String(config.appId || ""),
|
|
4791
|
+
appSecret: typeof config.appSecret === "string" ? decrypt4(config.appSecret) : "",
|
|
4792
|
+
verificationToken: typeof config.verificationToken === "string" ? decrypt4(config.verificationToken) : void 0,
|
|
4793
|
+
encryptKey: typeof config.encryptKey === "string" ? decrypt4(config.encryptKey) : void 0,
|
|
4794
|
+
mappingMode: config.mappingMode === "user" || config.mappingMode === "group" || config.mappingMode === "hybrid" ? config.mappingMode : "hybrid",
|
|
4795
|
+
assistantId: String(config.assistantId || ""),
|
|
4796
|
+
workspaceId: typeof config.workspaceId === "string" ? config.workspaceId : void 0,
|
|
4797
|
+
projectId: typeof config.projectId === "string" ? config.projectId : void 0
|
|
4798
|
+
};
|
|
4799
|
+
}
|
|
4800
|
+
};
|
|
4310
4801
|
export {
|
|
4311
4802
|
AddMessageParams,
|
|
4803
|
+
ChannelIdentityMappingStore,
|
|
4312
4804
|
MigrationManager,
|
|
4313
4805
|
PendingMessage,
|
|
4314
|
-
|
|
4315
|
-
|
|
4806
|
+
Pool15 as Pool,
|
|
4807
|
+
PoolConfig15 as PoolConfig,
|
|
4316
4808
|
PostgreSQLAssistantStore,
|
|
4809
|
+
PostgreSQLChannelInstallationStore,
|
|
4317
4810
|
PostgreSQLDatabaseConfigStore,
|
|
4318
4811
|
PostgreSQLMcpServerConfigStore,
|
|
4319
4812
|
PostgreSQLMetricsServerConfigStore,
|
|
@@ -4335,6 +4828,8 @@ export {
|
|
|
4335
4828
|
changeSkillPrimaryKey,
|
|
4336
4829
|
changeThreadPrimaryKey,
|
|
4337
4830
|
createAssistantsTable,
|
|
4831
|
+
createChannelIdentityMappingTables,
|
|
4832
|
+
createChannelInstallationsTable,
|
|
4338
4833
|
createDatabaseConfigsTable,
|
|
4339
4834
|
createMcpServerConfigsTable,
|
|
4340
4835
|
createMetricsConfigsTable,
|