incognitolm commited on
Commit
3c52eb9
·
1 Parent(s): cb54ec6
server/postgres.js CHANGED
@@ -9,10 +9,11 @@ import {
9
  unpackEncryptedBuffer,
10
  } from './cryptoUtils.js';
11
  import { isPostgresStorageMode, POSTGRES_STORAGE_DIR, STORAGE_MODE } from './dataPaths.js';
12
- import { POSTGRES_SCHEMA_SQL } from './postgresSchema.js';
13
 
14
  let poolInstance = null;
15
  let initPromise = null;
 
16
 
17
  function resolveSslConfig() {
18
  const raw = String(process.env.PGSSL || process.env.PGSSLMODE || '').trim().toLowerCase();
@@ -20,6 +21,30 @@ function resolveSslConfig() {
20
  return { rejectUnauthorized: false };
21
  }
22
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
23
  export function buildPoolConfig() {
24
  const connectionString = process.env.DATABASE_URL || process.env.POSTGRES_URL || '';
25
  const ssl = resolveSslConfig();
@@ -56,8 +81,21 @@ export async function createRawPostgresPool() {
56
  return attachPoolErrorHandler(pool);
57
  }
58
 
 
 
 
 
 
 
 
59
  export async function applyPostgresSchema(pool) {
60
- await pool.query(POSTGRES_SCHEMA_SQL);
 
 
 
 
 
 
61
  }
62
 
63
  async function createPool() {
@@ -99,6 +137,7 @@ export async function withPgClient(fn) {
99
  const pool = await getPostgresPool();
100
  const client = await pool.connect();
101
  try {
 
102
  return await fn(client);
103
  } finally {
104
  client.release();
 
9
  unpackEncryptedBuffer,
10
  } from './cryptoUtils.js';
11
  import { isPostgresStorageMode, POSTGRES_STORAGE_DIR, STORAGE_MODE } from './dataPaths.js';
12
+ import { APP_SCHEMA_NAME, POSTGRES_SCHEMA_SQL } from './postgresSchema.js';
13
 
14
  let poolInstance = null;
15
  let initPromise = null;
16
+ const configuredClients = new WeakSet();
17
 
18
  function resolveSslConfig() {
19
  const raw = String(process.env.PGSSL || process.env.PGSSLMODE || '').trim().toLowerCase();
 
21
  return { rejectUnauthorized: false };
22
  }
23
 
24
+ function getValidatedSchemaName() {
25
+ const schemaName = String(APP_SCHEMA_NAME || '').trim();
26
+ if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(schemaName)) {
27
+ throw new Error(`Invalid POSTGRES_APP_SCHEMA value: ${schemaName}`);
28
+ }
29
+ return schemaName;
30
+ }
31
+
32
+ export function getPostgresSchemaName() {
33
+ return getValidatedSchemaName();
34
+ }
35
+
36
+ export function getCreateSchemaSql() {
37
+ return `CREATE SCHEMA IF NOT EXISTS "${getValidatedSchemaName()}"`;
38
+ }
39
+
40
+ export function getDropSchemaSql() {
41
+ return `DROP SCHEMA IF EXISTS "${getValidatedSchemaName()}" CASCADE`;
42
+ }
43
+
44
+ export function getSetSearchPathSql() {
45
+ return `SET search_path TO "${getValidatedSchemaName()}", public`;
46
+ }
47
+
48
  export function buildPoolConfig() {
49
  const connectionString = process.env.DATABASE_URL || process.env.POSTGRES_URL || '';
50
  const ssl = resolveSslConfig();
 
81
  return attachPoolErrorHandler(pool);
82
  }
83
 
84
+ export async function preparePostgresClient(client) {
85
+ if (configuredClients.has(client)) return;
86
+ await client.query(getCreateSchemaSql());
87
+ await client.query(getSetSearchPathSql());
88
+ configuredClients.add(client);
89
+ }
90
+
91
  export async function applyPostgresSchema(pool) {
92
+ const client = await pool.connect();
93
+ try {
94
+ await preparePostgresClient(client);
95
+ await client.query(POSTGRES_SCHEMA_SQL);
96
+ } finally {
97
+ client.release();
98
+ }
99
  }
100
 
101
  async function createPool() {
 
137
  const pool = await getPostgresPool();
138
  const client = await pool.connect();
139
  try {
140
+ await preparePostgresClient(client);
141
  return await fn(client);
142
  } finally {
143
  client.release();
server/postgresMigration.js CHANGED
@@ -12,10 +12,14 @@ import {
12
  applyPostgresSchema,
13
  createRawPostgresPool,
14
  encryptJsonPayload,
 
 
 
 
15
  makeLookupToken,
16
  makeOwnerLookup,
17
  } from './postgres.js';
18
- import { APP_MANAGED_TABLES, POSTGRES_SCHEMA_SQL } from './postgresSchema.js';
19
  import { SUPABASE_URL } from './config.js';
20
 
21
  const TEMP_TTL_MS = 24 * 60 * 60 * 1000;
@@ -136,31 +140,16 @@ async function fetchAllSupabaseRows(client, tableName) {
136
  return rows;
137
  }
138
 
139
- async function truncateTargetTables(pool) {
140
- await pool.query(`
141
- TRUNCATE TABLE
142
- media_blobs,
143
- media_entries,
144
- deleted_chats,
145
- memories,
146
- system_prompts,
147
- feedback_tickets,
148
- guest_request_counters,
149
- web_search_usage,
150
- user_settings,
151
- user_profiles,
152
- device_sessions,
153
- session_shares,
154
- chat_sessions,
155
- guest_state,
156
- app_versions
157
- RESTART IDENTITY
158
- CASCADE
159
- `);
160
- }
161
-
162
- async function dropTargetTables(pool) {
163
- await pool.query(`DROP TABLE IF EXISTS ${APP_MANAGED_TABLES.join(', ')} CASCADE`);
164
  }
165
 
166
  async function migrateVersions(pool, report) {
@@ -555,14 +544,14 @@ export async function migrateLegacyDataToPostgres({ skipIfFolderExists = true }
555
  const report = {
556
  startedAt: nowIso(),
557
  targetFolder: POSTGRES_STORAGE_DIR,
 
558
  migrated: {},
559
  pending: [],
560
  };
561
 
562
  try {
563
- await dropTargetTables(pool);
564
  await applyPostgresSchema(pool);
565
- await truncateTargetTables(pool);
566
  await migrateVersions(pool, report);
567
  await migrateTempSessions(pool, report);
568
  await migrateMemories(pool, report);
 
12
  applyPostgresSchema,
13
  createRawPostgresPool,
14
  encryptJsonPayload,
15
+ getCreateSchemaSql,
16
+ getDropSchemaSql,
17
+ getPostgresSchemaName,
18
+ getSetSearchPathSql,
19
  makeLookupToken,
20
  makeOwnerLookup,
21
  } from './postgres.js';
22
+ import { POSTGRES_SCHEMA_SQL } from './postgresSchema.js';
23
  import { SUPABASE_URL } from './config.js';
24
 
25
  const TEMP_TTL_MS = 24 * 60 * 60 * 1000;
 
140
  return rows;
141
  }
142
 
143
+ async function resetBootstrapSchema(pool) {
144
+ const client = await pool.connect();
145
+ try {
146
+ await client.query('SET statement_timeout TO 0');
147
+ await client.query(getDropSchemaSql());
148
+ await client.query(getCreateSchemaSql());
149
+ await client.query(getSetSearchPathSql());
150
+ } finally {
151
+ client.release();
152
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
153
  }
154
 
155
  async function migrateVersions(pool, report) {
 
544
  const report = {
545
  startedAt: nowIso(),
546
  targetFolder: POSTGRES_STORAGE_DIR,
547
+ targetSchema: getPostgresSchemaName(),
548
  migrated: {},
549
  pending: [],
550
  };
551
 
552
  try {
553
+ await resetBootstrapSchema(pool);
554
  await applyPostgresSchema(pool);
 
555
  await migrateVersions(pool, report);
556
  await migrateTempSessions(pool, report);
557
  await migrateMemories(pool, report);
server/postgresSchema.js CHANGED
@@ -1,20 +1,4 @@
1
- export const APP_MANAGED_TABLES = [
2
- 'media_blobs',
3
- 'media_entries',
4
- 'deleted_chats',
5
- 'memories',
6
- 'system_prompts',
7
- 'feedback_tickets',
8
- 'guest_request_counters',
9
- 'web_search_usage',
10
- 'user_settings',
11
- 'user_profiles',
12
- 'device_sessions',
13
- 'session_shares',
14
- 'chat_sessions',
15
- 'guest_state',
16
- 'app_versions',
17
- ];
18
 
19
  export const POSTGRES_SCHEMA_SQL = `
20
  CREATE TABLE IF NOT EXISTS app_versions (
 
1
+ export const APP_SCHEMA_NAME = process.env.POSTGRES_APP_SCHEMA || 'inferenceport_backend';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2
 
3
  export const POSTGRES_SCHEMA_SQL = `
4
  CREATE TABLE IF NOT EXISTS app_versions (