@plumbus/core 0.2.9 → 0.3.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 (176) hide show
  1. package/dist/.tsbuildinfo +1 -1
  2. package/dist/ai/__tests__/ai-service.test.js +704 -1
  3. package/dist/ai/__tests__/ai-service.test.js.map +1 -1
  4. package/dist/ai/__tests__/chunking.test.js +34 -0
  5. package/dist/ai/__tests__/chunking.test.js.map +1 -1
  6. package/dist/ai/__tests__/provider.test.d.ts.map +1 -1
  7. package/dist/ai/__tests__/provider.test.js +425 -0
  8. package/dist/ai/__tests__/provider.test.js.map +1 -1
  9. package/dist/ai/__tests__/validation.test.js +200 -1
  10. package/dist/ai/__tests__/validation.test.js.map +1 -1
  11. package/dist/ai/__tests__/zod-to-provider-schema.test.d.ts +2 -0
  12. package/dist/ai/__tests__/zod-to-provider-schema.test.d.ts.map +1 -0
  13. package/dist/ai/__tests__/zod-to-provider-schema.test.js +60 -0
  14. package/dist/ai/__tests__/zod-to-provider-schema.test.js.map +1 -0
  15. package/dist/ai/ai-service.d.ts +19 -2
  16. package/dist/ai/ai-service.d.ts.map +1 -1
  17. package/dist/ai/ai-service.js +544 -110
  18. package/dist/ai/ai-service.js.map +1 -1
  19. package/dist/ai/cost-tracker.d.ts +26 -1
  20. package/dist/ai/cost-tracker.d.ts.map +1 -1
  21. package/dist/ai/cost-tracker.js +1 -0
  22. package/dist/ai/cost-tracker.js.map +1 -1
  23. package/dist/ai/index.d.ts +5 -3
  24. package/dist/ai/index.d.ts.map +1 -1
  25. package/dist/ai/index.js +5 -1
  26. package/dist/ai/index.js.map +1 -1
  27. package/dist/ai/provider.d.ts +45 -1
  28. package/dist/ai/provider.d.ts.map +1 -1
  29. package/dist/ai/provider.js +226 -32
  30. package/dist/ai/provider.js.map +1 -1
  31. package/dist/ai/rag/chunking.js +53 -3
  32. package/dist/ai/rag/chunking.js.map +1 -1
  33. package/dist/ai/refusal.d.ts +28 -0
  34. package/dist/ai/refusal.d.ts.map +1 -0
  35. package/dist/ai/refusal.js +36 -0
  36. package/dist/ai/refusal.js.map +1 -0
  37. package/dist/ai/validation.d.ts +40 -8
  38. package/dist/ai/validation.d.ts.map +1 -1
  39. package/dist/ai/validation.js +97 -6
  40. package/dist/ai/validation.js.map +1 -1
  41. package/dist/ai/zod-to-provider-schema.d.ts +15 -0
  42. package/dist/ai/zod-to-provider-schema.d.ts.map +1 -0
  43. package/dist/ai/zod-to-provider-schema.js +200 -0
  44. package/dist/ai/zod-to-provider-schema.js.map +1 -0
  45. package/dist/cli/__tests__/doctor.test.js +104 -2
  46. package/dist/cli/__tests__/doctor.test.js.map +1 -1
  47. package/dist/cli/__tests__/init.test.js +127 -7
  48. package/dist/cli/__tests__/init.test.js.map +1 -1
  49. package/dist/cli/__tests__/migrate.test.js +159 -2
  50. package/dist/cli/__tests__/migrate.test.js.map +1 -1
  51. package/dist/cli/commands/__tests__/commands.test.js +5 -0
  52. package/dist/cli/commands/__tests__/commands.test.js.map +1 -1
  53. package/dist/cli/commands/dev.d.ts.map +1 -1
  54. package/dist/cli/commands/dev.js +21 -1
  55. package/dist/cli/commands/dev.js.map +1 -1
  56. package/dist/cli/commands/doctor.d.ts +2 -0
  57. package/dist/cli/commands/doctor.d.ts.map +1 -1
  58. package/dist/cli/commands/doctor.js +78 -0
  59. package/dist/cli/commands/doctor.js.map +1 -1
  60. package/dist/cli/commands/generate.d.ts.map +1 -1
  61. package/dist/cli/commands/generate.js +7 -2
  62. package/dist/cli/commands/generate.js.map +1 -1
  63. package/dist/cli/commands/init.d.ts +16 -2
  64. package/dist/cli/commands/init.d.ts.map +1 -1
  65. package/dist/cli/commands/init.js +226 -25
  66. package/dist/cli/commands/init.js.map +1 -1
  67. package/dist/cli/commands/migrate.d.ts.map +1 -1
  68. package/dist/cli/commands/migrate.js +258 -8
  69. package/dist/cli/commands/migrate.js.map +1 -1
  70. package/dist/cli/commands/start.d.ts.map +1 -1
  71. package/dist/cli/commands/start.js +21 -1
  72. package/dist/cli/commands/start.js.map +1 -1
  73. package/dist/data/__tests__/drift-inspector.test.d.ts +2 -0
  74. package/dist/data/__tests__/drift-inspector.test.d.ts.map +1 -0
  75. package/dist/data/__tests__/drift-inspector.test.js +170 -0
  76. package/dist/data/__tests__/drift-inspector.test.js.map +1 -0
  77. package/dist/data/__tests__/framework-migration-rewriter.test.d.ts +2 -0
  78. package/dist/data/__tests__/framework-migration-rewriter.test.d.ts.map +1 -0
  79. package/dist/data/__tests__/framework-migration-rewriter.test.js +329 -0
  80. package/dist/data/__tests__/framework-migration-rewriter.test.js.map +1 -0
  81. package/dist/data/__tests__/migration.test.js +93 -2
  82. package/dist/data/__tests__/migration.test.js.map +1 -1
  83. package/dist/data/__tests__/repository.test.js +126 -0
  84. package/dist/data/__tests__/repository.test.js.map +1 -1
  85. package/dist/data/drift-inspector.d.ts +41 -0
  86. package/dist/data/drift-inspector.d.ts.map +1 -0
  87. package/dist/data/drift-inspector.js +197 -0
  88. package/dist/data/drift-inspector.js.map +1 -0
  89. package/dist/data/framework-migration-rewriter.d.ts +61 -0
  90. package/dist/data/framework-migration-rewriter.d.ts.map +1 -0
  91. package/dist/data/framework-migration-rewriter.js +357 -0
  92. package/dist/data/framework-migration-rewriter.js.map +1 -0
  93. package/dist/data/index.d.ts +2 -1
  94. package/dist/data/index.d.ts.map +1 -1
  95. package/dist/data/index.js +2 -1
  96. package/dist/data/index.js.map +1 -1
  97. package/dist/data/migration.d.ts +31 -1
  98. package/dist/data/migration.d.ts.map +1 -1
  99. package/dist/data/migration.js +113 -3
  100. package/dist/data/migration.js.map +1 -1
  101. package/dist/data/repository.d.ts.map +1 -1
  102. package/dist/data/repository.js +21 -0
  103. package/dist/data/repository.js.map +1 -1
  104. package/dist/define/__tests__/definePrompt.test.js +37 -0
  105. package/dist/define/__tests__/definePrompt.test.js.map +1 -1
  106. package/dist/define/definePrompt.d.ts +13 -0
  107. package/dist/define/definePrompt.d.ts.map +1 -1
  108. package/dist/define/definePrompt.js +3 -0
  109. package/dist/define/definePrompt.js.map +1 -1
  110. package/dist/errors/http.d.ts.map +1 -1
  111. package/dist/errors/http.js +2 -0
  112. package/dist/errors/http.js.map +1 -1
  113. package/dist/errors/index.d.ts +12 -0
  114. package/dist/errors/index.d.ts.map +1 -1
  115. package/dist/errors/index.js +21 -0
  116. package/dist/errors/index.js.map +1 -1
  117. package/dist/events/__tests__/event-emitter.test.js +72 -0
  118. package/dist/events/__tests__/event-emitter.test.js.map +1 -1
  119. package/dist/events/emitter.d.ts.map +1 -1
  120. package/dist/events/emitter.js +51 -0
  121. package/dist/events/emitter.js.map +1 -1
  122. package/dist/execution/__tests__/context-factory.test.js +1 -0
  123. package/dist/execution/__tests__/context-factory.test.js.map +1 -1
  124. package/dist/execution/context-factory.d.ts.map +1 -1
  125. package/dist/execution/context-factory.js +2 -0
  126. package/dist/execution/context-factory.js.map +1 -1
  127. package/dist/flows/__tests__/flow-engine.test.js +451 -4
  128. package/dist/flows/__tests__/flow-engine.test.js.map +1 -1
  129. package/dist/flows/__tests__/flow-service.test.js +8 -0
  130. package/dist/flows/__tests__/flow-service.test.js.map +1 -1
  131. package/dist/flows/__tests__/step-executor.test.js +8 -2
  132. package/dist/flows/__tests__/step-executor.test.js.map +1 -1
  133. package/dist/flows/engine.d.ts +50 -1
  134. package/dist/flows/engine.d.ts.map +1 -1
  135. package/dist/flows/engine.js +427 -23
  136. package/dist/flows/engine.js.map +1 -1
  137. package/dist/flows/flow-service.d.ts.map +1 -1
  138. package/dist/flows/flow-service.js +4 -0
  139. package/dist/flows/flow-service.js.map +1 -1
  140. package/dist/flows/index.d.ts +1 -1
  141. package/dist/flows/index.d.ts.map +1 -1
  142. package/dist/flows/index.js +1 -1
  143. package/dist/flows/index.js.map +1 -1
  144. package/dist/flows/schema.d.ts +34 -0
  145. package/dist/flows/schema.d.ts.map +1 -1
  146. package/dist/flows/schema.js +3 -0
  147. package/dist/flows/schema.js.map +1 -1
  148. package/dist/index.d.ts +4 -4
  149. package/dist/index.d.ts.map +1 -1
  150. package/dist/index.js +3 -3
  151. package/dist/index.js.map +1 -1
  152. package/dist/server/bootstrap.d.ts +14 -0
  153. package/dist/server/bootstrap.d.ts.map +1 -1
  154. package/dist/server/bootstrap.js +23 -4
  155. package/dist/server/bootstrap.js.map +1 -1
  156. package/dist/testing/context.d.ts.map +1 -1
  157. package/dist/testing/context.js +37 -1
  158. package/dist/testing/context.js.map +1 -1
  159. package/dist/types/context.d.ts +110 -0
  160. package/dist/types/context.d.ts.map +1 -1
  161. package/dist/types/enums.d.ts +2 -0
  162. package/dist/types/enums.d.ts.map +1 -1
  163. package/dist/types/enums.js +2 -0
  164. package/dist/types/enums.js.map +1 -1
  165. package/dist/types/prompt.d.ts +64 -0
  166. package/dist/types/prompt.d.ts.map +1 -1
  167. package/dist/worker/__tests__/bootstrap.test.js +36 -2
  168. package/dist/worker/__tests__/bootstrap.test.js.map +1 -1
  169. package/dist/worker/bootstrap.d.ts +7 -0
  170. package/dist/worker/bootstrap.d.ts.map +1 -1
  171. package/dist/worker/bootstrap.js +153 -12
  172. package/dist/worker/bootstrap.js.map +1 -1
  173. package/instructions/framework.md +7 -0
  174. package/instructions/guardrails.md +39 -0
  175. package/instructions/patterns.md +10 -0
  176. package/package.json +3 -2
