@pgpmjs/core 7.1.0 → 7.2.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 (94) hide show
  1. package/bundle/apply.d.ts +93 -0
  2. package/bundle/apply.js +137 -0
  3. package/bundle/index.d.ts +12 -0
  4. package/bundle/index.js +31 -0
  5. package/core/class/pgpm.d.ts +2 -2
  6. package/core/class/pgpm.js +6 -6
  7. package/esm/bundle/apply.js +131 -0
  8. package/esm/bundle/index.js +15 -0
  9. package/esm/core/class/pgpm.js +6 -6
  10. package/esm/index.js +5 -3
  11. package/esm/migrate/client.js +1 -1
  12. package/esm/migrate/utils/hash.js +3 -6
  13. package/esm/modules/modules.js +1 -1
  14. package/esm/packaging/package.js +1 -1
  15. package/esm/rebundle/module.js +1 -1
  16. package/esm/rebundle/rebundle.js +2 -2
  17. package/esm/rebundle/workspace.js +1 -1
  18. package/esm/refactor/rename.js +5 -27
  19. package/esm/resolution/deps.js +2 -2
  20. package/esm/resolution/resolve.js +2 -2
  21. package/esm/slice/slice.js +1 -1
  22. package/index.d.ts +4 -2
  23. package/index.js +6 -4
  24. package/migrate/client.js +1 -1
  25. package/migrate/utils/hash.d.ts +2 -4
  26. package/migrate/utils/hash.js +4 -8
  27. package/modules/modules.d.ts +1 -1
  28. package/modules/modules.js +1 -1
  29. package/package.json +4 -2
  30. package/packaging/package.js +1 -1
  31. package/rebundle/module.js +1 -1
  32. package/rebundle/rebundle.js +2 -2
  33. package/rebundle/types.d.ts +1 -1
  34. package/rebundle/workspace.js +1 -1
  35. package/refactor/rename.d.ts +2 -8
  36. package/refactor/rename.js +6 -29
  37. package/resolution/deps.d.ts +1 -1
  38. package/resolution/deps.js +2 -2
  39. package/resolution/resolve.js +2 -2
  40. package/slice/slice.d.ts +1 -1
  41. package/slice/slice.js +1 -1
  42. package/slice/types.d.ts +1 -1
  43. package/workspace/minimal.d.ts +1 -1
  44. package/esm/files/extension/index.js +0 -3
  45. package/esm/files/extension/reader.js +0 -79
  46. package/esm/files/extension/writer.js +0 -99
  47. package/esm/files/index.js +0 -6
  48. package/esm/files/plan/generator.js +0 -82
  49. package/esm/files/plan/index.js +0 -5
  50. package/esm/files/plan/parser.js +0 -297
  51. package/esm/files/plan/validators.js +0 -181
  52. package/esm/files/plan/writer.js +0 -142
  53. package/esm/files/sql/header.js +0 -259
  54. package/esm/files/sql/index.js +0 -2
  55. package/esm/files/sql/writer.js +0 -107
  56. package/esm/files/sql-scripts/index.js +0 -2
  57. package/esm/files/sql-scripts/reader.js +0 -19
  58. package/esm/files/types/index.js +0 -1
  59. package/esm/files/types/package.js +0 -1
  60. package/esm/utils/author.js +0 -11
  61. package/files/extension/index.d.ts +0 -2
  62. package/files/extension/index.js +0 -19
  63. package/files/extension/reader.d.ts +0 -24
  64. package/files/extension/reader.js +0 -86
  65. package/files/extension/writer.d.ts +0 -48
  66. package/files/extension/writer.js +0 -107
  67. package/files/index.d.ts +0 -5
  68. package/files/index.js +0 -22
  69. package/files/plan/generator.d.ts +0 -23
  70. package/files/plan/generator.js +0 -90
  71. package/files/plan/index.d.ts +0 -4
  72. package/files/plan/index.js +0 -21
  73. package/files/plan/parser.d.ts +0 -28
  74. package/files/plan/parser.js +0 -304
  75. package/files/plan/validators.d.ts +0 -52
  76. package/files/plan/validators.js +0 -187
  77. package/files/plan/writer.d.ts +0 -27
  78. package/files/plan/writer.js +0 -152
  79. package/files/sql/header.d.ts +0 -114
  80. package/files/sql/header.js +0 -266
  81. package/files/sql/index.d.ts +0 -2
  82. package/files/sql/index.js +0 -18
  83. package/files/sql/writer.d.ts +0 -12
  84. package/files/sql/writer.js +0 -114
  85. package/files/sql-scripts/index.d.ts +0 -1
  86. package/files/sql-scripts/index.js +0 -18
  87. package/files/sql-scripts/reader.d.ts +0 -8
  88. package/files/sql-scripts/reader.js +0 -23
  89. package/files/types/index.d.ts +0 -46
  90. package/files/types/index.js +0 -17
  91. package/files/types/package.d.ts +0 -20
  92. package/files/types/package.js +0 -2
  93. package/utils/author.d.ts +0 -5
  94. package/utils/author.js +0 -14
