@axiom-lattice/pg-stores 1.0.21 → 1.0.23

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@axiom-lattice/pg-stores",
3
- "version": "1.0.21",
3
+ "version": "1.0.23",
4
4
  "description": "PG stores implementation for Axiom Lattice framework",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -21,8 +21,8 @@
21
21
  "license": "MIT",
22
22
  "dependencies": {
23
23
  "pg": "^8.16.3",
24
- "@axiom-lattice/protocols": "2.1.18",
25
- "@axiom-lattice/core": "2.1.31"
24
+ "@axiom-lattice/protocols": "2.1.20",
25
+ "@axiom-lattice/core": "2.1.33"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^20.11.24",
package/src/index.ts CHANGED
@@ -18,9 +18,16 @@ export * from "./stores/PostgreSQLTenantStore";
18
18
  export * from "./stores/PostgreSQLUserTenantLinkStore";
19
19
  export * from "./migrations/migration";
20
20
  export * from "./migrations/thread_migrations";
21
+ export * from "./migrations/thread_tenant_migration";
22
+ export * from "./migrations/thread_pk_migration";
21
23
  export * from "./migrations/assistant_migrations";
24
+ export * from "./migrations/assistant_tenant_migration";
25
+ export * from "./migrations/assistant_pk_migration";
22
26
  export * from "./migrations/schedule_migrations";
27
+ export * from "./migrations/schedule_tenant_migration";
23
28
  export * from "./migrations/skill_migrations";
29
+ export * from "./migrations/skill_tenant_migration";
30
+ export * from "./migrations/skill_pk_migration";
24
31
  export * from "./migrations/database_config_migrations";
25
32
  export * from "./migrations/metrics_config_migrations";
26
33
  export * from "./migrations/mcp_server_config_migrations";
@@ -14,12 +14,14 @@ export const createAssistantsTable: Migration = {
14
14
  up: async (client: PoolClient) => {
15
15
  await client.query(`
16
16
  CREATE TABLE IF NOT EXISTS lattice_assistants (
17
- id VARCHAR(255) PRIMARY KEY,
17
+ id VARCHAR(255) NOT NULL,
18
+ tenant_id VARCHAR(255) NOT NULL DEFAULT 'default',
18
19
  name VARCHAR(255) NOT NULL,
19
20
  description TEXT,
20
21
  graph_definition JSONB NOT NULL,
21
22
  created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
22
- updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
23
+ updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
24
+ PRIMARY KEY (tenant_id, id)
23
25
  )
24
26
  `);
25
27
 
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Assistant table primary key migration
3
+ * Changes primary key from (id) to (tenant_id, id) for multi-tenancy
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Change primary key to support multi-tenancy
11
+ */
12
+ export const changeAssistantPrimaryKey: Migration = {
13
+ version: 15,
14
+ name: "change_assistant_primary_key",
15
+ up: async (client: PoolClient) => {
16
+ // Check if table exists and has the old primary key structure
17
+ const tableExists = await client.query(`
18
+ SELECT EXISTS (
19
+ SELECT FROM information_schema.tables
20
+ WHERE table_name = 'lattice_assistants'
21
+ )
22
+ `);
23
+
24
+ if (!tableExists.rows[0].exists) {
25
+ // Table doesn't exist, it will be created by createAssistantsTable migration
26
+ // with the correct primary key (tenant_id, id)
27
+ return;
28
+ }
29
+
30
+ // Check current primary key
31
+ const pkResult = await client.query(`
32
+ SELECT a.attname as column_name
33
+ FROM pg_index i
34
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
35
+ WHERE i.indrelid = 'lattice_assistants'::regclass
36
+ AND i.indisprimary
37
+ `);
38
+
39
+ const pkColumns = pkResult.rows.map(row => row.column_name);
40
+
41
+ // If primary key is already (tenant_id, id), nothing to do
42
+ if (pkColumns.includes('tenant_id') && pkColumns.includes('id')) {
43
+ console.log('Primary key already correct (tenant_id, id)');
44
+ return;
45
+ }
46
+
47
+ // If primary key is just (id), we need to change it
48
+ if (pkColumns.length === 1 && pkColumns[0] === 'id') {
49
+ console.log('Changing primary key from (id) to (tenant_id, id)');
50
+
51
+ // Check if tenant_id column exists
52
+ const tenantIdExists = await client.query(`
53
+ SELECT EXISTS (
54
+ SELECT FROM information_schema.columns
55
+ WHERE table_name = 'lattice_assistants'
56
+ AND column_name = 'tenant_id'
57
+ )
58
+ `);
59
+
60
+ if (!tenantIdExists.rows[0].exists) {
61
+ // Add tenant_id column if it doesn't exist
62
+ await client.query(`
63
+ ALTER TABLE lattice_assistants
64
+ ADD COLUMN tenant_id VARCHAR(255) DEFAULT 'default'
65
+ `);
66
+ }
67
+
68
+ // Update existing records to have tenant_id
69
+ await client.query(`
70
+ UPDATE lattice_assistants
71
+ SET tenant_id = 'default'
72
+ WHERE tenant_id IS NULL
73
+ `);
74
+
75
+ // Make tenant_id NOT NULL
76
+ await client.query(`
77
+ ALTER TABLE lattice_assistants
78
+ ALTER COLUMN tenant_id SET NOT NULL
79
+ `);
80
+
81
+ // Drop the old primary key
82
+ await client.query(`
83
+ ALTER TABLE lattice_assistants
84
+ DROP CONSTRAINT IF EXISTS lattice_assistants_pkey
85
+ `);
86
+
87
+ // Add new composite primary key
88
+ await client.query(`
89
+ ALTER TABLE lattice_assistants
90
+ ADD PRIMARY KEY (tenant_id, id)
91
+ `);
92
+
93
+ console.log('Primary key changed successfully to (tenant_id, id)');
94
+ }
95
+ },
96
+ down: async (client: PoolClient) => {
97
+ // Reverting this is complex and potentially dangerous
98
+ // as it would require ensuring no duplicate IDs across tenants
99
+ console.warn('Down migration for changeAssistantPrimaryKey is not supported');
100
+ },
101
+ };
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Assistant table tenant isolation migration
3
+ * Adds tenant_id column to lattice_assistants table
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Add tenant_id column to assistants table
11
+ */
12
+ export const addAssistantTenantId: Migration = {
13
+ version: 14,
14
+ name: "add_assistant_tenant_id",
15
+ up: async (client: PoolClient) => {
16
+ // tenant_id column is now created in the initial migration
17
+ // This migration is kept for backward compatibility but does nothing
18
+ // Create index for tenant-based queries if not exists
19
+ await client.query(`
20
+ CREATE INDEX IF NOT EXISTS idx_lattice_assistants_tenant_id
21
+ ON lattice_assistants(tenant_id)
22
+ `);
23
+ },
24
+ down: async (client: PoolClient) => {
25
+ await client.query(
26
+ "DROP INDEX IF EXISTS idx_lattice_assistants_tenant_id"
27
+ );
28
+ },
29
+ };
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Schedule table tenant isolation migration
3
+ * Adds tenant_id column to lattice_scheduled_tasks table
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Add tenant_id column to scheduled tasks table
11
+ */
12
+ export const addScheduleTenantId: Migration = {
13
+ version: 18,
14
+ name: "add_schedule_tenant_id",
15
+ up: async (client: PoolClient) => {
16
+ // Add tenant_id column
17
+ await client.query(`
18
+ ALTER TABLE lattice_scheduled_tasks
19
+ ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(255) DEFAULT 'default'
20
+ `);
21
+
22
+ // Update existing records to have tenant_id
23
+ await client.query(`
24
+ UPDATE lattice_scheduled_tasks
25
+ SET tenant_id = 'default'
26
+ WHERE tenant_id IS NULL
27
+ `);
28
+
29
+ // Make tenant_id NOT NULL after setting defaults
30
+ await client.query(`
31
+ ALTER TABLE lattice_scheduled_tasks
32
+ ALTER COLUMN tenant_id SET NOT NULL
33
+ `);
34
+
35
+ // Drop the default constraint
36
+ await client.query(`
37
+ ALTER TABLE lattice_scheduled_tasks
38
+ ALTER COLUMN tenant_id DROP DEFAULT
39
+ `);
40
+
41
+ // Create index for tenant-based queries
42
+ await client.query(`
43
+ CREATE INDEX IF NOT EXISTS idx_scheduled_tasks_tenant_id
44
+ ON lattice_scheduled_tasks(tenant_id)
45
+ `);
46
+
47
+ // Create composite index for common tenant+assistant queries
48
+ await client.query(`
49
+ CREATE INDEX IF NOT EXISTS idx_scheduled_tasks_tenant_assistant
50
+ ON lattice_scheduled_tasks(tenant_id, assistant_id)
51
+ WHERE assistant_id IS NOT NULL
52
+ `);
53
+
54
+ // Create composite index for common tenant+thread queries
55
+ await client.query(`
56
+ CREATE INDEX IF NOT EXISTS idx_scheduled_tasks_tenant_thread
57
+ ON lattice_scheduled_tasks(tenant_id, thread_id)
58
+ WHERE thread_id IS NOT NULL
59
+ `);
60
+ },
61
+ down: async (client: PoolClient) => {
62
+ await client.query(
63
+ "DROP INDEX IF EXISTS idx_scheduled_tasks_tenant_thread"
64
+ );
65
+ await client.query(
66
+ "DROP INDEX IF EXISTS idx_scheduled_tasks_tenant_assistant"
67
+ );
68
+ await client.query(
69
+ "DROP INDEX IF EXISTS idx_scheduled_tasks_tenant_id"
70
+ );
71
+ await client.query(
72
+ "ALTER TABLE lattice_scheduled_tasks DROP COLUMN IF EXISTS tenant_id"
73
+ );
74
+ },
75
+ };
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Skill table primary key migration
3
+ * Changes primary key from (id) to (tenant_id, id) for multi-tenancy
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Change skill table primary key to support multi-tenancy
11
+ */
12
+ export const changeSkillPrimaryKey: Migration = {
13
+ version: 17,
14
+ name: "change_skill_primary_key",
15
+ up: async (client: PoolClient) => {
16
+ // Check if table exists
17
+ const tableExists = await client.query(`
18
+ SELECT EXISTS (
19
+ SELECT FROM information_schema.tables
20
+ WHERE table_name = 'lattice_skills'
21
+ )
22
+ `);
23
+
24
+ if (!tableExists.rows[0].exists) {
25
+ return;
26
+ }
27
+
28
+ // Check current primary key
29
+ const pkResult = await client.query(`
30
+ SELECT a.attname as column_name
31
+ FROM pg_index i
32
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
33
+ WHERE i.indrelid = 'lattice_skills'::regclass
34
+ AND i.indisprimary
35
+ `);
36
+
37
+ const pkColumns = pkResult.rows.map(row => row.column_name);
38
+
39
+ // If primary key is already (tenant_id, id), nothing to do
40
+ if (pkColumns.includes('tenant_id') && pkColumns.includes('id')) {
41
+ console.log('Skill table primary key already correct (tenant_id, id)');
42
+ return;
43
+ }
44
+
45
+ // If primary key is just (id), we need to change it
46
+ if (pkColumns.length === 1 && pkColumns[0] === 'id') {
47
+ console.log('Changing skill table primary key from (id) to (tenant_id, id)');
48
+
49
+ // Check if tenant_id column exists
50
+ const tenantIdExists = await client.query(`
51
+ SELECT EXISTS (
52
+ SELECT FROM information_schema.columns
53
+ WHERE table_name = 'lattice_skills'
54
+ AND column_name = 'tenant_id'
55
+ )
56
+ `);
57
+
58
+ if (!tenantIdExists.rows[0].exists) {
59
+ // Add tenant_id column if it doesn't exist
60
+ await client.query(`
61
+ ALTER TABLE lattice_skills
62
+ ADD COLUMN tenant_id VARCHAR(255) DEFAULT 'default'
63
+ `);
64
+ }
65
+
66
+ // Update existing records to have tenant_id
67
+ await client.query(`
68
+ UPDATE lattice_skills
69
+ SET tenant_id = 'default'
70
+ WHERE tenant_id IS NULL
71
+ `);
72
+
73
+ // Make tenant_id NOT NULL
74
+ await client.query(`
75
+ ALTER TABLE lattice_skills
76
+ ALTER COLUMN tenant_id SET NOT NULL
77
+ `);
78
+
79
+ // Drop the old primary key
80
+ await client.query(`
81
+ ALTER TABLE lattice_skills
82
+ DROP CONSTRAINT IF EXISTS lattice_skills_pkey
83
+ `);
84
+
85
+ // Add new composite primary key
86
+ await client.query(`
87
+ ALTER TABLE lattice_skills
88
+ ADD PRIMARY KEY (tenant_id, id)
89
+ `);
90
+
91
+ console.log('Skill table primary key changed successfully to (tenant_id, id)');
92
+ }
93
+ },
94
+ down: async (client: PoolClient) => {
95
+ console.warn('Down migration for changeSkillPrimaryKey is not supported');
96
+ },
97
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Skill table tenant isolation migration
3
+ * Adds tenant_id column to lattice_skills table
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Add tenant_id column to skills table
11
+ */
12
+ export const addSkillTenantId: Migration = {
13
+ version: 16,
14
+ name: "add_skill_tenant_id",
15
+ up: async (client: PoolClient) => {
16
+ // Add tenant_id column
17
+ await client.query(`
18
+ ALTER TABLE lattice_skills
19
+ ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(255) DEFAULT 'default'
20
+ `);
21
+
22
+ // Update existing records to have tenant_id
23
+ await client.query(`
24
+ UPDATE lattice_skills
25
+ SET tenant_id = 'default'
26
+ WHERE tenant_id IS NULL
27
+ `);
28
+
29
+ // Make tenant_id NOT NULL after setting defaults
30
+ await client.query(`
31
+ ALTER TABLE lattice_skills
32
+ ALTER COLUMN tenant_id SET NOT NULL
33
+ `);
34
+
35
+ // Drop the default constraint
36
+ await client.query(`
37
+ ALTER TABLE lattice_skills
38
+ ALTER COLUMN tenant_id DROP DEFAULT
39
+ `);
40
+
41
+ // Create index for tenant-based queries
42
+ await client.query(`
43
+ CREATE INDEX IF NOT EXISTS idx_lattice_skills_tenant_id
44
+ ON lattice_skills(tenant_id)
45
+ `);
46
+ },
47
+ down: async (client: PoolClient) => {
48
+ await client.query(
49
+ "DROP INDEX IF EXISTS idx_lattice_skills_tenant_id"
50
+ );
51
+ await client.query(
52
+ "ALTER TABLE lattice_skills DROP COLUMN IF EXISTS tenant_id"
53
+ );
54
+ },
55
+ };
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Thread table primary key migration
3
+ * Changes primary key from (id, assistant_id) to (id, tenant_id) for multi-tenancy
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Change primary key to support multi-tenancy
11
+ */
12
+ export const changeThreadPrimaryKey: Migration = {
13
+ version: 19,
14
+ name: "change_thread_primary_key",
15
+ up: async (client: PoolClient) => {
16
+ // Check if table exists
17
+ const tableExists = await client.query(`
18
+ SELECT EXISTS (
19
+ SELECT FROM information_schema.tables
20
+ WHERE table_name = 'lattice_threads'
21
+ )
22
+ `);
23
+
24
+ if (!tableExists.rows[0].exists) {
25
+ // Table doesn't exist, it will be created with correct schema
26
+ return;
27
+ }
28
+
29
+ // Check current primary key
30
+ const pkResult = await client.query(`
31
+ SELECT a.attname as column_name
32
+ FROM pg_index i
33
+ JOIN pg_attribute a ON a.attrelid = i.indrelid AND a.attnum = ANY(i.indkey)
34
+ WHERE i.indrelid = 'lattice_threads'::regclass
35
+ AND i.indisprimary
36
+ `);
37
+
38
+ const pkColumns = pkResult.rows.map(row => row.column_name);
39
+
40
+ // If primary key is already (id, tenant_id), nothing to do
41
+ if (pkColumns.includes('tenant_id') && pkColumns.includes('id') && pkColumns.length === 2) {
42
+ console.log('Primary key already correct (id, tenant_id)');
43
+ return;
44
+ }
45
+
46
+ // If primary key is (id, assistant_id), we need to change it
47
+ if (pkColumns.includes('id') && pkColumns.includes('assistant_id')) {
48
+ console.log('Changing primary key from (id, assistant_id) to (id, tenant_id)');
49
+
50
+ // Check if tenant_id column exists
51
+ const tenantIdExists = await client.query(`
52
+ SELECT EXISTS (
53
+ SELECT FROM information_schema.columns
54
+ WHERE table_name = 'lattice_threads'
55
+ AND column_name = 'tenant_id'
56
+ )
57
+ `);
58
+
59
+ if (!tenantIdExists.rows[0].exists) {
60
+ // Add tenant_id column if it doesn't exist
61
+ await client.query(`
62
+ ALTER TABLE lattice_threads
63
+ ADD COLUMN tenant_id VARCHAR(255) DEFAULT 'default'
64
+ `);
65
+ }
66
+
67
+ // Update existing records to have tenant_id
68
+ await client.query(`
69
+ UPDATE lattice_threads
70
+ SET tenant_id = 'default'
71
+ WHERE tenant_id IS NULL
72
+ `);
73
+
74
+ // Make tenant_id NOT NULL
75
+ await client.query(`
76
+ ALTER TABLE lattice_threads
77
+ ALTER COLUMN tenant_id SET NOT NULL
78
+ `);
79
+
80
+ // Drop the old primary key
81
+ await client.query(`
82
+ ALTER TABLE lattice_threads
83
+ DROP CONSTRAINT IF EXISTS lattice_threads_pkey
84
+ `);
85
+
86
+ // Add new composite primary key
87
+ await client.query(`
88
+ ALTER TABLE lattice_threads
89
+ ADD PRIMARY KEY (id, tenant_id)
90
+ `);
91
+
92
+ console.log('Primary key changed successfully to (id, tenant_id)');
93
+ }
94
+ },
95
+ down: async (client: PoolClient) => {
96
+ // Reverting this is complex and potentially dangerous
97
+ console.warn('Down migration for changeThreadPrimaryKey is not supported');
98
+ },
99
+ };
@@ -0,0 +1,55 @@
1
+ /**
2
+ * Thread table tenant isolation migration
3
+ * Adds tenant_id column to lattice_threads table
4
+ */
5
+
6
+ import { PoolClient } from "pg";
7
+ import { Migration } from "./migration";
8
+
9
+ /**
10
+ * Migration: Add tenant_id column to threads table
11
+ */
12
+ export const addThreadTenantId: Migration = {
13
+ version: 15,
14
+ name: "add_thread_tenant_id",
15
+ up: async (client: PoolClient) => {
16
+ // Add tenant_id column
17
+ await client.query(`
18
+ ALTER TABLE lattice_threads
19
+ ADD COLUMN IF NOT EXISTS tenant_id VARCHAR(255) DEFAULT 'default'
20
+ `);
21
+
22
+ // Update existing records to have tenant_id
23
+ await client.query(`
24
+ UPDATE lattice_threads
25
+ SET tenant_id = 'default'
26
+ WHERE tenant_id IS NULL
27
+ `);
28
+
29
+ // Make tenant_id NOT NULL after setting defaults
30
+ await client.query(`
31
+ ALTER TABLE lattice_threads
32
+ ALTER COLUMN tenant_id SET NOT NULL
33
+ `);
34
+
35
+ // Drop the default constraint
36
+ await client.query(`
37
+ ALTER TABLE lattice_threads
38
+ ALTER COLUMN tenant_id DROP DEFAULT
39
+ `);
40
+
41
+ // Create index for tenant-based queries
42
+ await client.query(`
43
+ CREATE INDEX IF NOT EXISTS idx_lattice_threads_tenant_id
44
+ ON lattice_threads(tenant_id)
45
+ `);
46
+ },
47
+ down: async (client: PoolClient) => {
48
+ await client.query(
49
+ "DROP INDEX IF EXISTS idx_lattice_threads_tenant_id"
50
+ );
51
+ await client.query(
52
+ "ALTER TABLE lattice_threads DROP COLUMN IF EXISTS tenant_id"
53
+ );
54
+ },
55
+ };