@@ -0,0 +1,170 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { extractCreateTableNames, FRAMEWORK_TABLE_NAMES, formatDriftReport, } from '../drift-inspector.js';
3
+ describe('FRAMEWORK_TABLE_NAMES', () => {
4
+ it('contains all 9 framework table names', () => {
5
+ expect(FRAMEWORK_TABLE_NAMES).toHaveLength(9);
6
+ });
7
+ it('includes expected table names', () => {
8
+ expect(FRAMEWORK_TABLE_NAMES).toContain('audit_records');
9
+ expect(FRAMEWORK_TABLE_NAMES).toContain('event_outbox');
10
+ expect(FRAMEWORK_TABLE_NAMES).toContain('event_idempotency');
11
+ expect(FRAMEWORK_TABLE_NAMES).toContain('event_dead_letter');
12
+ expect(FRAMEWORK_TABLE_NAMES).toContain('flow_executions');
13
+ expect(FRAMEWORK_TABLE_NAMES).toContain('flow_dead_letter');
14
+ expect(FRAMEWORK_TABLE_NAMES).toContain('flow_schedules');
15
+ expect(FRAMEWORK_TABLE_NAMES).toContain('documents');
16
+ expect(FRAMEWORK_TABLE_NAMES).toContain('document_chunks');
17
+ });
18
+ });
19
+ describe('extractCreateTableNames', () => {
20
+ it('extracts quoted table names', () => {
21
+ const sql = 'CREATE TABLE "event_outbox" ("id" uuid PRIMARY KEY);';
22
+ expect(extractCreateTableNames(sql)).toEqual(['event_outbox']);
23
+ });
24
+ it('extracts unquoted table names', () => {
25
+ const sql = 'CREATE TABLE flow_executions (id uuid PRIMARY KEY);';
26
+ expect(extractCreateTableNames(sql)).toEqual(['flow_executions']);
27
+ });
28
+ it('extracts multiple CREATE TABLE statements', () => {
29
+ const sql = [
30
+ 'CREATE TABLE "event_outbox" ("id" uuid PRIMARY KEY);',
31
+ '--> statement-breakpoint',
32
+ 'CREATE TABLE "flow_executions" ("id" uuid PRIMARY KEY);',
33
+ ].join('\n');
34
+ expect(extractCreateTableNames(sql)).toEqual(['event_outbox', 'flow_executions']);
35
+ });
36
+ it('handles IF NOT EXISTS syntax', () => {
37
+ const sql = 'CREATE TABLE IF NOT EXISTS "audit_records" ("id" uuid PRIMARY KEY);';
38
+ expect(extractCreateTableNames(sql)).toEqual(['audit_records']);
39
+ });
40
+ it('returns empty for SQL without CREATE TABLE', () => {
41
+ const sql = 'ALTER TABLE "event_outbox" ADD COLUMN "new_col" text;';
42
+ expect(extractCreateTableNames(sql)).toEqual([]);
43
+ });
44
+ it('handles mixed case CREATE TABLE keywords', () => {
45
+ const sql = 'create table "documents" ("id" varchar PRIMARY KEY);';
46
+ expect(extractCreateTableNames(sql)).toEqual(['documents']);
47
+ });
48
+ it('handles extra whitespace in CREATE TABLE', () => {
49
+ const sql = 'CREATE TABLE "event_outbox" ("id" uuid);';
50
+ expect(extractCreateTableNames(sql)).toEqual(['event_outbox']);
51
+ });
52
+ });
53
+ describe('formatDriftReport', () => {
54
+ it('lists pre-existing framework tables', () => {
55
+ const report = {
56
+ hasDrift: false,
57
+ existingFrameworkTables: ['event_outbox', 'flow_executions'],
58
+ missingFrameworkTables: [],
59
+ tables: [
60
+ { tableName: 'event_outbox', exists: true, columnDrifts: [] },
61
+ { tableName: 'flow_executions', exists: true, columnDrifts: [] },
62
+ ],
63
+ };
64
+ const lines = formatDriftReport(report);
65
+ expect(lines[0]).toContain('event_outbox');
66
+ expect(lines[0]).toContain('flow_executions');
67
+ });
68
+ it('reports missing columns', () => {
69
+ const report = {
70
+ hasDrift: true,
71
+ existingFrameworkTables: ['event_outbox'],
72
+ missingFrameworkTables: [],
73
+ tables: [
74
+ {
75
+ tableName: 'event_outbox',
76
+ exists: true,
77
+ columnDrifts: [{ column: 'correlation_id', kind: 'missing_in_db', expected: 'text' }],
78
+ },
79
+ ],
80
+ };
81
+ const output = formatDriftReport(report).join('\n');
82
+ expect(output).toContain('correlation_id');
83
+ expect(output).toContain('missing');
84
+ });
85
+ it('reports type mismatches', () => {
86
+ const report = {
87
+ hasDrift: true,
88
+ existingFrameworkTables: ['event_outbox'],
89
+ missingFrameworkTables: [],
90
+ tables: [
91
+ {
92
+ tableName: 'event_outbox',
93
+ exists: true,
94
+ columnDrifts: [
95
+ {
96
+ column: 'retry_count',
97
+ kind: 'type_mismatch',
98
+ expected: 'text',
99
+ actual: 'integer',
100
+ },
101
+ ],
102
+ },
103
+ ],
104
+ };
105
+ const output = formatDriftReport(report).join('\n');
106
+ expect(output).toContain('retry_count');
107
+ expect(output).toContain('type mismatch');
108
+ expect(output).toContain('text');
109
+ expect(output).toContain('integer');
110
+ });
111
+ it('reports extra columns in DB', () => {
112
+ const report = {
113
+ hasDrift: true,
114
+ existingFrameworkTables: ['event_outbox'],
115
+ missingFrameworkTables: [],
116
+ tables: [
117
+ {
118
+ tableName: 'event_outbox',
119
+ exists: true,
120
+ columnDrifts: [{ column: 'extra_col', kind: 'extra_in_db', actual: 'text' }],
121
+ },
122
+ ],
123
+ };
124
+ const output = formatDriftReport(report).join('\n');
125
+ expect(output).toContain('extra_col');
126
+ expect(output).toContain('exists in DB but not in schema');
127
+ });
128
+ it('includes recovery instructions', () => {
129
+ const report = {
130
+ hasDrift: true,
131
+ existingFrameworkTables: ['event_outbox'],
132
+ missingFrameworkTables: [],
133
+ tables: [
134
+ {
135
+ tableName: 'event_outbox',
136
+ exists: true,
137
+ columnDrifts: [{ column: 'x', kind: 'missing_in_db', expected: 'text' }],
138
+ },
139
+ ],
140
+ };
141
+ const output = formatDriftReport(report).join('\n');
142
+ expect(output).toContain('Recovery');
143
+ expect(output).toContain('plumbus migrate reconcile');
144
+ });
145
+ it('reports nullability mismatch', () => {
146
+ const report = {
147
+ hasDrift: true,
148
+ existingFrameworkTables: ['flow_executions'],
149
+ missingFrameworkTables: [],
150
+ tables: [
151
+ {
152
+ tableName: 'flow_executions',
153
+ exists: true,
154
+ columnDrifts: [
155
+ {
156
+ column: 'status',
157
+ kind: 'nullability_mismatch',
158
+ expected: 'not null',
159
+ actual: 'nullable',
160
+ },
161
+ ],
162
+ },
163
+ ],
164
+ };
165
+ const output = formatDriftReport(report).join('\n');
166
+ expect(output).toContain('status');
167
+ expect(output).toContain('nullability');
168
+ });
169
+ });
170
+ //# sourceMappingURL=drift-inspector.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"drift-inspector.test.js","sourceRoot":"","sources":["../../../src/data/__tests__/drift-inspector.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=framework-migration-rewriter.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-migration-rewriter.test.d.ts","sourceRoot":"","sources":["../../../src/data/__tests__/framework-migration-rewriter.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,329 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { formatRewriteSummary, rewriteFrameworkDriftMigration, rewriteHadEffect, } from '../framework-migration-rewriter.js';
3
+ function makeReport(overrides) {
4
+ return {
5
+ hasDrift: false,
6
+ existingFrameworkTables: [],
7
+ missingFrameworkTables: [],
8
+ tables: [],
9
+ ...overrides,
10
+ };
11
+ }
12
+ describe('rewriteFrameworkDriftMigration', () => {
13
+ it('rewrites CREATE TABLE for an existing framework table to ALTER TABLE ADD COLUMN for missing columns only', () => {
14
+ const stmts = [
15
+ `CREATE TABLE "flow_executions" (
16
+ \t"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
17
+ \t"flow_name" text NOT NULL,
18
+ \t"status" text DEFAULT 'created' NOT NULL,
19
+ \t"lease_owner" text,
20
+ \t"lease_expires_at" timestamp with time zone
21
+ );`,
22
+ `CREATE INDEX "flow_exec_lease_idx" ON "flow_executions" USING btree ("status","lease_expires_at");`,
23
+ ];
24
+ const report = makeReport({
25
+ hasDrift: true,
26
+ existingFrameworkTables: ['flow_executions'],
27
+ tables: [
28
+ {
29
+ tableName: 'flow_executions',
30
+ exists: true,
31
+ columnDrifts: [
32
+ { column: 'lease_owner', kind: 'missing_in_db', expected: 'text' },
33
+ {
34
+ column: 'lease_expires_at',
35
+ kind: 'missing_in_db',
36
+ expected: 'timestamp with time zone',
37
+ },
38
+ ],
39
+ },
40
+ ],
41
+ });
42
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, report);
43
+ const joined = statements.join('\n');
44
+ expect(joined).not.toMatch(/CREATE\s+TABLE\s+"flow_executions"/i);
45
+ expect(statements).toContain(`ALTER TABLE "flow_executions" ADD COLUMN "lease_owner" text;`);
46
+ expect(statements).toContain(`ALTER TABLE "flow_executions" ADD COLUMN "lease_expires_at" timestamp with time zone;`);
47
+ expect(joined).toMatch(/CREATE INDEX IF NOT EXISTS "flow_exec_lease_idx" ON "flow_executions"/);
48
+ expect(summary.alteredTables).toEqual([
49
+ { table: 'flow_executions', addedColumns: ['lease_owner', 'lease_expires_at'] },
50
+ ]);
51
+ expect(summary.droppedCreateTables).toEqual([]);
52
+ expect(summary.wrappedIndexes).toEqual(['flow_exec_lease_idx']);
53
+ expect(summary.warnings).toEqual([]);
54
+ expect(rewriteHadEffect(summary)).toBe(true);
55
+ });
56
+ it('drops CREATE TABLE entirely for an existing framework table with no missing columns', () => {
57
+ const stmts = [
58
+ `CREATE TABLE "event_outbox" (
59
+ \t"id" uuid PRIMARY KEY,
60
+ \t"event_type" text NOT NULL
61
+ );`,
62
+ `CREATE INDEX "event_outbox_status_idx" ON "event_outbox" USING btree ("status");`,
63
+ ];
64
+ const report = makeReport({
65
+ existingFrameworkTables: ['event_outbox'],
66
+ tables: [{ tableName: 'event_outbox', exists: true, columnDrifts: [] }],
67
+ });
68
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, report);
69
+ const joined = statements.join('\n');
70
+ expect(joined).not.toMatch(/CREATE\s+TABLE\s+"event_outbox"/i);
71
+ expect(joined).toContain('CREATE INDEX IF NOT EXISTS "event_outbox_status_idx"');
72
+ expect(summary.droppedCreateTables).toEqual(['event_outbox']);
73
+ expect(summary.alteredTables).toEqual([]);
74
+ });
75
+ it('preserves CREATE TABLE for framework tables that do NOT exist in the live DB', () => {
76
+ const stmts = [
77
+ `CREATE TABLE "documents" (
78
+ \t"id" varchar(255) PRIMARY KEY NOT NULL,
79
+ \t"source" varchar(1024) NOT NULL
80
+ );`,
81
+ ];
82
+ const report = makeReport({
83
+ missingFrameworkTables: ['documents'],
84
+ tables: [{ tableName: 'documents', exists: false, columnDrifts: [] }],
85
+ });
86
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, report);
87
+ expect(statements.join('\n')).toMatch(/CREATE\s+TABLE\s+"documents"/i);
88
+ expect(summary.droppedCreateTables).toEqual([]);
89
+ expect(summary.alteredTables).toEqual([]);
90
+ });
91
+ it('passes user entity tables through unchanged', () => {
92
+ const stmts = [
93
+ `CREATE TABLE "project" (
94
+ \t"id" uuid PRIMARY KEY,
95
+ \t"name" text NOT NULL
96
+ );`,
97
+ ];
98
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
99
+ expect(statements).toEqual(stmts);
100
+ expect(rewriteHadEffect(summary)).toBe(false);
101
+ });
102
+ it('wraps CREATE INDEX with IF NOT EXISTS', () => {
103
+ const stmts = [`CREATE INDEX "idx_name" ON "tbl" USING btree ("col");`];
104
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
105
+ expect(statements[0]).toContain('CREATE INDEX IF NOT EXISTS "idx_name"');
106
+ expect(summary.wrappedIndexes).toEqual(['idx_name']);
107
+ });
108
+ it('wraps CREATE UNIQUE INDEX with IF NOT EXISTS', () => {
109
+ const stmts = [`CREATE UNIQUE INDEX "ux_name" ON "tbl" ("col");`];
110
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
111
+ expect(statements[0]).toContain('CREATE UNIQUE INDEX IF NOT EXISTS "ux_name"');
112
+ expect(summary.wrappedIndexes).toEqual(['ux_name']);
113
+ });
114
+ it('does not double-wrap CREATE INDEX IF NOT EXISTS', () => {
115
+ const stmts = [`CREATE INDEX IF NOT EXISTS "idx_name" ON "tbl" ("col");`];
116
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
117
+ expect(statements).toEqual(stmts);
118
+ expect(summary.wrappedIndexes).toEqual([]);
119
+ });
120
+ it('warns when a framework CREATE TABLE contains table-level constraints', () => {
121
+ const stmts = [
122
+ `CREATE TABLE "flow_dead_letter" (
123
+ \t"id" uuid PRIMARY KEY,
124
+ \t"execution_id" text NOT NULL,
125
+ \t"new_col" text,
126
+ \tCONSTRAINT "flow_dead_letter_execution_id_unique" UNIQUE("execution_id")
127
+ );`,
128
+ ];
129
+ const report = makeReport({
130
+ existingFrameworkTables: ['flow_dead_letter'],
131
+ tables: [
132
+ {
133
+ tableName: 'flow_dead_letter',
134
+ exists: true,
135
+ columnDrifts: [{ column: 'new_col', kind: 'missing_in_db', expected: 'text' }],
136
+ },
137
+ ],
138
+ });
139
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, report);
140
+ const joined = statements.join('\n');
141
+ expect(joined).toContain(`ALTER TABLE "flow_dead_letter" ADD COLUMN "new_col" text`);
142
+ expect(joined).not.toContain('CONSTRAINT');
143
+ expect(summary.warnings.some((w) => w.includes('flow_dead_letter'))).toBe(true);
144
+ });
145
+ it('warns and skips when the drift report names a column that the generated CREATE TABLE does not include', () => {
146
+ const stmts = [
147
+ `CREATE TABLE "flow_executions" (
148
+ \t"id" uuid PRIMARY KEY
149
+ );`,
150
+ ];
151
+ const report = makeReport({
152
+ existingFrameworkTables: ['flow_executions'],
153
+ tables: [
154
+ {
155
+ tableName: 'flow_executions',
156
+ exists: true,
157
+ columnDrifts: [{ column: 'lease_owner', kind: 'missing_in_db', expected: 'text' }],
158
+ },
159
+ ],
160
+ });
161
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, report);
162
+ expect(statements.join('\n')).not.toContain('ALTER TABLE');
163
+ expect(summary.warnings.some((w) => w.includes('lease_owner'))).toBe(true);
164
+ expect(summary.droppedCreateTables).toEqual(['flow_executions']);
165
+ });
166
+ it('handles mixed migrations: rewrite + new framework table + entity table + index wrapping in one go', () => {
167
+ const stmts = [
168
+ // Existing framework table needs columns added
169
+ `CREATE TABLE "flow_executions" (
170
+ \t"id" uuid PRIMARY KEY,
171
+ \t"lease_owner" text,
172
+ \t"lease_expires_at" timestamp with time zone
173
+ );`,
174
+ // New framework table — should be preserved
175
+ `CREATE TABLE "documents" (
176
+ \t"id" varchar(255) PRIMARY KEY,
177
+ \t"source" varchar(1024) NOT NULL
178
+ );`,
179
+ // User entity table — passes through
180
+ `CREATE TABLE "project" (
181
+ \t"id" uuid PRIMARY KEY,
182
+ \t"name" text
183
+ );`,
184
+ // Index — wrapped
185
+ `CREATE INDEX "flow_exec_lease_idx" ON "flow_executions" ("status","lease_expires_at");`,
186
+ // Another index — wrapped
187
+ `CREATE INDEX "documents_tenant_id_idx" ON "documents" ("tenant_id");`,
188
+ ];
189
+ const report = makeReport({
190
+ hasDrift: true,
191
+ existingFrameworkTables: ['flow_executions'],
192
+ missingFrameworkTables: ['documents'],
193
+ tables: [
194
+ {
195
+ tableName: 'flow_executions',
196
+ exists: true,
197
+ columnDrifts: [
198
+ { column: 'lease_owner', kind: 'missing_in_db', expected: 'text' },
199
+ {
200
+ column: 'lease_expires_at',
201
+ kind: 'missing_in_db',
202
+ expected: 'timestamp with time zone',
203
+ },
204
+ ],
205
+ },
206
+ { tableName: 'documents', exists: false, columnDrifts: [] },
207
+ ],
208
+ });
209
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, report);
210
+ const joined = statements.join('\n');
211
+ expect(joined).not.toMatch(/CREATE\s+TABLE\s+"flow_executions"/i);
212
+ expect(joined).toMatch(/CREATE\s+TABLE\s+"documents"/i);
213
+ expect(joined).toMatch(/CREATE\s+TABLE\s+"project"/i);
214
+ expect(statements).toContain('ALTER TABLE "flow_executions" ADD COLUMN "lease_owner" text;');
215
+ expect(statements).toContain('ALTER TABLE "flow_executions" ADD COLUMN "lease_expires_at" timestamp with time zone;');
216
+ expect(joined).toContain('CREATE INDEX IF NOT EXISTS "flow_exec_lease_idx"');
217
+ expect(joined).toContain('CREATE INDEX IF NOT EXISTS "documents_tenant_id_idx"');
218
+ expect(summary.alteredTables).toEqual([
219
+ { table: 'flow_executions', addedColumns: ['lease_owner', 'lease_expires_at'] },
220
+ ]);
221
+ expect(summary.wrappedIndexes).toEqual(['flow_exec_lease_idx', 'documents_tenant_id_idx']);
222
+ });
223
+ it('emits one statement per ALTER (not a concatenated string) so the caller can join freely', () => {
224
+ const stmts = [
225
+ `CREATE TABLE "flow_executions" (
226
+ \t"id" uuid PRIMARY KEY,
227
+ \t"lease_owner" text,
228
+ \t"lease_expires_at" timestamp with time zone
229
+ );`,
230
+ `CREATE INDEX "flow_exec_lease_idx" ON "flow_executions" ("lease_expires_at");`,
231
+ ];
232
+ const report = makeReport({
233
+ existingFrameworkTables: ['flow_executions'],
234
+ tables: [
235
+ {
236
+ tableName: 'flow_executions',
237
+ exists: true,
238
+ columnDrifts: [
239
+ { column: 'lease_owner', kind: 'missing_in_db', expected: 'text' },
240
+ {
241
+ column: 'lease_expires_at',
242
+ kind: 'missing_in_db',
243
+ expected: 'timestamp with time zone',
244
+ },
245
+ ],
246
+ },
247
+ ],
248
+ });
249
+ const { statements } = rewriteFrameworkDriftMigration(stmts, report);
250
+ // 2 ALTERs + 1 CREATE INDEX = 3 array entries
251
+ expect(statements).toHaveLength(3);
252
+ for (const s of statements) {
253
+ expect(s).not.toContain('--> statement-breakpoint');
254
+ }
255
+ });
256
+ it('leaves statements untouched when there is no framework drift and no indexes to wrap', () => {
257
+ const stmts = [
258
+ `CREATE TABLE "project" (
259
+ \t"id" uuid PRIMARY KEY,
260
+ \t"name" text
261
+ );`,
262
+ ];
263
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
264
+ expect(statements).toEqual(stmts);
265
+ expect(rewriteHadEffect(summary)).toBe(false);
266
+ });
267
+ it('skips empty/whitespace-only input statements', () => {
268
+ const stmts = ['', ' \n ', `CREATE TABLE "project" ("id" uuid PRIMARY KEY);`];
269
+ const { statements } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
270
+ expect(statements).toEqual([`CREATE TABLE "project" ("id" uuid PRIMARY KEY);`]);
271
+ });
272
+ });
273
+ describe('ADD COLUMN idempotency', () => {
274
+ it('rewrites ALTER TABLE … ADD COLUMN to ADD COLUMN IF NOT EXISTS', () => {
275
+ const stmts = [`ALTER TABLE "timeline_event" ADD COLUMN "evidence" jsonb;`];
276
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
277
+ expect(statements[0]).toBe(`ALTER TABLE "timeline_event" ADD COLUMN IF NOT EXISTS "evidence" jsonb;`);
278
+ expect(summary.idempotentAddColumns).toEqual(['"timeline_event"."evidence"']);
279
+ });
280
+ it('does not double-wrap ADD COLUMN IF NOT EXISTS', () => {
281
+ const stmts = [`ALTER TABLE "x" ADD COLUMN IF NOT EXISTS "y" text;`];
282
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
283
+ expect(statements).toEqual(stmts);
284
+ expect(summary.idempotentAddColumns).toEqual([]);
285
+ });
286
+ it('handles multiple ADD COLUMN clauses in a single ALTER TABLE statement', () => {
287
+ const stmts = [`ALTER TABLE "x" ADD COLUMN "a" text, ADD COLUMN "b" int;`];
288
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
289
+ expect(statements[0]).toBe(`ALTER TABLE "x" ADD COLUMN IF NOT EXISTS "a" text, ADD COLUMN IF NOT EXISTS "b" int;`);
290
+ expect(summary.idempotentAddColumns).toEqual(['"x"."a","b"']);
291
+ });
292
+ it('does not rewrite ALTER TABLE … ADD CONSTRAINT or ALTER COLUMN', () => {
293
+ const stmts = [
294
+ `ALTER TABLE "x" ADD CONSTRAINT "c" UNIQUE ("a");`,
295
+ `ALTER TABLE "x" ALTER COLUMN "a" SET NOT NULL;`,
296
+ `ALTER TABLE "x" DROP COLUMN "b";`,
297
+ ];
298
+ const { statements, summary } = rewriteFrameworkDriftMigration(stmts, makeReport({}));
299
+ expect(statements).toEqual(stmts);
300
+ expect(summary.idempotentAddColumns).toEqual([]);
301
+ });
302
+ });
303
+ describe('formatRewriteSummary', () => {
304
+ it('produces empty output when nothing was rewritten', () => {
305
+ expect(formatRewriteSummary({
306
+ alteredTables: [],
307
+ droppedCreateTables: [],
308
+ wrappedIndexes: [],
309
+ idempotentAddColumns: [],
310
+ warnings: [],
311
+ })).toEqual([]);
312
+ });
313
+ it('formats altered, dropped, wrapped, idempotent, and warning sections', () => {
314
+ const lines = formatRewriteSummary({
315
+ alteredTables: [{ table: 'flow_executions', addedColumns: ['lease_owner'] }],
316
+ droppedCreateTables: ['event_outbox'],
317
+ wrappedIndexes: ['idx_a', 'idx_b'],
318
+ idempotentAddColumns: ['"timeline_event"."evidence"'],
319
+ warnings: ['something is off'],
320
+ });
321
+ const out = lines.join('\n');
322
+ expect(out).toContain('flow_executions: lease_owner');
323
+ expect(out).toContain('event_outbox');
324
+ expect(out).toContain('2 CREATE INDEX');
325
+ expect(out).toContain('1 ALTER TABLE ADD COLUMN');
326
+ expect(out).toContain('something is off');
327
+ });
328
+ });
329
+ //# sourceMappingURL=framework-migration-rewriter.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"framework-migration-rewriter.test.js","sourceRoot":"","sources":["../../../src/data/__tests__/framework-migration-rewriter.test.ts"],"names":[],"mappings":"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"}
@@ -1,7 +1,11 @@
1
+ import * as crypto from 'node:crypto';
2
+ import * as fs from 'node:fs';
3
+ import * as os from 'node:os';
4
+ import * as path from 'node:path';
1
5
  import { getTableName } from 'drizzle-orm';
