@pgpmjs/core 3.0.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.
Files changed (140) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +99 -0
  3. package/core/boilerplate-scanner.d.ts +41 -0
  4. package/core/boilerplate-scanner.js +106 -0
  5. package/core/boilerplate-types.d.ts +52 -0
  6. package/core/boilerplate-types.js +6 -0
  7. package/core/class/pgpm.d.ts +150 -0
  8. package/core/class/pgpm.js +1470 -0
  9. package/core/template-scaffold.d.ts +29 -0
  10. package/core/template-scaffold.js +168 -0
  11. package/esm/core/boilerplate-scanner.js +96 -0
  12. package/esm/core/boilerplate-types.js +5 -0
  13. package/esm/core/class/pgpm.js +1430 -0
  14. package/esm/core/template-scaffold.js +161 -0
  15. package/esm/export/export-meta.js +240 -0
  16. package/esm/export/export-migrations.js +180 -0
  17. package/esm/extensions/extensions.js +31 -0
  18. package/esm/files/extension/index.js +3 -0
  19. package/esm/files/extension/reader.js +79 -0
  20. package/esm/files/extension/writer.js +63 -0
  21. package/esm/files/index.js +6 -0
  22. package/esm/files/plan/generator.js +49 -0
  23. package/esm/files/plan/index.js +5 -0
  24. package/esm/files/plan/parser.js +296 -0
  25. package/esm/files/plan/validators.js +181 -0
  26. package/esm/files/plan/writer.js +114 -0
  27. package/esm/files/sql/index.js +1 -0
  28. package/esm/files/sql/writer.js +107 -0
  29. package/esm/files/sql-scripts/index.js +2 -0
  30. package/esm/files/sql-scripts/reader.js +19 -0
  31. package/esm/files/types/index.js +1 -0
  32. package/esm/files/types/package.js +1 -0
  33. package/esm/index.js +21 -0
  34. package/esm/init/client.js +144 -0
  35. package/esm/init/sql/bootstrap-roles.sql +55 -0
  36. package/esm/init/sql/bootstrap-test-roles.sql +72 -0
  37. package/esm/migrate/clean.js +23 -0
  38. package/esm/migrate/client.js +551 -0
  39. package/esm/migrate/index.js +5 -0
  40. package/esm/migrate/sql/procedures.sql +258 -0
  41. package/esm/migrate/sql/schema.sql +37 -0
  42. package/esm/migrate/types.js +1 -0
  43. package/esm/migrate/utils/event-logger.js +28 -0
  44. package/esm/migrate/utils/hash.js +27 -0
  45. package/esm/migrate/utils/transaction.js +125 -0
  46. package/esm/modules/modules.js +49 -0
  47. package/esm/packaging/package.js +96 -0
  48. package/esm/packaging/transform.js +70 -0
  49. package/esm/projects/deploy.js +123 -0
  50. package/esm/projects/revert.js +75 -0
  51. package/esm/projects/verify.js +61 -0
  52. package/esm/resolution/deps.js +526 -0
  53. package/esm/resolution/resolve.js +101 -0
  54. package/esm/utils/debug.js +147 -0
  55. package/esm/utils/target-utils.js +37 -0
  56. package/esm/workspace/paths.js +43 -0
  57. package/esm/workspace/utils.js +31 -0
  58. package/export/export-meta.d.ts +8 -0
  59. package/export/export-meta.js +244 -0
  60. package/export/export-migrations.d.ts +17 -0
  61. package/export/export-migrations.js +187 -0
  62. package/extensions/extensions.d.ts +5 -0
  63. package/extensions/extensions.js +35 -0
  64. package/files/extension/index.d.ts +2 -0
  65. package/files/extension/index.js +19 -0
  66. package/files/extension/reader.d.ts +24 -0
  67. package/files/extension/reader.js +86 -0
  68. package/files/extension/writer.d.ts +39 -0
  69. package/files/extension/writer.js +70 -0
  70. package/files/index.d.ts +5 -0
  71. package/files/index.js +22 -0
  72. package/files/plan/generator.d.ts +22 -0
  73. package/files/plan/generator.js +57 -0
  74. package/files/plan/index.d.ts +4 -0
  75. package/files/plan/index.js +21 -0
  76. package/files/plan/parser.d.ts +27 -0
  77. package/files/plan/parser.js +303 -0
  78. package/files/plan/validators.d.ts +52 -0
  79. package/files/plan/validators.js +187 -0
  80. package/files/plan/writer.d.ts +27 -0
  81. package/files/plan/writer.js +124 -0
  82. package/files/sql/index.d.ts +1 -0
  83. package/files/sql/index.js +17 -0
  84. package/files/sql/writer.d.ts +12 -0
  85. package/files/sql/writer.js +114 -0
  86. package/files/sql-scripts/index.d.ts +1 -0
  87. package/files/sql-scripts/index.js +18 -0
  88. package/files/sql-scripts/reader.d.ts +8 -0
  89. package/files/sql-scripts/reader.js +23 -0
  90. package/files/types/index.d.ts +46 -0
  91. package/files/types/index.js +17 -0
  92. package/files/types/package.d.ts +20 -0
  93. package/files/types/package.js +2 -0
  94. package/index.d.ts +21 -0
  95. package/index.js +45 -0
  96. package/init/client.d.ts +26 -0
  97. package/init/client.js +148 -0
  98. package/init/sql/bootstrap-roles.sql +55 -0
  99. package/init/sql/bootstrap-test-roles.sql +72 -0
  100. package/migrate/clean.d.ts +1 -0
  101. package/migrate/clean.js +27 -0
  102. package/migrate/client.d.ts +80 -0
  103. package/migrate/client.js +555 -0
  104. package/migrate/index.d.ts +5 -0
  105. package/migrate/index.js +21 -0
  106. package/migrate/sql/procedures.sql +258 -0
  107. package/migrate/sql/schema.sql +37 -0
  108. package/migrate/types.d.ts +67 -0
  109. package/migrate/types.js +2 -0
  110. package/migrate/utils/event-logger.d.ts +13 -0
  111. package/migrate/utils/event-logger.js +32 -0
  112. package/migrate/utils/hash.d.ts +12 -0
  113. package/migrate/utils/hash.js +32 -0
  114. package/migrate/utils/transaction.d.ts +27 -0
  115. package/migrate/utils/transaction.js +129 -0
  116. package/modules/modules.d.ts +31 -0
  117. package/modules/modules.js +56 -0
  118. package/package.json +70 -0
  119. package/packaging/package.d.ts +19 -0
  120. package/packaging/package.js +102 -0
  121. package/packaging/transform.d.ts +22 -0
  122. package/packaging/transform.js +75 -0
  123. package/projects/deploy.d.ts +8 -0
  124. package/projects/deploy.js +160 -0
  125. package/projects/revert.d.ts +15 -0
  126. package/projects/revert.js +112 -0
  127. package/projects/verify.d.ts +8 -0
  128. package/projects/verify.js +98 -0
  129. package/resolution/deps.d.ts +57 -0
  130. package/resolution/deps.js +531 -0
  131. package/resolution/resolve.d.ts +37 -0
  132. package/resolution/resolve.js +107 -0
  133. package/utils/debug.d.ts +21 -0
  134. package/utils/debug.js +153 -0
  135. package/utils/target-utils.d.ts +5 -0
  136. package/utils/target-utils.js +40 -0
  137. package/workspace/paths.d.ts +14 -0
  138. package/workspace/paths.js +50 -0
  139. package/workspace/utils.d.ts +8 -0
  140. package/workspace/utils.js +36 -0
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./writer"), exports);
@@ -0,0 +1,12 @@
1
+ import { SqitchRow } from '../types';
2
+ export interface SqlWriteOptions {
3
+ outdir: string;
4
+ name: string;
5
+ replacer: (str: string) => string;
6
+ author?: string;
7
+ useTx?: boolean;
8
+ }
9
+ /**
10
+ * Write SQL files for Sqitch migrations (deploy, revert, verify)
11
+ */
12
+ export declare const writeSqitchFiles: (rows: SqitchRow[], opts: SqlWriteOptions) => void;
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.writeSqitchFiles = void 0;
7
+ const env_1 = require("@pgpmjs/env");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ /**
11
+ * Write SQL files for Sqitch migrations (deploy, revert, verify)
12
+ */
13
+ const writeSqitchFiles = (rows, opts) => {
14
+ rows.forEach((row) => writeVerify(row, opts));
15
+ rows.forEach((row) => writeRevert(row, opts));
16
+ rows.forEach((row) => writeDeploy(row, opts));
17
+ };
18
+ exports.writeSqitchFiles = writeSqitchFiles;
19
+ /**
20
+ * Sort dependencies in a consistent order
21
+ */
22
+ const ordered = (arr) => {
23
+ if (!arr)
24
+ return [];
25
+ return arr.sort((a, b) => a.length - b.length || a.localeCompare(b));
26
+ };
27
+ /**
28
+ * Write a deploy SQL file for a Sqitch change
29
+ */
30
+ const writeDeploy = (row, opts) => {
31
+ const globalOpts = (0, env_1.getEnvOptions)({
32
+ migrations: {
33
+ codegen: {
34
+ useTx: opts.useTx
35
+ }
36
+ }
37
+ });
38
+ const useTx = globalOpts.migrations.codegen.useTx;
39
+ const deploy = opts.replacer(row.deploy);
40
+ const dir = path_1.default.dirname(deploy);
41
+ const prefix = path_1.default.join(opts.outdir, opts.name, 'deploy');
42
+ const actualDir = path_1.default.resolve(prefix, dir);
43
+ const actualFile = path_1.default.resolve(prefix, `${deploy}.sql`);
44
+ fs_1.default.mkdirSync(actualDir, { recursive: true });
45
+ const sqlContent = opts.replacer(row.content);
46
+ const content = `-- Deploy: ${deploy}
47
+ -- made with <3 @ constructive.io
48
+
49
+ ${opts.replacer(ordered(row?.deps)
50
+ .map((dep) => `-- requires: ${dep}`)
51
+ .join('\n') || '')}
52
+
53
+ ${useTx ? 'BEGIN;' : ''}
54
+ ${sqlContent}
55
+ ${useTx ? 'COMMIT;' : ''}
56
+ `;
57
+ fs_1.default.writeFileSync(actualFile, content);
58
+ };
59
+ /**
60
+ * Write a verify SQL file for a Sqitch change
61
+ */
62
+ const writeVerify = (row, opts) => {
63
+ const globalOpts = (0, env_1.getEnvOptions)({
64
+ migrations: {
65
+ codegen: {
66
+ useTx: opts.useTx
67
+ }
68
+ }
69
+ });
70
+ const useTx = globalOpts.migrations.codegen.useTx;
71
+ const deploy = opts.replacer(row.deploy);
72
+ const dir = path_1.default.dirname(deploy);
73
+ const prefix = path_1.default.join(opts.outdir, opts.name, 'verify');
74
+ const actualDir = path_1.default.resolve(prefix, dir);
75
+ const actualFile = path_1.default.resolve(prefix, `${deploy}.sql`);
76
+ fs_1.default.mkdirSync(actualDir, { recursive: true });
77
+ const sqlContent = opts.replacer(row.verify);
78
+ const content = opts.replacer(`-- Verify: ${deploy}
79
+
80
+ ${useTx ? 'BEGIN;' : ''}
81
+ ${sqlContent}
82
+ ${useTx ? 'COMMIT;' : ''}
83
+
84
+ `);
85
+ fs_1.default.writeFileSync(actualFile, content);
86
+ };
87
+ /**
88
+ * Write a revert SQL file for a Sqitch change
89
+ */
90
+ const writeRevert = (row, opts) => {
91
+ const globalOpts = (0, env_1.getEnvOptions)({
92
+ migrations: {
93
+ codegen: {
94
+ useTx: opts.useTx
95
+ }
96
+ }
97
+ });
98
+ const useTx = globalOpts.migrations.codegen.useTx;
99
+ const deploy = opts.replacer(row.deploy);
100
+ const dir = path_1.default.dirname(deploy);
101
+ const prefix = path_1.default.join(opts.outdir, opts.name, 'revert');
102
+ const actualDir = path_1.default.resolve(prefix, dir);
103
+ const actualFile = path_1.default.resolve(prefix, `${deploy}.sql`);
104
+ fs_1.default.mkdirSync(actualDir, { recursive: true });
105
+ const sqlContent = opts.replacer(row.revert);
106
+ const content = `-- Revert: ${deploy}
107
+
108
+ ${useTx ? 'BEGIN;' : ''}
109
+ ${sqlContent}
110
+ ${useTx ? 'COMMIT;' : ''}
111
+
112
+ `;
113
+ fs_1.default.writeFileSync(actualFile, content);
114
+ };
@@ -0,0 +1 @@
1
+ export * from './reader';
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ // Re-export all sql-scripts functionality
18
+ __exportStar(require("./reader"), exports);
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Read a SQL script file, return empty string if not found
3
+ */
4
+ export declare function readScript(basePath: string, scriptType: string, changeName: string): string;
5
+ /**
6
+ * Check if a script file exists
7
+ */
8
+ export declare function scriptExists(basePath: string, scriptType: string, changeName: string): boolean;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.readScript = readScript;
4
+ exports.scriptExists = scriptExists;
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ /**
8
+ * Read a SQL script file, return empty string if not found
9
+ */
10
+ function readScript(basePath, scriptType, changeName) {
11
+ const scriptPath = (0, path_1.join)(basePath, scriptType, `${changeName}.sql`);
12
+ if (!(0, fs_1.existsSync)(scriptPath)) {
13
+ return '';
14
+ }
15
+ return (0, fs_1.readFileSync)(scriptPath, 'utf-8');
16
+ }
17
+ /**
18
+ * Check if a script file exists
19
+ */
20
+ function scriptExists(basePath, scriptType, changeName) {
21
+ const scriptPath = (0, path_1.join)(basePath, scriptType, `${changeName}.sql`);
22
+ return (0, fs_1.existsSync)(scriptPath);
23
+ }
@@ -0,0 +1,46 @@
1
+ export * from './package';
2
+ export interface Change {
3
+ name: string;
4
+ dependencies: string[];
5
+ timestamp?: string;
6
+ planner?: string;
7
+ email?: string;
8
+ comment?: string;
9
+ }
10
+ export interface PlanFile {
11
+ package: string;
12
+ uri?: string;
13
+ changes: Change[];
14
+ }
15
+ export interface Tag {
16
+ name: string;
17
+ change: string;
18
+ timestamp?: string;
19
+ planner?: string;
20
+ email?: string;
21
+ comment?: string;
22
+ }
23
+ export interface ExtendedPlanFile extends PlanFile {
24
+ tags: Tag[];
25
+ }
26
+ export interface ParseError {
27
+ line: number;
28
+ message: string;
29
+ }
30
+ export interface ParseResult<T> {
31
+ data?: T;
32
+ errors: ParseError[];
33
+ }
34
+ export interface ResolvedReference {
35
+ type: 'change' | 'tag' | 'sha1' | 'relative';
36
+ target: string;
37
+ resolved?: string;
38
+ }
39
+ export interface SqitchRow {
40
+ deploy: string;
41
+ revert?: string;
42
+ verify?: string;
43
+ content: string;
44
+ deps?: string[];
45
+ name?: string;
46
+ }
@@ -0,0 +1,17 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./package"), exports);
@@ -0,0 +1,20 @@
1
+ export interface PackageAnalysisIssue {
2
+ code: string;
3
+ message: string;
4
+ file?: string;
5
+ fixable?: boolean;
6
+ }
7
+ export interface PackageAnalysisResult {
8
+ ok: boolean;
9
+ name: string;
10
+ path: string;
11
+ issues: PackageAnalysisIssue[];
12
+ }
13
+ export interface RenameOptions {
14
+ dryRun?: boolean;
15
+ syncPackageJsonName?: boolean;
16
+ }
17
+ export interface RenameResult {
18
+ changed: string[];
19
+ warnings: string[];
20
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/index.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ export * from './core/class/pgpm';
2
+ export * from './export/export-meta';
3
+ export * from './export/export-migrations';
4
+ export * from './extensions/extensions';
5
+ export * from './modules/modules';
6
+ export * from './packaging/package';
7
+ export * from './packaging/transform';
8
+ export * from './resolution/deps';
9
+ export * from './resolution/resolve';
10
+ export * from './workspace/paths';
11
+ export * from './workspace/utils';
12
+ export * from './core/template-scaffold';
13
+ export * from './core/boilerplate-types';
14
+ export * from './core/boilerplate-scanner';
15
+ export * from './files';
16
+ export { cleanSql } from './migrate/clean';
17
+ export { PgpmMigrate } from './migrate/client';
18
+ export { PgpmInit } from './init/client';
19
+ export { DeployOptions, DeployResult, MigrateChange, MigratePlanFile, RevertOptions, RevertResult, StatusResult, VerifyOptions, VerifyResult } from './migrate/types';
20
+ export { hashFile, hashString } from './migrate/utils/hash';
21
+ export { executeQuery, TransactionContext, TransactionOptions, withTransaction } from './migrate/utils/transaction';
package/index.js ADDED
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.withTransaction = exports.executeQuery = exports.hashString = exports.hashFile = exports.PgpmInit = exports.PgpmMigrate = exports.cleanSql = void 0;
18
+ __exportStar(require("./core/class/pgpm"), exports);
19
+ __exportStar(require("./export/export-meta"), exports);
20
+ __exportStar(require("./export/export-migrations"), exports);
21
+ __exportStar(require("./extensions/extensions"), exports);
22
+ __exportStar(require("./modules/modules"), exports);
23
+ __exportStar(require("./packaging/package"), exports);
24
+ __exportStar(require("./packaging/transform"), exports);
25
+ __exportStar(require("./resolution/deps"), exports);
26
+ __exportStar(require("./resolution/resolve"), exports);
27
+ __exportStar(require("./workspace/paths"), exports);
28
+ __exportStar(require("./workspace/utils"), exports);
29
+ __exportStar(require("./core/template-scaffold"), exports);
30
+ __exportStar(require("./core/boilerplate-types"), exports);
31
+ __exportStar(require("./core/boilerplate-scanner"), exports);
32
+ // Export package-files functionality (now integrated into core)
33
+ __exportStar(require("./files"), exports);
34
+ var clean_1 = require("./migrate/clean");
35
+ Object.defineProperty(exports, "cleanSql", { enumerable: true, get: function () { return clean_1.cleanSql; } });
36
+ var client_1 = require("./migrate/client");
37
+ Object.defineProperty(exports, "PgpmMigrate", { enumerable: true, get: function () { return client_1.PgpmMigrate; } });
38
+ var client_2 = require("./init/client");
39
+ Object.defineProperty(exports, "PgpmInit", { enumerable: true, get: function () { return client_2.PgpmInit; } });
40
+ var hash_1 = require("./migrate/utils/hash");
41
+ Object.defineProperty(exports, "hashFile", { enumerable: true, get: function () { return hash_1.hashFile; } });
42
+ Object.defineProperty(exports, "hashString", { enumerable: true, get: function () { return hash_1.hashString; } });
43
+ var transaction_1 = require("./migrate/utils/transaction");
44
+ Object.defineProperty(exports, "executeQuery", { enumerable: true, get: function () { return transaction_1.executeQuery; } });
45
+ Object.defineProperty(exports, "withTransaction", { enumerable: true, get: function () { return transaction_1.withTransaction; } });
@@ -0,0 +1,26 @@
1
+ import { PgConfig } from 'pg-env';
2
+ export declare class PgpmInit {
3
+ private pool;
4
+ private pgConfig;
5
+ constructor(config: PgConfig);
6
+ /**
7
+ * Bootstrap standard roles (anonymous, authenticated, administrator)
8
+ */
9
+ bootstrapRoles(): Promise<void>;
10
+ /**
11
+ * Bootstrap test roles (roles only, no users)
12
+ */
13
+ bootstrapTestRoles(): Promise<void>;
14
+ /**
15
+ * Bootstrap database roles with custom username and password
16
+ */
17
+ bootstrapDbRoles(username: string, password: string): Promise<void>;
18
+ /**
19
+ * Remove database roles and revoke grants
20
+ */
21
+ removeDbRoles(username: string): Promise<void>;
22
+ /**
23
+ * Close the database connection
24
+ */
25
+ close(): Promise<void>;
26
+ }
package/init/client.js ADDED
@@ -0,0 +1,148 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PgpmInit = void 0;
4
+ const logger_1 = require("@pgpmjs/logger");
5
+ const fs_1 = require("fs");
6
+ const path_1 = require("path");
7
+ const pg_cache_1 = require("pg-cache");
8
+ const log = new logger_1.Logger('init');
9
+ class PgpmInit {
10
+ pool;
11
+ pgConfig;
12
+ constructor(config) {
13
+ this.pgConfig = config;
14
+ this.pool = (0, pg_cache_1.getPgPool)(this.pgConfig);
15
+ }
16
+ /**
17
+ * Bootstrap standard roles (anonymous, authenticated, administrator)
18
+ */
19
+ async bootstrapRoles() {
20
+ try {
21
+ log.info('Bootstrapping PGPM roles...');
22
+ const sqlPath = (0, path_1.join)(__dirname, 'sql', 'bootstrap-roles.sql');
23
+ const sql = (0, fs_1.readFileSync)(sqlPath, 'utf-8');
24
+ await this.pool.query(sql);
25
+ log.success('Successfully bootstrapped PGPM roles');
26
+ }
27
+ catch (error) {
28
+ log.error('Failed to bootstrap roles:', error);
29
+ throw error;
30
+ }
31
+ }
32
+ /**
33
+ * Bootstrap test roles (roles only, no users)
34
+ */
35
+ async bootstrapTestRoles() {
36
+ try {
37
+ log.warn('WARNING: This command creates test roles and should NEVER be run on a production database!');
38
+ log.info('Bootstrapping PGPM test roles...');
39
+ const sqlPath = (0, path_1.join)(__dirname, 'sql', 'bootstrap-test-roles.sql');
40
+ const sql = (0, fs_1.readFileSync)(sqlPath, 'utf-8');
41
+ await this.pool.query(sql);
42
+ log.success('Successfully bootstrapped PGPM test roles');
43
+ }
44
+ catch (error) {
45
+ log.error('Failed to bootstrap test roles:', error);
46
+ throw error;
47
+ }
48
+ }
49
+ /**
50
+ * Bootstrap database roles with custom username and password
51
+ */
52
+ async bootstrapDbRoles(username, password) {
53
+ try {
54
+ log.info(`Bootstrapping PGPM database roles for user: ${username}...`);
55
+ const sql = `
56
+ BEGIN;
57
+ DO $do$
58
+ DECLARE
59
+ v_username TEXT := '${username.replace(/'/g, "''")}';
60
+ v_password TEXT := '${password.replace(/'/g, "''")}';
61
+ BEGIN
62
+ BEGIN
63
+ EXECUTE format('CREATE ROLE %I LOGIN PASSWORD %L', v_username, v_password);
64
+ EXCEPTION
65
+ WHEN duplicate_object THEN
66
+ -- Role already exists; optionally sync attributes here with ALTER ROLE
67
+ NULL;
68
+ END;
69
+ END
70
+ $do$;
71
+
72
+ -- Robust GRANTs under concurrency: GRANT can race on pg_auth_members unique index.
73
+ -- Catch unique_violation (23505) and continue so CI/CD concurrent jobs don't fail.
74
+ DO $do$
75
+ DECLARE
76
+ v_username TEXT := '${username.replace(/'/g, "''")}';
77
+ BEGIN
78
+ BEGIN
79
+ EXECUTE format('GRANT %I TO %I', 'anonymous', v_username);
80
+ EXCEPTION
81
+ WHEN unique_violation THEN
82
+ -- Membership was granted concurrently; ignore.
83
+ NULL;
84
+ WHEN undefined_object THEN
85
+ -- One of the roles doesn't exist yet; order operations as needed.
86
+ RAISE NOTICE 'Missing role when granting % to %', 'anonymous', v_username;
87
+ END;
88
+
89
+ BEGIN
90
+ EXECUTE format('GRANT %I TO %I', 'authenticated', v_username);
91
+ EXCEPTION
92
+ WHEN unique_violation THEN
93
+ -- Membership was granted concurrently; ignore.
94
+ NULL;
95
+ WHEN undefined_object THEN
96
+ RAISE NOTICE 'Missing role when granting % to %', 'authenticated', v_username;
97
+ END;
98
+ END
99
+ $do$;
100
+ COMMIT;
101
+ `;
102
+ await this.pool.query(sql);
103
+ log.success(`Successfully bootstrapped PGPM database roles for user: ${username}`);
104
+ }
105
+ catch (error) {
106
+ log.error(`Failed to bootstrap database roles for user ${username}:`, error);
107
+ throw error;
108
+ }
109
+ }
110
+ /**
111
+ * Remove database roles and revoke grants
112
+ */
113
+ async removeDbRoles(username) {
114
+ try {
115
+ log.info(`Removing PGPM database roles for user: ${username}...`);
116
+ const sql = `
117
+ BEGIN;
118
+ DO $do$
119
+ BEGIN
120
+ IF EXISTS (
121
+ SELECT 1
122
+ FROM
123
+ pg_catalog.pg_roles
124
+ WHERE
125
+ rolname = '${username}') THEN
126
+ REVOKE anonymous FROM ${username};
127
+ REVOKE authenticated FROM ${username};
128
+ DROP ROLE ${username};
129
+ END IF;
130
+ END
131
+ $do$;
132
+ COMMIT;
133
+ `;
134
+ await this.pool.query(sql);
135
+ log.success(`Successfully removed PGPM database roles for user: ${username}`);
136
+ }
137
+ catch (error) {
138
+ log.error(`Failed to remove database roles for user ${username}:`, error);
139
+ throw error;
140
+ }
141
+ }
142
+ /**
143
+ * Close the database connection
144
+ */
145
+ async close() {
146
+ }
147
+ }
148
+ exports.PgpmInit = PgpmInit;
@@ -0,0 +1,55 @@
1
+ BEGIN;
2
+ DO $do$
3
+ BEGIN
4
+ -- anonymous
5
+ BEGIN
6
+ EXECUTE format('CREATE ROLE %I', 'anonymous');
7
+ EXCEPTION
8
+ WHEN duplicate_object THEN
9
+ -- Role already exists; optionally sync attributes here with ALTER ROLE
10
+ NULL;
11
+ END;
12
+
13
+ -- authenticated
14
+ BEGIN
15
+ EXECUTE format('CREATE ROLE %I', 'authenticated');
16
+ EXCEPTION
17
+ WHEN duplicate_object THEN
18
+ -- Role already exists; optionally sync attributes here with ALTER ROLE
19
+ NULL;
20
+ END;
21
+
22
+ -- administrator
23
+ BEGIN
24
+ EXECUTE format('CREATE ROLE %I', 'administrator');
25
+ EXCEPTION
26
+ WHEN duplicate_object THEN
27
+ -- Role already exists; optionally sync attributes here with ALTER ROLE
28
+ NULL;
29
+ END;
30
+ END
31
+ $do$;
32
+
33
+ -- Set role attributes (safe to run even if role already exists)
34
+ ALTER USER anonymous WITH NOCREATEDB;
35
+ ALTER USER anonymous WITH NOSUPERUSER;
36
+ ALTER USER anonymous WITH NOCREATEROLE;
37
+ ALTER USER anonymous WITH NOLOGIN;
38
+ ALTER USER anonymous WITH NOREPLICATION;
39
+ ALTER USER anonymous WITH NOBYPASSRLS;
40
+
41
+ ALTER USER authenticated WITH NOCREATEDB;
42
+ ALTER USER authenticated WITH NOSUPERUSER;
43
+ ALTER USER authenticated WITH NOCREATEROLE;
44
+ ALTER USER authenticated WITH NOLOGIN;
45
+ ALTER USER authenticated WITH NOREPLICATION;
46
+ ALTER USER authenticated WITH NOBYPASSRLS;
47
+
48
+ ALTER USER administrator WITH NOCREATEDB;
49
+ ALTER USER administrator WITH NOSUPERUSER;
50
+ ALTER USER administrator WITH NOCREATEROLE;
51
+ ALTER USER administrator WITH NOLOGIN;
52
+ ALTER USER administrator WITH NOREPLICATION;
53
+ -- they CAN bypass RLS
54
+ ALTER USER administrator WITH BYPASSRLS;
55
+ COMMIT;
@@ -0,0 +1,72 @@
1
+ BEGIN;
2
+ DO $do$
3
+ BEGIN
4
+ BEGIN
5
+ EXECUTE format('CREATE ROLE %I LOGIN PASSWORD %L', 'app_user', 'app_password');
6
+ EXCEPTION
7
+ WHEN duplicate_object THEN
8
+ -- Role already exists; optionally sync attributes here with ALTER ROLE
9
+ NULL;
10
+ END;
11
+
12
+ BEGIN
13
+ EXECUTE format('CREATE ROLE %I LOGIN PASSWORD %L', 'app_admin', 'admin_password');
14
+ EXCEPTION
15
+ WHEN duplicate_object THEN
16
+ -- Role already exists; optionally sync attributes here with ALTER ROLE
17
+ NULL;
18
+ END;
19
+ END
20
+ $do$;
21
+
22
+ DO $do$
23
+ BEGIN
24
+ BEGIN
25
+ EXECUTE format('GRANT %I TO %I', 'anonymous', 'app_user');
26
+ EXCEPTION
27
+ WHEN unique_violation THEN
28
+ -- Membership was granted concurrently; ignore.
29
+ NULL;
30
+ WHEN undefined_object THEN
31
+ -- One of the roles doesn't exist yet; order operations as needed.
32
+ RAISE NOTICE 'Missing role when granting % to %', 'anonymous', 'app_user';
33
+ END;
34
+
35
+ BEGIN
36
+ EXECUTE format('GRANT %I TO %I', 'authenticated', 'app_user');
37
+ EXCEPTION
38
+ WHEN unique_violation THEN
39
+ NULL;
40
+ WHEN undefined_object THEN
41
+ RAISE NOTICE 'Missing role when granting % to %', 'authenticated', 'app_user';
42
+ END;
43
+
44
+ BEGIN
45
+ EXECUTE format('GRANT %I TO %I', 'anonymous', 'administrator');
46
+ EXCEPTION
47
+ WHEN unique_violation THEN
48
+ NULL;
49
+ WHEN undefined_object THEN
50
+ RAISE NOTICE 'Missing role when granting % to %', 'anonymous', 'administrator';
51
+ END;
52
+
53
+ BEGIN
54
+ EXECUTE format('GRANT %I TO %I', 'authenticated', 'administrator');
55
+ EXCEPTION
56
+ WHEN unique_violation THEN
57
+ NULL;
58
+ WHEN undefined_object THEN
59
+ RAISE NOTICE 'Missing role when granting % to %', 'authenticated', 'administrator';
60
+ END;
61
+
62
+ BEGIN
63
+ EXECUTE format('GRANT %I TO %I', 'administrator', 'app_admin');
64
+ EXCEPTION
65
+ WHEN unique_violation THEN
66
+ NULL;
67
+ WHEN undefined_object THEN
68
+ RAISE NOTICE 'Missing role when granting % to %', 'administrator', 'app_admin';
69
+ END;
70
+ END
71
+ $do$;
72
+ COMMIT;
@@ -0,0 +1 @@
1
+ export declare const cleanSql: (sql: string, pretty: boolean, functionDelimiter: string) => Promise<string>;