@@ -0,0 +1,93 @@
1
+ import { PgConfig } from 'pg-env';
2
+ import { PgpmScriptKind } from '@pgpmjs/ast/module/types';
3
+ import { BundleIssue, MigrationBundle } from '@pgpmjs/bundle';
4
+ import { PgpmMigrateOptions } from '../migrate/client';
5
+ import { DeployResult, VerifyResult } from '../migrate/types';
6
+ /** A script whose SQL references something outside the allowed namespace. */
7
+ export interface NamespaceViolation {
8
+ change: string;
9
+ kind: PgpmScriptKind;
10
+ /** Offending references reported by the caller's validator. */
11
+ references: string[];
12
+ }
13
+ /**
14
+ * A validator for transpiled bundles: given a script's SQL, return the
15
+ * references that fall *outside* the target namespace (empty = clean). Core
16
+ * stays parser-agnostic; the caller (constructive-db) supplies the AST check.
17
+ */
18
+ export type ReferenceValidator = (sql: string, ctx: {
19
+ change: string;
20
+ kind: PgpmScriptKind;
21
+ }) => string[];
22
+ /** Pre-flight analysis of an apply, computed without touching the database. */
23
+ export interface ApplyBundlePreview {
24
+ name: string;
25
+ /** Changes in deploy order. */
26
+ deployOrder: string[];
27
+ /** Digest/order/integrity problems from {@link verifyBundle}. */
28
+ bundleIssues: BundleIssue[];
29
+ /** References outside the target namespace (only when a validator is given). */
30
+ namespaceViolations: NamespaceViolation[];
31
+ /** Reverse deploy order — the revert sequence that fully undoes this apply. */
32
+ rollbackPlan: string[];
33
+ }
34
+ export interface PreviewBundleApplyOptions {
35
+ validateReferences?: ReferenceValidator;
36
+ }
37
+ /**
38
+ * Analyze a bundle apply without executing it: verify artifact integrity, run
39
+ * the optional namespace-reference validator, and derive the rollback plan.
40
+ * Pure — no database, no disk.
41
+ */
42
+ export declare function previewBundleApply(bundle: MigrationBundle, options?: PreviewBundleApplyOptions): ApplyBundlePreview;
43
+ export interface ApplyBundleOptions extends PreviewBundleApplyOptions {
44
+ /** Target database. */
45
+ config: PgConfig;
46
+ /** Analyze only; never touch the database. Default false. */
47
+ dryRun?: boolean;
48
+ /** Run `verify` after a successful deploy. Default false. */
49
+ verify?: boolean;
50
+ /**
51
+ * Wall-clock budget for the deploy (+ optional verify). On expiry the result
52
+ * is flagged `timedOut` and a {@link BundleApplyError} is thrown. The apply
53
+ * runs in a single transaction (see `useTransaction`), so the database rolls
54
+ * back rather than being left half-applied.
55
+ */
56
+ timeoutMs?: number;
57
+ /** Apply as one atomic transaction so any failure rolls back. Default true. */
58
+ useTransaction?: boolean;
59
+ /** Directory to materialize into (default: a temp dir, removed afterward). */
60
+ workDir?: string;
61
+ migrateOptions?: PgpmMigrateOptions;
62
+ /** Apply even if artifact verification fails. Default false (refuse). */
63
+ allowUnverified?: boolean;
64
+ }
65
+ /** Explicit outcome of an {@link applyBundle} call. */
66
+ export interface ApplyBundleResult {
67
+ preview: ApplyBundlePreview;
68
+ dryRun: boolean;
69
+ /** True when the deploy actually ran against the database. */
70
+ executed: boolean;
71
+ deploy?: DeployResult;
72
+ verify?: VerifyResult;
73
+ durationMs: number;
74
+ timedOut: boolean;
75
+ }
76
+ /** Thrown when an apply is refused pre-flight or exceeds its timeout. */
77
+ export declare class BundleApplyError extends Error {
78
+ readonly preview: ApplyBundlePreview;
79
+ readonly timedOut: boolean;
80
+ constructor(message: string, preview: ApplyBundlePreview, timedOut?: boolean);
81
+ }
82
+ /**
83
+ * Safely apply a {@link MigrationBundle} to a target database.
84
+ *
85
+ * A thin, safety-first wrapper over {@link PgpmMigrate}: it gates on artifact
86
+ * integrity and (optionally) namespace validation, supports a dry run, applies
87
+ * atomically in a single transaction, enforces a timeout, and returns an
88
+ * explicit result including the rollback plan.
89
+ *
90
+ * The mechanics (materialize → deploy → verify) reuse existing plumbing;
91
+ * nothing here re-implements deployment.
92
+ */
93
+ export declare function applyBundle(bundle: MigrationBundle, options: ApplyBundleOptions): Promise<ApplyBundleResult>;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BundleApplyError = void 0;
4
+ exports.previewBundleApply = previewBundleApply;
5
+ exports.applyBundle = applyBundle;
6
+ const fs_1 = require("fs");
7
+ const os_1 = require("os");
8
+ const path_1 = require("path");
9
+ const bundle_1 = require("@pgpmjs/bundle");
10
+ const client_1 = require("../migrate/client");
11
+ /**
12
+ * Analyze a bundle apply without executing it: verify artifact integrity, run
13
+ * the optional namespace-reference validator, and derive the rollback plan.
14
+ * Pure — no database, no disk.
15
+ */
16
+ function previewBundleApply(bundle, options = {}) {
17
+ const namespaceViolations = [];
18
+ if (options.validateReferences) {
19
+ for (const change of bundle.changes) {
20
+ for (const script of [change.deploy, change.revert, change.verify]) {
21
+ if (!script)
22
+ continue;
23
+ const references = options.validateReferences(script.sql, {
24
+ change: change.name,
25
+ kind: script.kind
26
+ });
27
+ if (references.length > 0) {
28
+ namespaceViolations.push({ change: change.name, kind: script.kind, references });
29
+ }
30
+ }
31
+ }
32
+ }
33
+ return {
34
+ name: bundle.manifest.name,
35
+ deployOrder: [...bundle.manifest.deployOrder],
36
+ bundleIssues: (0, bundle_1.verifyBundle)(bundle),
37
+ namespaceViolations,
38
+ rollbackPlan: [...bundle.manifest.deployOrder].reverse()
39
+ };
40
+ }
41
+ /** Thrown when an apply is refused pre-flight or exceeds its timeout. */
42
+ class BundleApplyError extends Error {
43
+ preview;
44
+ timedOut;
45
+ constructor(message, preview, timedOut = false) {
46
+ super(message);
47
+ this.preview = preview;
48
+ this.timedOut = timedOut;
49
+ this.name = 'BundleApplyError';
50
+ }
51
+ }
52
+ exports.BundleApplyError = BundleApplyError;
53
+ const TIMEOUT = Symbol('timeout');
54
+ async function withTimeout(work, ms) {
55
+ if (!ms)
56
+ return work;
57
+ let timer;
58
+ const timeout = new Promise(resolve => {
59
+ timer = setTimeout(() => resolve(TIMEOUT), ms);
60
+ });
61
+ try {
62
+ return await Promise.race([work, timeout]);
63
+ }
64
+ finally {
65
+ clearTimeout(timer);
66
+ }
67
+ }
68
+ /**
69
+ * Safely apply a {@link MigrationBundle} to a target database.
70
+ *
71
+ * A thin, safety-first wrapper over {@link PgpmMigrate}: it gates on artifact
72
+ * integrity and (optionally) namespace validation, supports a dry run, applies
73
+ * atomically in a single transaction, enforces a timeout, and returns an
74
+ * explicit result including the rollback plan.
75
+ *
76
+ * The mechanics (materialize → deploy → verify) reuse existing plumbing;
77
+ * nothing here re-implements deployment.
78
+ */
79
+ async function applyBundle(bundle, options) {
80
+ const started = Date.now();
81
+ const preview = previewBundleApply(bundle, options);
82
+ if (!options.allowUnverified && preview.bundleIssues.length > 0) {
83
+ throw new BundleApplyError(`Refusing to apply "${preview.name}": bundle failed integrity verification ` +
84
+ `(${preview.bundleIssues.length} issue(s): ${preview.bundleIssues.map(i => i.kind).join(', ')})`, preview);
85
+ }
86
+ if (preview.namespaceViolations.length > 0) {
87
+ throw new BundleApplyError(`Refusing to apply "${preview.name}": ${preview.namespaceViolations.length} ` +
88
+ `reference(s) fall outside the target namespace`, preview);
89
+ }
90
+ if (options.dryRun) {
91
+ return {
92
+ preview,
93
+ dryRun: true,
94
+ executed: false,
95
+ durationMs: Date.now() - started,
96
+ timedOut: false
97
+ };
98
+ }
99
+ const ownWorkDir = options.workDir === undefined;
100
+ const workDir = options.workDir ?? (0, fs_1.mkdtempSync)((0, path_1.join)((0, os_1.tmpdir)(), 'pgpm-apply-'));
101
+ (0, bundle_1.materializeBundle)(bundle, workDir);
102
+ const migrate = new client_1.PgpmMigrate(options.config, options.migrateOptions);
103
+ const useTransaction = options.useTransaction ?? true;
104
+ try {
105
+ const run = (async () => {
106
+ const deploy = await migrate.deploy({ modulePath: workDir, useTransaction });
107
+ let verify;
108
+ if (options.verify) {
109
+ verify = await migrate.verify({ modulePath: workDir });
110
+ }
111
+ return { deploy, verify };
112
+ })();
113
+ const outcome = await withTimeout(run, options.timeoutMs);
114
+ if (outcome === TIMEOUT) {
115
+ throw new BundleApplyError(`Apply of "${preview.name}" exceeded ${options.timeoutMs}ms`, preview, true);
116
+ }
117
+ return {
118
+ preview,
119
+ dryRun: false,
120
+ executed: true,
121
+ deploy: outcome.deploy,
122
+ verify: outcome.verify,
123
+ durationMs: Date.now() - started,
124
+ timedOut: false
125
+ };
126
+ }
127
+ finally {
128
+ if (ownWorkDir) {
129
+ try {
130
+ (0, fs_1.rmSync)(workDir, { recursive: true, force: true });
131
+ }
132
+ catch {
133
+ // best-effort cleanup
134
+ }
135
+ }
136
+ }
137
+ }
@@ -0,0 +1,12 @@
1
+ /**
2
+ * pgpm migration bundles: the portable, content-addressed artifact layer.
3
+ *
4
+ * A {@link MigrationBundle} is a deterministic snapshot of a pgpm module — plan,
5
+ * control, ordered changes, and per-change/whole-bundle sha256 digests — with an
6
+ * optional provenance manifest. It is the substrate for the `exportMigrationBundle`
7
+ * / `applyMigrationBundle` / `transpileMigrationBundle` cloud functions: build one
8
+ * from a module AST, transport or transform it, verify its digests, then
9
+ * materialize it back into a deployable module.
10
+ */
11
+ export * from '@pgpmjs/bundle';
12
+ export * from './apply';
@@ -0,0 +1,31 @@
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
+ /**
18
+ * pgpm migration bundles: the portable, content-addressed artifact layer.
19
+ *
20
+ * A {@link MigrationBundle} is a deterministic snapshot of a pgpm module — plan,
21
+ * control, ordered changes, and per-change/whole-bundle sha256 digests — with an
22
+ * optional provenance manifest. It is the substrate for the `exportMigrationBundle`
23
+ * / `applyMigrationBundle` / `transpileMigrationBundle` cloud functions: build one
24
+ * from a module AST, transport or transform it, verify its digests, then
25
+ * materialize it back into a deployable module.
26
+ */
27
+ // Pure artifact layer moved to @pgpmjs/bundle; re-exported here so existing
28
+ // `@pgpmjs/core` consumers keep importing the whole bundle surface unchanged.
29
+ __exportStar(require("@pgpmjs/bundle"), exports);
30
+ // applyBundle stays in core: it drives PgpmMigrate (the deploy engine).
31
+ __exportStar(require("./apply"), exports);
@@ -1,7 +1,7 @@
1
1
  import { PgpmOptions, PgpmWorkspaceConfig } from '@pgpmjs/types';
