@pgpmjs/core 4.7.1 → 4.8.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.
@@ -2,7 +2,7 @@ import { Parser } from 'csv-to-pg';
2
2
  import { getPgPool } from 'pg-cache';
3
3
  const config = {
4
4
  database: {
5
- schema: 'collections_public',
5
+ schema: 'metaschema_public',
6
6
  table: 'database',
7
7
  fields: {
8
8
  id: 'uuid',
@@ -12,7 +12,7 @@ const config = {
12
12
  }
13
13
  },
14
14
  database_extension: {
15
- schema: 'collections_public',
15
+ schema: 'metaschema_public',
16
16
  table: 'database_extension',
17
17
  fields: {
18
18
  name: 'text',
@@ -20,7 +20,7 @@ const config = {
20
20
  }
21
21
  },
22
22
  schema: {
23
- schema: 'collections_public',
23
+ schema: 'metaschema_public',
24
24
  table: 'schema',
25
25
  fields: {
26
26
  id: 'uuid',
@@ -31,7 +31,7 @@ const config = {
31
31
  }
32
32
  },
33
33
  table: {
34
- schema: 'collections_public',
34
+ schema: 'metaschema_public',
35
35
  table: 'table',
36
36
  fields: {
37
37
  id: 'uuid',
@@ -42,7 +42,7 @@ const config = {
42
42
  }
43
43
  },
44
44
  field: {
45
- schema: 'collections_public',
45
+ schema: 'metaschema_public',
46
46
  table: 'field',
47
47
  fields: {
48
48
  id: 'uuid',
@@ -54,7 +54,7 @@ const config = {
54
54
  }
55
55
  },
56
56
  domains: {
57
- schema: 'meta_public',
57
+ schema: 'services_public',
58
58
  table: 'domains',
59
59
  fields: {
60
60
  id: 'uuid',
@@ -66,7 +66,7 @@ const config = {
66
66
  }
67
67
  },
68
68
  sites: {
69
- schema: 'meta_public',
69
+ schema: 'services_public',
70
70
  table: 'sites',
71
71
  fields: {
72
72
  id: 'uuid',
@@ -81,7 +81,7 @@ const config = {
81
81
  }
82
82
  },
83
83
  apis: {
84
- schema: 'meta_public',
84
+ schema: 'services_public',
85
85
  table: 'apis',
86
86
  fields: {
87
87
  id: 'uuid',
@@ -94,7 +94,7 @@ const config = {
94
94
  }
95
95
  },
96
96
  apps: {
97
- schema: 'meta_public',
97
+ schema: 'services_public',
98
98
  table: 'apps',
99
99
  fields: {
100
100
  id: 'uuid',
@@ -109,7 +109,7 @@ const config = {
109
109
  }
110
110
  },
111
111
  site_modules: {
112
- schema: 'meta_public',
112
+ schema: 'services_public',
113
113
  table: 'site_modules',
114
114
  fields: {
115
115
  id: 'uuid',
@@ -120,7 +120,7 @@ const config = {
120
120
  }
121
121
  },
122
122
  site_themes: {
123
- schema: 'meta_public',
123
+ schema: 'services_public',
124
124
  table: 'site_themes',
125
125
  fields: {
126
126
  id: 'uuid',
@@ -130,7 +130,7 @@ const config = {
130
130
  }
131
131
  },
132
132
  api_modules: {
133
- schema: 'meta_public',
133
+ schema: 'services_public',
134
134
  table: 'api_modules',
135
135
  fields: {
136
136
  id: 'uuid',
@@ -141,7 +141,7 @@ const config = {
141
141
  }
142
142
  },
143
143
  api_extensions: {
144
- schema: 'meta_public',
144
+ schema: 'services_public',
145
145
  table: 'api_extensions',
146
146
  fields: {
147
147
  id: 'uuid',
@@ -151,7 +151,7 @@ const config = {
151
151
  }
152
152
  },
153
153
  api_schemata: {
154
- schema: 'meta_public',
154
+ schema: 'services_public',
155
155
  table: 'api_schemata',
156
156
  fields: {
157
157
  id: 'uuid',
@@ -161,7 +161,7 @@ const config = {
161
161
  }
162
162
  },
163
163
  rls_module: {
164
- schema: 'meta_public',
164
+ schema: 'metaschema_modules_public',
165
165
  table: 'rls_module',
166
166
  fields: {
167
167
  id: 'uuid',
@@ -178,7 +178,7 @@ const config = {
178
178
  }
179
179
  },
180
180
  user_auth_module: {
181
- schema: 'meta_public',
181
+ schema: 'metaschema_modules_public',
182
182
  table: 'user_auth_module',
183
183
  fields: {
184
184
  id: 'uuid',
@@ -224,21 +224,21 @@ export const exportMeta = async ({ opts, dbname, database_id }) => {
224
224
  }
225
225
  }
226
226
  };
227
- await queryAndParse('database', `SELECT * FROM collections_public.database WHERE id = $1`);
228
- await queryAndParse('schema', `SELECT * FROM collections_public.schema WHERE database_id = $1`);
229
- await queryAndParse('table', `SELECT * FROM collections_public.table WHERE database_id = $1`);
230
- await queryAndParse('field', `SELECT * FROM collections_public.field WHERE database_id = $1`);
231
- await queryAndParse('domains', `SELECT * FROM meta_public.domains WHERE database_id = $1`);
232
- await queryAndParse('apis', `SELECT * FROM meta_public.apis WHERE database_id = $1`);
233
- await queryAndParse('sites', `SELECT * FROM meta_public.sites WHERE database_id = $1`);
234
- await queryAndParse('api_modules', `SELECT * FROM meta_public.api_modules WHERE database_id = $1`);
235
- await queryAndParse('site_modules', `SELECT * FROM meta_public.site_modules WHERE database_id = $1`);
236
- await queryAndParse('site_themes', `SELECT * FROM meta_public.site_themes WHERE database_id = $1`);
237
- await queryAndParse('apps', `SELECT * FROM meta_public.apps WHERE database_id = $1`);
238
- await queryAndParse('database_extension', `SELECT * FROM collections_public.database_extension WHERE database_id = $1`);
239
- await queryAndParse('api_extensions', `SELECT * FROM meta_public.api_extensions WHERE database_id = $1`);
240
- await queryAndParse('api_schemata', `SELECT * FROM meta_public.api_schemata WHERE database_id = $1`);
241
- await queryAndParse('rls_module', `SELECT * FROM meta_public.rls_module WHERE database_id = $1`);
242
- await queryAndParse('user_auth_module', `SELECT * FROM meta_public.user_auth_module WHERE database_id = $1`);
227
+ await queryAndParse('database', `SELECT * FROM metaschema_public.database WHERE id = $1`);
228
+ await queryAndParse('schema', `SELECT * FROM metaschema_public.schema WHERE database_id = $1`);
229
+ await queryAndParse('table', `SELECT * FROM metaschema_public.table WHERE database_id = $1`);
230
+ await queryAndParse('field', `SELECT * FROM metaschema_public.field WHERE database_id = $1`);
231
+ await queryAndParse('domains', `SELECT * FROM services_public.domains WHERE database_id = $1`);
232
+ await queryAndParse('apis', `SELECT * FROM services_public.apis WHERE database_id = $1`);
233
+ await queryAndParse('sites', `SELECT * FROM services_public.sites WHERE database_id = $1`);
234
+ await queryAndParse('api_modules', `SELECT * FROM services_public.api_modules WHERE database_id = $1`);
235
+ await queryAndParse('site_modules', `SELECT * FROM services_public.site_modules WHERE database_id = $1`);
236
+ await queryAndParse('site_themes', `SELECT * FROM services_public.site_themes WHERE database_id = $1`);
237
+ await queryAndParse('apps', `SELECT * FROM services_public.apps WHERE database_id = $1`);
238
+ await queryAndParse('database_extension', `SELECT * FROM metaschema_public.database_extension WHERE database_id = $1`);
239
+ await queryAndParse('api_extensions', `SELECT * FROM services_public.api_extensions WHERE database_id = $1`);
240
+ await queryAndParse('api_schemata', `SELECT * FROM services_public.api_schemata WHERE database_id = $1`);
241
+ await queryAndParse('rls_module', `SELECT * FROM metaschema_modules_public.rls_module WHERE database_id = $1`);
242
+ await queryAndParse('user_auth_module', `SELECT * FROM metaschema_modules_public.user_auth_module WHERE database_id = $1`);
243
243
  return Object.entries(sql).reduce((m, [_, v]) => m + '\n\n' + v, '');
244
244
  };
@@ -92,7 +92,7 @@ const installMissingModules = async (moduleDir, missingModules) => {
92
92
  await moduleProject.installModules(...missingNames);
93
93
  console.log('Modules installed successfully.');
94
94
  };
95
- const exportMigrationsToDisk = async ({ project, options, database, databaseId, databaseName, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir }) => {
95
+ const exportMigrationsToDisk = async ({ project, options, database, databaseId, databaseName, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir, skipSchemaRenaming = false }) => {
96
96
  outdir = outdir + '/';
97
97
  // Use serviceOutdir for service module, defaulting to outdir if not provided
98
98
  const svcOutdir = (serviceOutdir || outdir.slice(0, -1)) + '/';
@@ -100,8 +100,8 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
100
100
  ...options.pg,
101
101
  database
102
102
  });
103
- const db = await pgPool.query(`select * from collections_public.database where id=$1`, [databaseId]);
104
- const schemas = await pgPool.query(`select * from collections_public.schema where database_id=$1`, [databaseId]);
103
+ const db = await pgPool.query(`select * from metaschema_public.database where id=$1`, [databaseId]);
104
+ const schemas = await pgPool.query(`select * from metaschema_public.schema where database_id=$1`, [databaseId]);
105
105
  if (!db?.rows?.length) {
106
106
  console.log('NO DATABASES.');
107
107
  return;
@@ -111,11 +111,20 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
111
111
  return;
112
112
  }
113
113
  const name = extensionName || db.rows[0].name;
114
+ // When skipSchemaRenaming is true, pass empty schemas array to avoid renaming
115
+ // This is useful for self-referential introspection where you want to apply
116
+ // policies to real infrastructure schemas (metaschema_public, services_public, etc.)
117
+ const schemasForReplacement = skipSchemaRenaming
118
+ ? []
119
+ : schemas.rows.filter((schema) => schema_names.includes(schema.schema_name));
114
120
  const { replace, replacer } = makeReplacer({
115
- schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
121
+ schemas: schemasForReplacement,
116
122
  name
117
123
  });
118
- const results = await pgPool.query(`select * from db_migrate.sql_actions order by id`);
124
+ // Filter sql_actions by database_id to avoid cross-database pollution
125
+ // Previously this query had no WHERE clause, which could export actions
126
+ // from unrelated databases in a persistent database environment
127
+ const results = await pgPool.query(`select * from db_migrate.sql_actions where database_id = $1 order by id`, [databaseId]);
119
128
  const opts = {
120
129
  name,
121
130
  replacer,
@@ -171,8 +180,12 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
171
180
  if (svcMissingResult.shouldInstall) {
172
181
  await installMissingModules(svcModuleDir, svcMissingResult.missingModules);
173
182
  }
183
+ // Use same skipSchemaRenaming logic for meta replacer
184
+ const metaSchemasForReplacement = skipSchemaRenaming
185
+ ? []
186
+ : schemas.rows.filter((schema) => schema_names.includes(schema.schema_name));
174
187
  const metaReplacer = makeReplacer({
175
- schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
188
+ schemas: metaSchemasForReplacement,
176
189
  name: metaExtensionName
177
190
  });
178
191
  const metaPackage = [
@@ -180,7 +193,7 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
180
193
  deps: [],
181
194
  deploy: 'migrate/meta',
182
195
  content: `SET session_replication_role TO replica;
183
- -- using replica in case we are deploying triggers to collections_public
196
+ -- using replica in case we are deploying triggers to metaschema_public
184
197
 
185
198
  -- unaccent, postgis affected and require grants
186
199
  GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public to public;
@@ -199,12 +212,12 @@ ${meta}
199
212
 
200
213
  -- TODO: Research needed - These UPDATE statements may be a security leak.
201
214
  -- They appear to rebind exported metadata to the target database after import,
202
- -- but exposing dbname in meta_public tables could leak internal database names.
215
+ -- but exposing dbname in services_public tables could leak internal database names.
203
216
  -- Consider removing entirely or gating behind an explicit flag.
204
- -- UPDATE meta_public.apis
217
+ -- UPDATE services_public.apis
205
218
  -- SET dbname = current_database() WHERE TRUE;
206
219
 
207
- -- UPDATE meta_public.sites
220
+ -- UPDATE services_public.sites
208
221
  -- SET dbname = current_database() WHERE TRUE;
209
222
 
210
223
  SET session_replication_role TO DEFAULT;
@@ -219,7 +232,7 @@ SET session_replication_role TO DEFAULT;
219
232
  }
220
233
  pgPool.end();
221
234
  };
222
- export const exportMigrations = async ({ project, options, dbInfo, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir }) => {
235
+ export const exportMigrations = async ({ project, options, dbInfo, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir, skipSchemaRenaming }) => {
223
236
  for (let v = 0; v < dbInfo.database_ids.length; v++) {
224
237
  const databaseId = dbInfo.database_ids[v];
225
238
  await exportMigrationsToDisk({
@@ -238,7 +251,8 @@ export const exportMigrations = async ({ project, options, dbInfo, author, outdi
238
251
  prompter,
239
252
  repoName,
240
253
  username,
241
- serviceOutdir
254
+ serviceOutdir,
255
+ skipSchemaRenaming
242
256
  });
243
257
  }
244
258
  };
@@ -8,8 +8,8 @@ import { errors } from '@pgpmjs/types';
8
8
  export const PGPM_MODULE_MAP = {
9
9
  'pgpm-base32': '@pgpm/base32',
10
10
  'pgpm-database-jobs': '@pgpm/database-jobs',
11
- 'db-meta-modules': '@pgpm/db-meta-modules',
12
- 'db-meta-schema': '@pgpm/db-meta-schema',
11
+ 'metaschema-modules': '@pgpm/metaschema-modules',
12
+ 'metaschema-schema': '@pgpm/metaschema-schema',
13
13
  'pgpm-inflection': '@pgpm/inflection',
14
14
  'pgpm-jwt-claims': '@pgpm/jwt-claims',
15
15
  'pgpm-stamps': '@pgpm/stamps',
@@ -5,7 +5,7 @@ const csv_to_pg_1 = require("csv-to-pg");
5
5
  const pg_cache_1 = require("pg-cache");
6
6
  const config = {
7
7
  database: {
8
- schema: 'collections_public',
8
+ schema: 'metaschema_public',
9
9
  table: 'database',
10
10
  fields: {
11
11
  id: 'uuid',
@@ -15,7 +15,7 @@ const config = {
15
15
  }
16
16
  },
17
17
  database_extension: {
18
- schema: 'collections_public',
18
+ schema: 'metaschema_public',
19
19
  table: 'database_extension',
20
20
  fields: {
21
21
  name: 'text',
@@ -23,7 +23,7 @@ const config = {
23
23
  }
24
24
  },
25
25
  schema: {
26
- schema: 'collections_public',
26
+ schema: 'metaschema_public',
27
27
  table: 'schema',
28
28
  fields: {
29
29
  id: 'uuid',
@@ -34,7 +34,7 @@ const config = {
34
34
  }
35
35
  },
36
36
  table: {
37
- schema: 'collections_public',
37
+ schema: 'metaschema_public',
38
38
  table: 'table',
39
39
  fields: {
40
40
  id: 'uuid',
@@ -45,7 +45,7 @@ const config = {
45
45
  }
46
46
  },
47
47
  field: {
48
- schema: 'collections_public',
48
+ schema: 'metaschema_public',
49
49
  table: 'field',
50
50
  fields: {
51
51
  id: 'uuid',
@@ -57,7 +57,7 @@ const config = {
57
57
  }
58
58
  },
59
59
  domains: {
60
- schema: 'meta_public',
60
+ schema: 'services_public',
61
61
  table: 'domains',
62
62
  fields: {
63
63
  id: 'uuid',
@@ -69,7 +69,7 @@ const config = {
69
69
  }
70
70
  },
71
71
  sites: {
72
- schema: 'meta_public',
72
+ schema: 'services_public',
73
73
  table: 'sites',
74
74
  fields: {
75
75
  id: 'uuid',
@@ -84,7 +84,7 @@ const config = {
84
84
  }
85
85
  },
86
86
  apis: {
87
- schema: 'meta_public',
87
+ schema: 'services_public',
88
88
  table: 'apis',
89
89
  fields: {
90
90
  id: 'uuid',
@@ -97,7 +97,7 @@ const config = {
97
97
  }
98
98
  },
99
99
  apps: {
100
- schema: 'meta_public',
100
+ schema: 'services_public',
101
101
  table: 'apps',
102
102
  fields: {
103
103
  id: 'uuid',
@@ -112,7 +112,7 @@ const config = {
112
112
  }
113
113
  },
114
114
  site_modules: {
115
- schema: 'meta_public',
115
+ schema: 'services_public',
116
116
  table: 'site_modules',
117
117
  fields: {
118
118
  id: 'uuid',
@@ -123,7 +123,7 @@ const config = {
123
123
  }
124
124
  },
125
125
  site_themes: {
126
- schema: 'meta_public',
126
+ schema: 'services_public',
127
127
  table: 'site_themes',
128
128
  fields: {
129
129
  id: 'uuid',
@@ -133,7 +133,7 @@ const config = {
133
133
  }
134
134
  },
135
135
  api_modules: {
136
- schema: 'meta_public',
136
+ schema: 'services_public',
137
137
  table: 'api_modules',
138
138
  fields: {
139
139
  id: 'uuid',
@@ -144,7 +144,7 @@ const config = {
144
144
  }
145
145
  },
146
146
  api_extensions: {
147
- schema: 'meta_public',
147
+ schema: 'services_public',
148
148
  table: 'api_extensions',
149
149
  fields: {
150
150
  id: 'uuid',
@@ -154,7 +154,7 @@ const config = {
154
154
  }
155
155
  },
156
156
  api_schemata: {
157
- schema: 'meta_public',
157
+ schema: 'services_public',
158
158
  table: 'api_schemata',
159
159
  fields: {
160
160
  id: 'uuid',
@@ -164,7 +164,7 @@ const config = {
164
164
  }
165
165
  },
166
166
  rls_module: {
167
- schema: 'meta_public',
167
+ schema: 'metaschema_modules_public',
168
168
  table: 'rls_module',
169
169
  fields: {
170
170
  id: 'uuid',
@@ -181,7 +181,7 @@ const config = {
181
181
  }
182
182
  },
183
183
  user_auth_module: {
184
- schema: 'meta_public',
184
+ schema: 'metaschema_modules_public',
185
185
  table: 'user_auth_module',
186
186
  fields: {
187
187
  id: 'uuid',
@@ -227,22 +227,22 @@ const exportMeta = async ({ opts, dbname, database_id }) => {
227
227
  }
228
228
  }
229
229
  };
230
- await queryAndParse('database', `SELECT * FROM collections_public.database WHERE id = $1`);
231
- await queryAndParse('schema', `SELECT * FROM collections_public.schema WHERE database_id = $1`);
232
- await queryAndParse('table', `SELECT * FROM collections_public.table WHERE database_id = $1`);
233
- await queryAndParse('field', `SELECT * FROM collections_public.field WHERE database_id = $1`);
234
- await queryAndParse('domains', `SELECT * FROM meta_public.domains WHERE database_id = $1`);
235
- await queryAndParse('apis', `SELECT * FROM meta_public.apis WHERE database_id = $1`);
236
- await queryAndParse('sites', `SELECT * FROM meta_public.sites WHERE database_id = $1`);
237
- await queryAndParse('api_modules', `SELECT * FROM meta_public.api_modules WHERE database_id = $1`);
238
- await queryAndParse('site_modules', `SELECT * FROM meta_public.site_modules WHERE database_id = $1`);
239
- await queryAndParse('site_themes', `SELECT * FROM meta_public.site_themes WHERE database_id = $1`);
240
- await queryAndParse('apps', `SELECT * FROM meta_public.apps WHERE database_id = $1`);
241
- await queryAndParse('database_extension', `SELECT * FROM collections_public.database_extension WHERE database_id = $1`);
242
- await queryAndParse('api_extensions', `SELECT * FROM meta_public.api_extensions WHERE database_id = $1`);
243
- await queryAndParse('api_schemata', `SELECT * FROM meta_public.api_schemata WHERE database_id = $1`);
244
- await queryAndParse('rls_module', `SELECT * FROM meta_public.rls_module WHERE database_id = $1`);
245
- await queryAndParse('user_auth_module', `SELECT * FROM meta_public.user_auth_module WHERE database_id = $1`);
230
+ await queryAndParse('database', `SELECT * FROM metaschema_public.database WHERE id = $1`);
231
+ await queryAndParse('schema', `SELECT * FROM metaschema_public.schema WHERE database_id = $1`);
232
+ await queryAndParse('table', `SELECT * FROM metaschema_public.table WHERE database_id = $1`);
233
+ await queryAndParse('field', `SELECT * FROM metaschema_public.field WHERE database_id = $1`);
234
+ await queryAndParse('domains', `SELECT * FROM services_public.domains WHERE database_id = $1`);
235
+ await queryAndParse('apis', `SELECT * FROM services_public.apis WHERE database_id = $1`);
236
+ await queryAndParse('sites', `SELECT * FROM services_public.sites WHERE database_id = $1`);
237
+ await queryAndParse('api_modules', `SELECT * FROM services_public.api_modules WHERE database_id = $1`);
238
+ await queryAndParse('site_modules', `SELECT * FROM services_public.site_modules WHERE database_id = $1`);
239
+ await queryAndParse('site_themes', `SELECT * FROM services_public.site_themes WHERE database_id = $1`);
240
+ await queryAndParse('apps', `SELECT * FROM services_public.apps WHERE database_id = $1`);
241
+ await queryAndParse('database_extension', `SELECT * FROM metaschema_public.database_extension WHERE database_id = $1`);
242
+ await queryAndParse('api_extensions', `SELECT * FROM services_public.api_extensions WHERE database_id = $1`);
243
+ await queryAndParse('api_schemata', `SELECT * FROM services_public.api_schemata WHERE database_id = $1`);
244
+ await queryAndParse('rls_module', `SELECT * FROM metaschema_modules_public.rls_module WHERE database_id = $1`);
245
+ await queryAndParse('user_auth_module', `SELECT * FROM metaschema_modules_public.user_auth_module WHERE database_id = $1`);
246
246
  return Object.entries(sql).reduce((m, [_, v]) => m + '\n\n' + v, '');
247
247
  };
248
248
  exports.exportMeta = exportMeta;
@@ -29,6 +29,12 @@ interface ExportOptions {
29
29
  username?: string;
30
30
  /** Output directory for service/meta module. Defaults to outdir if not provided. */
31
31
  serviceOutdir?: string;
32
+ /**
33
+ * Skip schema name replacement for infrastructure schemas.
34
+ * When true, schema names like metaschema_public, services_public will not be renamed.
35
+ * Useful for self-referential introspection where you want to apply policies to real schemas.
36
+ */
37
+ skipSchemaRenaming?: boolean;
32
38
  }
33
- export declare const exportMigrations: ({ project, options, dbInfo, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir }: ExportOptions) => Promise<void>;
39
+ export declare const exportMigrations: ({ project, options, dbInfo, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir, skipSchemaRenaming }: ExportOptions) => Promise<void>;
34
40
  export {};
@@ -98,7 +98,7 @@ const installMissingModules = async (moduleDir, missingModules) => {
98
98
  await moduleProject.installModules(...missingNames);
99
99
  console.log('Modules installed successfully.');
100
100
  };
101
- const exportMigrationsToDisk = async ({ project, options, database, databaseId, databaseName, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir }) => {
101
+ const exportMigrationsToDisk = async ({ project, options, database, databaseId, databaseName, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir, skipSchemaRenaming = false }) => {
102
102
  outdir = outdir + '/';
103
103
  // Use serviceOutdir for service module, defaulting to outdir if not provided
104
104
  const svcOutdir = (serviceOutdir || outdir.slice(0, -1)) + '/';
@@ -106,8 +106,8 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
106
106
  ...options.pg,
107
107
  database
108
108
  });
109
- const db = await pgPool.query(`select * from collections_public.database where id=$1`, [databaseId]);
110
- const schemas = await pgPool.query(`select * from collections_public.schema where database_id=$1`, [databaseId]);
109
+ const db = await pgPool.query(`select * from metaschema_public.database where id=$1`, [databaseId]);
110
+ const schemas = await pgPool.query(`select * from metaschema_public.schema where database_id=$1`, [databaseId]);
111
111
  if (!db?.rows?.length) {
112
112
  console.log('NO DATABASES.');
113
113
  return;
@@ -117,11 +117,20 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
117
117
  return;
118
118
  }
119
119
  const name = extensionName || db.rows[0].name;
120
+ // When skipSchemaRenaming is true, pass empty schemas array to avoid renaming
121
+ // This is useful for self-referential introspection where you want to apply
122
+ // policies to real infrastructure schemas (metaschema_public, services_public, etc.)
123
+ const schemasForReplacement = skipSchemaRenaming
124
+ ? []
125
+ : schemas.rows.filter((schema) => schema_names.includes(schema.schema_name));
120
126
  const { replace, replacer } = makeReplacer({
121
- schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
127
+ schemas: schemasForReplacement,
122
128
  name
123
129
  });
124
- const results = await pgPool.query(`select * from db_migrate.sql_actions order by id`);
130
+ // Filter sql_actions by database_id to avoid cross-database pollution
131
+ // Previously this query had no WHERE clause, which could export actions
132
+ // from unrelated databases in a persistent database environment
133
+ const results = await pgPool.query(`select * from db_migrate.sql_actions where database_id = $1 order by id`, [databaseId]);
125
134
  const opts = {
126
135
  name,
127
136
  replacer,
@@ -177,8 +186,12 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
177
186
  if (svcMissingResult.shouldInstall) {
178
187
  await installMissingModules(svcModuleDir, svcMissingResult.missingModules);
179
188
  }
189
+ // Use same skipSchemaRenaming logic for meta replacer
190
+ const metaSchemasForReplacement = skipSchemaRenaming
191
+ ? []
192
+ : schemas.rows.filter((schema) => schema_names.includes(schema.schema_name));
180
193
  const metaReplacer = makeReplacer({
181
- schemas: schemas.rows.filter((schema) => schema_names.includes(schema.schema_name)),
194
+ schemas: metaSchemasForReplacement,
182
195
  name: metaExtensionName
183
196
  });
184
197
  const metaPackage = [
@@ -186,7 +199,7 @@ const exportMigrationsToDisk = async ({ project, options, database, databaseId,
186
199
  deps: [],
187
200
  deploy: 'migrate/meta',
188
201
  content: `SET session_replication_role TO replica;
189
- -- using replica in case we are deploying triggers to collections_public
202
+ -- using replica in case we are deploying triggers to metaschema_public
190
203
 
191
204
  -- unaccent, postgis affected and require grants
192
205
  GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public to public;
@@ -205,12 +218,12 @@ ${meta}
205
218
 
206
219
  -- TODO: Research needed - These UPDATE statements may be a security leak.
207
220
  -- They appear to rebind exported metadata to the target database after import,
208
- -- but exposing dbname in meta_public tables could leak internal database names.
221
+ -- but exposing dbname in services_public tables could leak internal database names.
209
222
  -- Consider removing entirely or gating behind an explicit flag.
210
- -- UPDATE meta_public.apis
223
+ -- UPDATE services_public.apis
211
224
  -- SET dbname = current_database() WHERE TRUE;
212
225
 
213
- -- UPDATE meta_public.sites
226
+ -- UPDATE services_public.sites
214
227
  -- SET dbname = current_database() WHERE TRUE;
215
228
 
216
229
  SET session_replication_role TO DEFAULT;
@@ -225,7 +238,7 @@ SET session_replication_role TO DEFAULT;
225
238
  }
226
239
  pgPool.end();
227
240
  };
228
- const exportMigrations = async ({ project, options, dbInfo, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir }) => {
241
+ const exportMigrations = async ({ project, options, dbInfo, author, outdir, schema_names, extensionName, extensionDesc, metaExtensionName, metaExtensionDesc, prompter, repoName, username, serviceOutdir, skipSchemaRenaming }) => {
229
242
  for (let v = 0; v < dbInfo.database_ids.length; v++) {
230
243
  const databaseId = dbInfo.database_ids[v];
231
244
  await exportMigrationsToDisk({
@@ -244,7 +257,8 @@ const exportMigrations = async ({ project, options, dbInfo, author, outdir, sche
244
257
  prompter,
245
258
  repoName,
246
259
  username,
247
- serviceOutdir
260
+ serviceOutdir,
261
+ skipSchemaRenaming
248
262
  });
249
263
  }
250
264
  };
@@ -11,8 +11,8 @@ const types_1 = require("@pgpmjs/types");
11
11
  exports.PGPM_MODULE_MAP = {
12
12
  'pgpm-base32': '@pgpm/base32',
13
13
  'pgpm-database-jobs': '@pgpm/database-jobs',
14
- 'db-meta-modules': '@pgpm/db-meta-modules',
15
- 'db-meta-schema': '@pgpm/db-meta-schema',
14
+ 'metaschema-modules': '@pgpm/metaschema-modules',
15
+ 'metaschema-schema': '@pgpm/metaschema-schema',
16
16
  'pgpm-inflection': '@pgpm/inflection',
17
17
  'pgpm-jwt-claims': '@pgpm/jwt-claims',
18
18
  'pgpm-stamps': '@pgpm/stamps',
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pgpmjs/core",
3
- "version": "4.7.1",
3
+ "version": "4.8.0",
4
4
  "author": "Constructive <developers@constructive.io>",
5
5
  "description": "PGPM Package and Migration Tools",
6
6
  "main": "index.js",
@@ -64,5 +64,5 @@
64
64
  "pgsql-parser": "^17.9.9",
65
65
  "yanse": "^0.1.11"
66
66
  },
67
- "gitHead": "acb072b93704ad5218dd2c38306680f3750ead09"
67
+ "gitHead": "97528ad4eb2f60c16785ffb84af7b61c52cb5ad8"
68
68
  }