2
- import { describe, expect, it } from 'vitest';
6
+ import { afterEach, describe, expect, it, vi } from 'vitest';
3
7
  import { field } from '../../fields/index.js';
4
- import { collectSchemas } from '../migration.js';
8
+ import { collectSchemas, readPendingMigrations, reconcileMigrationHistory } from '../migration.js';
5
9
  function makeEntity(name) {
6
10
  return {
7
11
  name,
@@ -16,6 +20,34 @@ function getSchema(schemas, key) {
16
20
  expect(table).toBeDefined();
17
21
  return table;
18
22
  }
23
+ function writeMigrationFixture(baseDir, files) {
24
+ const metaDir = path.join(baseDir, 'meta');
25
+ fs.mkdirSync(metaDir, { recursive: true });
26
+ for (const file of files) {
27
+ fs.writeFileSync(path.join(baseDir, `${file.tag}.sql`), file.sql, 'utf-8');
28
+ }
29
+ fs.writeFileSync(path.join(metaDir, '_journal.json'), JSON.stringify({
30
+ entries: files.map((file, index) => ({
31
+ idx: index,
32
+ version: '7',
33
+ when: file.when,
34
+ tag: file.tag,
35
+ breakpoints: true,
36
+ })),
37
+ }, null, 2), 'utf-8');
38
+ }
39
+ function sha256(input) {
40
+ return crypto.createHash('sha256').update(input).digest('hex');
41
+ }
42
+ const tempDirs = [];
43
+ afterEach(() => {
44
+ while (tempDirs.length > 0) {
45
+ const dir = tempDirs.pop();
46
+ if (dir) {
47
+ fs.rmSync(dir, { recursive: true, force: true });
48
+ }
49
+ }
50
+ });
19
51
  describe('collectSchemas', () => {
20
52
  it('includes user-defined entity tables', () => {
21
53
  const schemas = collectSchemas([makeEntity('Order'), makeEntity('Customer')]);
@@ -49,4 +81,63 @@ describe('collectSchemas', () => {
49
81
  expect(frameworkKeys).toHaveLength(9);
50
82
  });
51
83
  });
84
+ describe('migration history helpers', () => {
85
+ it('reads only unapplied migrations from the journal', async () => {
86
+ const migrationsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'plumbus-migrations-'));
87
+ tempDirs.push(migrationsDir);
88
+ const firstSql = 'CREATE TABLE "orders" ("id" uuid PRIMARY KEY);';
89
+ const secondSql = [
90
+ 'ALTER TABLE "orders" ADD COLUMN "slug" text;',
91
+ '--> statement-breakpoint',
92
+ 'CREATE INDEX "orders_slug_idx" ON "orders" ("slug");',
93
+ ].join('\n');
94
+ writeMigrationFixture(migrationsDir, [
95
+ { tag: '0001_init', sql: firstSql, when: 1000 },
96
+ { tag: '0002_slug', sql: secondSql, when: 2000 },
97
+ ]);
98
+ const db = {
99
+ execute: vi
100
+ .fn()
101
+ .mockResolvedValueOnce([])
102
+ .mockResolvedValueOnce([{ hash: sha256(firstSql) }]),
103
+ };
104
+ const pending = await readPendingMigrations({
105
+ db: db,
106
+ migrationsFolder: migrationsDir,
107
+ });
108
+ expect(pending).toHaveLength(1);
109
+ expect(pending[0]?.tag).toBe('0002_slug');
110
+ expect(pending[0]?.statements).toHaveLength(2);
111
+ });
112
+ it('reconciles only missing migration records', async () => {
113
+ const migrationsDir = fs.mkdtempSync(path.join(os.tmpdir(), 'plumbus-migrations-'));
114
+ tempDirs.push(migrationsDir);
115
+ const firstSql = 'CREATE TABLE "orders" ("id" uuid PRIMARY KEY);';
116
+ const secondSql = 'ALTER TABLE "orders" ADD COLUMN "slug" text;';
117
+ writeMigrationFixture(migrationsDir, [
118
+ { tag: '0001_init', sql: firstSql, when: 1000 },
119
+ { tag: '0002_slug', sql: secondSql, when: 2000 },
120
+ ]);
121
+ const tx = {
122
+ execute: vi.fn(async () => []),
123
+ };
124
+ const db = {
125
+ execute: vi
126
+ .fn()
127
+ .mockResolvedValueOnce([])
128
+ .mockResolvedValueOnce([{ hash: sha256(firstSql) }]),
129
+ transaction: vi.fn(async (callback) => callback(tx)),
130
+ };
131
+ const result = await reconcileMigrationHistory({
132
+ db: db,
133
+ migrationsFolder: migrationsDir,
134
+ });
135
+ expect(result).toEqual({
136
+ adopted: 1,
137
+ alreadyApplied: 1,
138
+ adoptedTags: ['0002_slug'],
139
+ });
140
+ expect(tx.execute).toHaveBeenCalledTimes(1);
141
+ });
142
+ });
52
143
  //# sourceMappingURL=migration.test.js.map