2
2
  import { PgConfig } from 'pg-env';
3
- import { ExtensionInfo } from '../../files';
4
- import { PackageAnalysisResult, RenameOptions } from '../../files/types';
3
+ import { ExtensionInfo } from '@pgpmjs/ast/files';
4
+ import { PackageAnalysisResult, RenameOptions } from '@pgpmjs/ast/files/types';
5
5
  import { ModuleMap } from '../../modules/modules';
6
6
  export declare enum PackageContext {
7
7
  Outside = "outside",
@@ -49,12 +49,12 @@ const path_1 = __importStar(require("path"));
49
49
  const pg_cache_1 = require("pg-cache");
50
50
  const yanse_1 = __importDefault(require("yanse"));
51
51
  const extensions_1 = require("../../extensions/extensions");
52
- const files_1 = require("../../files");
53
- const files_2 = require("../../files");
54
- const writer_1 = require("../../files/extension/writer");
55
- const generator_1 = require("../../files/plan/generator");
56
- const parser_1 = require("../../files/plan/parser");
57
- const validators_1 = require("../../files/plan/validators");
52
+ const files_1 = require("@pgpmjs/ast/files");
53
+ const files_2 = require("@pgpmjs/ast/files");
54
+ const writer_1 = require("@pgpmjs/ast/files/extension/writer");
55
+ const generator_1 = require("@pgpmjs/ast/files/plan/generator");
56
+ const parser_1 = require("@pgpmjs/ast/files/plan/parser");
57
+ const validators_1 = require("@pgpmjs/ast/files/plan/validators");
58
58
  const client_1 = require("../../migrate/client");
59
59
  const modules_1 = require("../../modules/modules");
60
60
  const package_1 = require("../../packaging/package");
@@ -0,0 +1,131 @@
1
+ import { mkdtempSync, rmSync } from 'fs';
2
+ import { tmpdir } from 'os';
3
+ import { join } from 'path';
4
+ import { materializeBundle, verifyBundle } from '@pgpmjs/bundle';
5
+ import { PgpmMigrate } from '../migrate/client';
6
+ /**
7
+ * Analyze a bundle apply without executing it: verify artifact integrity, run
8
+ * the optional namespace-reference validator, and derive the rollback plan.
9
+ * Pure — no database, no disk.
10
+ */
11
+ export function previewBundleApply(bundle, options = {}) {
12
+ const namespaceViolations = [];
13
+ if (options.validateReferences) {
14
+ for (const change of bundle.changes) {
15
+ for (const script of [change.deploy, change.revert, change.verify]) {
16
+ if (!script)
17
+ continue;
18
+ const references = options.validateReferences(script.sql, {
19
+ change: change.name,
20
+ kind: script.kind
21
+ });
22
+ if (references.length > 0) {
23
+ namespaceViolations.push({ change: change.name, kind: script.kind, references });
24
+ }
25
+ }
26
+ }
27
+ }
28
+ return {
29
+ name: bundle.manifest.name,
30
+ deployOrder: [...bundle.manifest.deployOrder],
31
+ bundleIssues: verifyBundle(bundle),
32
+ namespaceViolations,
33
+ rollbackPlan: [...bundle.manifest.deployOrder].reverse()
34
+ };
35
+ }
36
+ /** Thrown when an apply is refused pre-flight or exceeds its timeout. */
37
+ export class BundleApplyError extends Error {
38
+ preview;
39
+ timedOut;
40
+ constructor(message, preview, timedOut = false) {
41
+ super(message);
42
+ this.preview = preview;
43
+ this.timedOut = timedOut;
44
+ this.name = 'BundleApplyError';
45
+ }
46
+ }
47
+ const TIMEOUT = Symbol('timeout');
48
+ async function withTimeout(work, ms) {
49
+ if (!ms)
50
+ return work;
51
+ let timer;
52
+ const timeout = new Promise(resolve => {
53
+ timer = setTimeout(() => resolve(TIMEOUT), ms);
54
+ });
55
+ try {
56
+ return await Promise.race([work, timeout]);
57
+ }
58
+ finally {
59
+ clearTimeout(timer);
60
+ }
61
+ }
62
+ /**
63
+ * Safely apply a {@link MigrationBundle} to a target database.
64
+ *
65
+ * A thin, safety-first wrapper over {@link PgpmMigrate}: it gates on artifact
66
+ * integrity and (optionally) namespace validation, supports a dry run, applies
67
+ * atomically in a single transaction, enforces a timeout, and returns an
68
+ * explicit result including the rollback plan.
69
+ *
70
+ * The mechanics (materialize → deploy → verify) reuse existing plumbing;
71
+ * nothing here re-implements deployment.
72
+ */
73
+ export async function applyBundle(bundle, options) {
74
+ const started = Date.now();
75
+ const preview = previewBundleApply(bundle, options);
76
+ if (!options.allowUnverified && preview.bundleIssues.length > 0) {
77
+ throw new BundleApplyError(`Refusing to apply "${preview.name}": bundle failed integrity verification ` +
78
+ `(${preview.bundleIssues.length} issue(s): ${preview.bundleIssues.map(i => i.kind).join(', ')})`, preview);
79
+ }
80
+ if (preview.namespaceViolations.length > 0) {
81
+ throw new BundleApplyError(`Refusing to apply "${preview.name}": ${preview.namespaceViolations.length} ` +
82
+ `reference(s) fall outside the target namespace`, preview);
83
+ }
84
+ if (options.dryRun) {
85
+ return {
86
+ preview,
87
+ dryRun: true,
88
+ executed: false,
89
+ durationMs: Date.now() - started,
90
+ timedOut: false
91
+ };
92
+ }
93
+ const ownWorkDir = options.workDir === undefined;
94
+ const workDir = options.workDir ?? mkdtempSync(join(tmpdir(), 'pgpm-apply-'));
95
+ materializeBundle(bundle, workDir);
96
+ const migrate = new PgpmMigrate(options.config, options.migrateOptions);
97
+ const useTransaction = options.useTransaction ?? true;
98
+ try {
99
+ const run = (async () => {
100
+ const deploy = await migrate.deploy({ modulePath: workDir, useTransaction });
101
+ let verify;
102
+ if (options.verify) {
103
+ verify = await migrate.verify({ modulePath: workDir });
104
+ }
105
+ return { deploy, verify };
106
+ })();
107
+ const outcome = await withTimeout(run, options.timeoutMs);
108
+ if (outcome === TIMEOUT) {
109
+ throw new BundleApplyError(`Apply of "${preview.name}" exceeded ${options.timeoutMs}ms`, preview, true);
110
+ }
111
+ return {
112
+ preview,
113
+ dryRun: false,
114
+ executed: true,
115
+ deploy: outcome.deploy,
116
+ verify: outcome.verify,
117
+ durationMs: Date.now() - started,
118
+ timedOut: false
119
+ };
120
+ }
121
+ finally {
122
+ if (ownWorkDir) {
123
+ try {
124
+ rmSync(workDir, { recursive: true, force: true });
125
+ }
126
+ catch {
127
+ // best-effort cleanup
128
+ }
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,15 @@
1
+ /**
2
+ * pgpm migration bundles: the portable, content-addressed artifact layer.
3
+ *
4
+ * A {@link MigrationBundle} is a deterministic snapshot of a pgpm module — plan,
5
+ * control, ordered changes, and per-change/whole-bundle sha256 digests — with an
6
+ * optional provenance manifest. It is the substrate for the `exportMigrationBundle`
7
+ * / `applyMigrationBundle` / `transpileMigrationBundle` cloud functions: build one
8
+ * from a module AST, transport or transform it, verify its digests, then
9
+ * materialize it back into a deployable module.
10
+ */
11
+ // Pure artifact layer moved to @pgpmjs/bundle; re-exported here so existing
12
+ // `@pgpmjs/core` consumers keep importing the whole bundle surface unchanged.
13
+ export * from '@pgpmjs/bundle';
14
+ // applyBundle stays in core: it drives PgpmMigrate (the deploy engine).
15
+ export * from './apply';
@@ -10,12 +10,12 @@ import path, { dirname, resolve } from 'path';
10
10
  import { getPgPool } from 'pg-cache';
11
11
  import yanse from 'yanse';
12
12
  import { getAvailableExtensions } from '../../extensions/extensions';
13
- import { generatePlan, writePlan, writePlanFile } from '../../files';
14
- import { getExtensionInfo, getExtensionName, getInstalledExtensions, parseControlFile, writeExtensions } from '../../files';
15
- import { generateControlFileContent, writeExtensionMakefile } from '../../files/extension/writer';
16
- import { getNow as getPlanTimestamp } from '../../files/plan/generator';
17
- import { parsePlanFile } from '../../files/plan/parser';
18
- import { isValidChangeName, isValidTagName, parseReference } from '../../files/plan/validators';
13
+ import { generatePlan, writePlan, writePlanFile } from '@pgpmjs/ast/files';
14
+ import { getExtensionInfo, getExtensionName, getInstalledExtensions, parseControlFile, writeExtensions } from '@pgpmjs/ast/files';
15
+ import { generateControlFileContent, writeExtensionMakefile } from '@pgpmjs/ast/files/extension/writer';
16
+ import { getNow as getPlanTimestamp } from '@pgpmjs/ast/files/plan/generator';
17
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
18
+ import { isValidChangeName, isValidTagName, parseReference } from '@pgpmjs/ast/files/plan/validators';
19
19
  import { PgpmMigrate } from '../../migrate/client';
20
20
  import { getExtensionsAndModules, getExtensionsAndModulesChanges, latestChange, latestChangeAndVersion } from '../../modules/modules';
21
21
  import { packageModule } from '../../packaging/package';
package/esm/index.js CHANGED
@@ -13,13 +13,15 @@ export * from './workspace/minimal';
13
13
  export * from './core/template-scaffold';
14
14
  export * from './core/boilerplate-types';
15
15
  export * from './core/boilerplate-scanner';
16
- // Export package-files functionality (now integrated into core)
17
- export * from './files';
16
+ // Re-export the module AST layer (moved to the @pgpmjs/ast leaf package)
17
+ export * from '@pgpmjs/ast/files';
18
+ export * from '@pgpmjs/ast/module';
19
+ export * from './bundle';
18
20
  export * from './refactor';
19
21
  export { cleanSql } from './migrate/clean';
20
22
  export { PgpmMigrate } from './migrate/client';
21
23
  export { PgpmInit } from './init/client';
22
24
  export * from './roles';
23
- export { parseAuthor } from './utils/author';
25
+ export { parseAuthor } from '@pgpmjs/ast';
24
26
  export { hashFile, hashString } from './migrate/utils/hash';
25
27
  export { executeQuery, withTransaction } from './migrate/utils/transaction';
@@ -3,7 +3,7 @@ import { errors, extractPgErrorFields, formatPgError, formatPgErrorFields } from
3
3
  import { readFileSync } from 'fs';
4
4
  import { dirname, join } from 'path';
5
5
  import { getPgPool } from 'pg-cache';
6
- import { parsePlanFile, parsePlanFileSimple, readScript } from '../files';
6
+ import { parsePlanFile, parsePlanFileSimple, readScript } from '@pgpmjs/ast/files';
7
7
  import { resolveDependencies } from '../resolution/deps';
8
8
  import { resolveTagToChangeName } from '../resolution/resolve';
9
9
  import { cleanSql } from './clean';
@@ -1,7 +1,10 @@
1
+ import { hashString } from '@pgpmjs/ast';
1
2
  import { createHash } from 'crypto';
2
3
  import { readFile } from 'fs/promises';
3
4
  import { parse } from 'pgsql-parser';
4
5
  import { cleanTree } from '../../packaging/package';
6
+ // Re-exported from @pgpmjs/ast so existing `@pgpmjs/core` consumers keep importing it here.
7
+ export { hashString };
5
8
  /**
6
9
  * Generate SHA256 hash of a file's contents
7
10
  */
@@ -9,12 +12,6 @@ export async function hashFile(filePath) {
9
12
  const content = await readFile(filePath, 'utf-8');
10
13
  return createHash('sha256').update(content).digest('hex');
11
14
  }
12
- /**
13
- * Generate SHA256 hash of a string
14
- */
15
- export function hashString(content) {
16
- return createHash('sha256').update(content).digest('hex');
17
- }
18
15
  /**
19
16
  * Generate SHA256 hash of a SQL file's parsed and cleaned AST
20
17
  */
@@ -1,4 +1,4 @@
1
- import { getLatestChange } from '../files';
1
+ import { getLatestChange } from '@pgpmjs/ast/files';
2
2
  import { errors } from '@pgpmjs/types';
3
3
  /**
4
4
  * Mapping from control file names (used in extensions list) to npm package names.
@@ -3,7 +3,7 @@ import { mkdirSync, readFileSync, rmSync, writeFileSync } from 'fs';
3
3
  import { relative } from 'path';
4
4
  import { deparse } from 'pgsql-deparser';
5
5
  import { parse } from 'pgsql-parser';
6
- import { getExtensionName } from '../files';
6
+ import { getExtensionName } from '@pgpmjs/ast/files';
7
7
  import { resolve, resolveWithPlan } from '../resolution/resolve';
8
8
  import { transformProps } from './transform';
9
9
  const log = new Logger('package');
@@ -1,6 +1,6 @@
1
1
  import { copyFileSync, existsSync, mkdirSync, readdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
- import { parsePlanFile } from '../files/plan/parser';
3
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
4
4
  import { mergeSqlStatements, packageModule } from '../packaging/package';
5
5
  import { generatePlanContent } from '../slice/slice';
6
6
  import { assembleChunkSql, rebundlePlan } from './rebundle';
@@ -1,9 +1,9 @@
1
1
  import { readFileSync } from 'fs';
2
2
  import { join } from 'path';
3
- import { getChanges } from '../files/plan/parser';
3
+ import { getChanges } from '@pgpmjs/ast/files/plan/parser';
4
4
  import { resolveWithPlan } from '../resolution/resolve';
5
5
  import { buildDependencyGraph, buildPackageDependencies, computeDeployOrder, detectPackageCycle, extractPackageFromPath, } from '../slice/slice';
6
- import { parsePlanFile } from '../files/plan/parser';
6
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
7
7
  /**
8
8
  * Derive the boundary key for a change under the given strategy.
9
9
  * Consecutive changes sharing a key may be merged into the same chunk.
@@ -1,7 +1,7 @@
1
1
  import { existsSync, readdirSync, readFileSync } from 'fs';
2
2
  import { basename, join } from 'path';
3
3
  import { DEFAULT_TEMPLATE_REPO, scaffoldTemplate } from '../core/template-scaffold';
4
- import { parsePlanFile } from '../files/plan/parser';
4
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
5
5
  import { mergeSqlStatements } from '../packaging/package';
6
6
  import { resolveWithPlan } from '../resolution/resolve';
7
7
  import { writeMinimalModule, writeMinimalWorkspace } from '../workspace/minimal';
@@ -1,7 +1,10 @@
1
1
  import { existsSync, mkdirSync, readdirSync, readFileSync, renameSync, rmdirSync, statSync, writeFileSync } from 'fs';
2
2
  import { dirname, join, relative, sep } from 'path';
3
- import { parsePlanFileSimple } from '../files/plan/parser';
4
- import { parsePgpmHeader, renameInHeader, writePgpmScript } from '../files/sql/header';
3
+ import { parsePlanFileSimple } from '@pgpmjs/ast/files/plan/parser';
4
+ import { parsePgpmHeader, renameInHeader, writePgpmScript } from '@pgpmjs/ast/files/sql/header';
5
+ import { renameInPlanContent } from '@pgpmjs/ast/plan-rename';
6
+ // Re-exported from @pgpmjs/ast so existing `@pgpmjs/core` consumers keep importing it here.
7
+ export { renameInPlanContent };
5
8
  const SCRIPT_DIRS = ['deploy', 'revert', 'verify'];
6
9
  function escapeRe(str) {
7
10
  return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
@@ -59,31 +62,6 @@ export function validateRenames(moduleDir, renames) {
59
62
  targets.add(to);
60
63
  }
61
64
  }
62
- /**
63
- * Rewrite change names in a pgpm.plan's content according to a rename map.
64
- * Textual and format-preserving: only the change-name token at the start of a
65
- * change line, plain (same-package) dependency refs inside `[...]`, and tag
66
- * lines' change field are rewritten; timestamps, planners, comments,
67
- * cross-package refs, and tag refs are untouched.
68
- */
69
- export function renameInPlanContent(content, renames) {
70
- const froms = Array.from(renames.keys()).sort((a, b) => b.length - a.length);
71
- return content
72
- .split('\n')
73
- .map(line => {
74
- const trimmed = line.trim();
75
- if (!trimmed || trimmed.startsWith('#') || trimmed.startsWith('%'))
76
- return line;
77
- let result = line;
78
- for (const from of froms) {
79
- const to = renames.get(from);
80
- const re = new RegExp(`(^|[\\s\\[])${escapeRe(from)}(?=$|[\\s\\]@])`, 'g');
81
- result = result.replace(re, `$1${to}`);
82
- }
83
- return result;
84
- })
85
- .join('\n');
86
- }
87
65
  /**
88
66
  * Atomically rename/move changes within a pgpm module: the coupled 4-way
89
67
  * rewrite of (1) deploy/revert/verify script files on disk, (2) the moved
@@ -2,8 +2,8 @@ import { readFileSync } from 'fs';
2
2
  import { sync as glob } from 'glob';
3
3
  import { join, relative } from 'path';
4
4
  import { PgpmPackage } from '../core/class/pgpm';
5
- import { parsePlanFile } from '../files/plan/parser';
6
- import { scanDeployScript } from '../files/sql/header';
5
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
6
+ import { scanDeployScript } from '@pgpmjs/ast/files/sql/header';
7
7
  import { errors } from '@pgpmjs/types';
8
8
  /**
9
9
  * Core dependency resolution algorithm that handles circular dependency detection
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'fs';
2
- import { getChanges, getExtensionName } from '../files';
3
- import { parsePlanFile } from '../files/plan/parser';
2
+ import { getChanges, getExtensionName } from '@pgpmjs/ast/files';
3
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
4
4
  import { resolveDependencies } from './deps';
5
5
  import { errors } from '@pgpmjs/types';
6
6
  /**
@@ -1,4 +1,4 @@
1
- import { parsePlanFile } from '../files/plan/parser';
1
+ import { parsePlanFile } from '@pgpmjs/ast/files/plan/parser';
2
2
  import { minimatch } from 'minimatch';
3
3
  /**
4
4
  * Build a dependency graph from a parsed plan file