@automagik/omni 2.260423.3 → 2.260423.5
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.
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
-- Issue #407: reconcile gupshup column drift.
|
|
2
|
+
--
|
|
3
|
+
-- Migration 0018_supreme_puma renamed three columns on "instances":
|
|
4
|
+
-- gupshup_api_key -> gupshup_callback_url
|
|
5
|
+
-- gupshup_app_name -> gupshup_auth_token
|
|
6
|
+
-- gupshup_source_phone -> gupshup_event_id
|
|
7
|
+
--
|
|
8
|
+
-- On at least one deployed DB the migration was marked applied in
|
|
9
|
+
-- drizzle.__drizzle_migrations but the rename never executed, leaving the
|
|
10
|
+
-- live table with the old column names. Because RENAME is not idempotent,
|
|
11
|
+
-- replaying 0018 would fail. This migration is safe to rerun: it adds the
|
|
12
|
+
-- new columns if missing, copies any surviving data from old columns, and
|
|
13
|
+
-- then drops the old columns if present.
|
|
14
|
+
|
|
15
|
+
ALTER TABLE "instances" ADD COLUMN IF NOT EXISTS "gupshup_callback_url" text;
|
|
16
|
+
ALTER TABLE "instances" ADD COLUMN IF NOT EXISTS "gupshup_auth_token" text;
|
|
17
|
+
ALTER TABLE "instances" ADD COLUMN IF NOT EXISTS "gupshup_event_id" varchar(255);
|
|
18
|
+
|
|
19
|
+
DO $$
|
|
20
|
+
BEGIN
|
|
21
|
+
IF EXISTS (
|
|
22
|
+
SELECT 1 FROM information_schema.columns
|
|
23
|
+
WHERE table_schema = 'public' AND table_name = 'instances' AND column_name = 'gupshup_api_key'
|
|
24
|
+
) THEN
|
|
25
|
+
EXECUTE 'UPDATE "instances" SET "gupshup_callback_url" = "gupshup_api_key" WHERE "gupshup_callback_url" IS NULL AND "gupshup_api_key" IS NOT NULL';
|
|
26
|
+
END IF;
|
|
27
|
+
|
|
28
|
+
IF EXISTS (
|
|
29
|
+
SELECT 1 FROM information_schema.columns
|
|
30
|
+
WHERE table_schema = 'public' AND table_name = 'instances' AND column_name = 'gupshup_app_name'
|
|
31
|
+
) THEN
|
|
32
|
+
EXECUTE 'UPDATE "instances" SET "gupshup_auth_token" = "gupshup_app_name" WHERE "gupshup_auth_token" IS NULL AND "gupshup_app_name" IS NOT NULL';
|
|
33
|
+
END IF;
|
|
34
|
+
|
|
35
|
+
IF EXISTS (
|
|
36
|
+
SELECT 1 FROM information_schema.columns
|
|
37
|
+
WHERE table_schema = 'public' AND table_name = 'instances' AND column_name = 'gupshup_source_phone'
|
|
38
|
+
) THEN
|
|
39
|
+
EXECUTE 'UPDATE "instances" SET "gupshup_event_id" = "gupshup_source_phone" WHERE "gupshup_event_id" IS NULL AND "gupshup_source_phone" IS NOT NULL';
|
|
40
|
+
END IF;
|
|
41
|
+
END $$;
|
|
42
|
+
|
|
43
|
+
ALTER TABLE "instances" DROP COLUMN IF EXISTS "gupshup_api_key";
|
|
44
|
+
ALTER TABLE "instances" DROP COLUMN IF EXISTS "gupshup_app_name";
|
|
45
|
+
ALTER TABLE "instances" DROP COLUMN IF EXISTS "gupshup_source_phone";
|
|
@@ -218,6 +218,13 @@
|
|
|
218
218
|
"when": 1777300000000,
|
|
219
219
|
"tag": "0030_twilio_whatsapp_channel",
|
|
220
220
|
"breakpoints": true
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
"idx": 31,
|
|
224
|
+
"version": "7",
|
|
225
|
+
"when": 1777400000000,
|
|
226
|
+
"tag": "0031_reconcile_gupshup_columns",
|
|
227
|
+
"breakpoints": true
|
|
221
228
|
}
|
|
222
229
|
]
|
|
223
230
|
}
|
package/dist/index.js
CHANGED
|
@@ -62070,10 +62070,14 @@ var init_migrate = __esm(() => {
|
|
|
62070
62070
|
if (false) {}
|
|
62071
62071
|
});
|
|
62072
62072
|
|
|
62073
|
+
// ../db/src/verify-schema.ts
|
|
62074
|
+
var init_verify_schema = () => {};
|
|
62075
|
+
|
|
62073
62076
|
// ../db/src/index.ts
|
|
62074
62077
|
var init_src3 = __esm(() => {
|
|
62075
62078
|
init_client3();
|
|
62076
62079
|
init_migrate();
|
|
62080
|
+
init_verify_schema();
|
|
62077
62081
|
init_schema2();
|
|
62078
62082
|
});
|
|
62079
62083
|
|
|
@@ -113839,7 +113843,7 @@ import { fileURLToPath } from "url";
|
|
|
113839
113843
|
// package.json
|
|
113840
113844
|
var package_default = {
|
|
113841
113845
|
name: "@automagik/omni",
|
|
113842
|
-
version: "2.260423.
|
|
113846
|
+
version: "2.260423.5",
|
|
113843
113847
|
description: "LLM-optimized CLI for Omni",
|
|
113844
113848
|
type: "module",
|
|
113845
113849
|
bin: {
|
package/dist/server/index.js
CHANGED
|
@@ -224464,7 +224464,7 @@ var init_sentry_scrub = __esm(() => {
|
|
|
224464
224464
|
var require_package8 = __commonJS((exports, module) => {
|
|
224465
224465
|
module.exports = {
|
|
224466
224466
|
name: "@omni/api",
|
|
224467
|
-
version: "2.260423.
|
|
224467
|
+
version: "2.260423.5",
|
|
224468
224468
|
type: "module",
|
|
224469
224469
|
exports: {
|
|
224470
224470
|
".": {
|
|
@@ -233528,10 +233528,68 @@ var init_migrate = __esm(() => {
|
|
|
233528
233528
|
if (false) {}
|
|
233529
233529
|
});
|
|
233530
233530
|
|
|
233531
|
+
// ../db/src/verify-schema.ts
|
|
233532
|
+
async function verifyCriticalColumns(db2, expectations) {
|
|
233533
|
+
if (expectations.length === 0) {
|
|
233534
|
+
return { ok: true, drift: [] };
|
|
233535
|
+
}
|
|
233536
|
+
const tables = expectations.map((e) => e.table);
|
|
233537
|
+
const rows = await db2.execute(sql`
|
|
233538
|
+
SELECT table_name, column_name
|
|
233539
|
+
FROM information_schema.columns
|
|
233540
|
+
WHERE table_schema = 'public'
|
|
233541
|
+
AND table_name IN (${sql.join(tables.map((t) => sql`${t}`), sql`, `)})
|
|
233542
|
+
`);
|
|
233543
|
+
const liveColumns = new Map;
|
|
233544
|
+
for (const row of rows) {
|
|
233545
|
+
const set = liveColumns.get(row.table_name) ?? new Set;
|
|
233546
|
+
set.add(row.column_name);
|
|
233547
|
+
liveColumns.set(row.table_name, set);
|
|
233548
|
+
}
|
|
233549
|
+
const drift = [];
|
|
233550
|
+
for (const expectation of expectations) {
|
|
233551
|
+
const live = liveColumns.get(expectation.table) ?? new Set;
|
|
233552
|
+
const missing = expectation.columns.filter((col) => !live.has(col));
|
|
233553
|
+
if (missing.length > 0) {
|
|
233554
|
+
drift.push({ table: expectation.table, missing });
|
|
233555
|
+
}
|
|
233556
|
+
}
|
|
233557
|
+
return { ok: drift.length === 0, drift };
|
|
233558
|
+
}
|
|
233559
|
+
function formatDriftReport(report) {
|
|
233560
|
+
if (report.ok)
|
|
233561
|
+
return "Schema drift check passed.";
|
|
233562
|
+
const lines = [
|
|
233563
|
+
"Schema drift detected \u2014 live database is missing columns Drizzle expects.",
|
|
233564
|
+
"This usually means drizzle-kit push was used against a migrated database,",
|
|
233565
|
+
"or a migration was marked applied but its SQL did not execute.",
|
|
233566
|
+
""
|
|
233567
|
+
];
|
|
233568
|
+
for (const entry of report.drift) {
|
|
233569
|
+
lines.push(` table "${entry.table}" missing columns: ${entry.missing.join(", ")}`);
|
|
233570
|
+
}
|
|
233571
|
+
lines.push("");
|
|
233572
|
+
lines.push("Run `bun run db:verify-drift` locally against the same DATABASE_URL,");
|
|
233573
|
+
lines.push("then apply the reconcile migration (see issue #407).");
|
|
233574
|
+
return lines.join(`
|
|
233575
|
+
`);
|
|
233576
|
+
}
|
|
233577
|
+
var API_CRITICAL_COLUMNS;
|
|
233578
|
+
var init_verify_schema = __esm(() => {
|
|
233579
|
+
init_drizzle_orm();
|
|
233580
|
+
API_CRITICAL_COLUMNS = [
|
|
233581
|
+
{
|
|
233582
|
+
table: "instances",
|
|
233583
|
+
columns: ["gupshup_callback_url", "gupshup_auth_token", "gupshup_event_id"]
|
|
233584
|
+
}
|
|
233585
|
+
];
|
|
233586
|
+
});
|
|
233587
|
+
|
|
233531
233588
|
// ../db/src/index.ts
|
|
233532
233589
|
var init_src5 = __esm(() => {
|
|
233533
233590
|
init_client5();
|
|
233534
233591
|
init_migrate();
|
|
233592
|
+
init_verify_schema();
|
|
233535
233593
|
init_schema2();
|
|
233536
233594
|
});
|
|
233537
233595
|
|
|
@@ -278915,11 +278973,11 @@ class BatchJobService {
|
|
|
278915
278973
|
if (!mimeType || !this.mediaService.canProcess(mimeType)) {
|
|
278916
278974
|
return this.failedResult(`MIME type not processable: ${mimeType}`);
|
|
278917
278975
|
}
|
|
278918
|
-
const
|
|
278919
|
-
if (!
|
|
278920
|
-
return this.failedResult(
|
|
278976
|
+
const resolved = await this.resolveFilePath(instanceId, message2, mimeType);
|
|
278977
|
+
if (!resolved.ok) {
|
|
278978
|
+
return this.failedResult(resolved.reason);
|
|
278921
278979
|
}
|
|
278922
|
-
const fullPath = join19(this.mediaStorage.getBasePath(),
|
|
278980
|
+
const fullPath = join19(this.mediaStorage.getBasePath(), resolved.path);
|
|
278923
278981
|
const result = await this.mediaService.process(fullPath, mimeType, {
|
|
278924
278982
|
language: "pt",
|
|
278925
278983
|
caption: message2.textContent ?? undefined
|
|
@@ -278943,17 +279001,23 @@ class BatchJobService {
|
|
|
278943
279001
|
}
|
|
278944
279002
|
async resolveFilePath(instanceId, message2, mimeType) {
|
|
278945
279003
|
if (message2.mediaLocalPath) {
|
|
278946
|
-
return message2.mediaLocalPath;
|
|
279004
|
+
return { ok: true, path: message2.mediaLocalPath };
|
|
278947
279005
|
}
|
|
278948
279006
|
if (!message2.mediaUrl) {
|
|
278949
|
-
return
|
|
279007
|
+
return { ok: false, reason: "No media_url and no media_local_path on message" };
|
|
278950
279008
|
}
|
|
278951
279009
|
try {
|
|
278952
279010
|
const result = await this.mediaStorage.storeFromUrl(instanceId, message2.id, message2.mediaUrl, mimeType, message2.platformTimestamp ?? undefined);
|
|
278953
279011
|
await this.mediaStorage.updateMessageLocalPath(message2.id, result.localPath);
|
|
278954
|
-
return result.localPath;
|
|
278955
|
-
} catch {
|
|
278956
|
-
|
|
279012
|
+
return { ok: true, path: result.localPath };
|
|
279013
|
+
} catch (error2) {
|
|
279014
|
+
const reason = `storeFromUrl failed: ${error2 instanceof Error ? error2.message : String(error2)}`;
|
|
279015
|
+
log76.warn("storeFromUrl failed during batch retrofill", {
|
|
279016
|
+
messageId: message2.id,
|
|
279017
|
+
mediaUrl: message2.mediaUrl,
|
|
279018
|
+
error: reason
|
|
279019
|
+
});
|
|
279020
|
+
return { ok: false, reason };
|
|
278957
279021
|
}
|
|
278958
279022
|
}
|
|
278959
279023
|
async persistProcessingResult(messageId, result, batchJobId) {
|
|
@@ -305428,6 +305492,20 @@ async function main() {
|
|
|
305428
305492
|
throw error2;
|
|
305429
305493
|
}
|
|
305430
305494
|
log111.info("Database migrations complete", { durationMs: Date.now() - migrationStart });
|
|
305495
|
+
try {
|
|
305496
|
+
const driftReport = await verifyCriticalColumns(db3, API_CRITICAL_COLUMNS);
|
|
305497
|
+
if (!driftReport.ok) {
|
|
305498
|
+
log111.error(formatDriftReport(driftReport), { drift: driftReport.drift });
|
|
305499
|
+
await closeDb();
|
|
305500
|
+
await stopEmbeddedPgserve();
|
|
305501
|
+
process.exit(1);
|
|
305502
|
+
}
|
|
305503
|
+
} catch (error2) {
|
|
305504
|
+
log111.error("Schema drift check failed", { error: String(error2) });
|
|
305505
|
+
await closeDb();
|
|
305506
|
+
await stopEmbeddedPgserve();
|
|
305507
|
+
process.exit(1);
|
|
305508
|
+
}
|
|
305431
305509
|
try {
|
|
305432
305510
|
const [countRow] = await db3.select({ count: sql`count(*)::int` }).from(instances);
|
|
305433
305511
|
const rowCount = countRow?.count ?? 0;
|
|
@@ -424310,14 +424388,16 @@ var contentExtractors = [
|
|
|
424310
424388
|
extract: (m2) => ({
|
|
424311
424389
|
type: "image",
|
|
424312
424390
|
caption: m2.imageMessage?.caption ?? undefined,
|
|
424313
|
-
mimeType: m2.imageMessage?.mimetype ?? "image/jpeg"
|
|
424391
|
+
mimeType: m2.imageMessage?.mimetype ?? "image/jpeg",
|
|
424392
|
+
mediaUrl: m2.imageMessage?.url ?? undefined
|
|
424314
424393
|
})
|
|
424315
424394
|
},
|
|
424316
424395
|
{
|
|
424317
424396
|
check: (m2) => !!m2.audioMessage,
|
|
424318
424397
|
extract: (m2) => ({
|
|
424319
424398
|
type: "audio",
|
|
424320
|
-
mimeType: m2.audioMessage?.mimetype ?? "audio/ogg"
|
|
424399
|
+
mimeType: m2.audioMessage?.mimetype ?? "audio/ogg",
|
|
424400
|
+
mediaUrl: m2.audioMessage?.url ?? undefined
|
|
424321
424401
|
})
|
|
424322
424402
|
},
|
|
424323
424403
|
{
|
|
@@ -424325,7 +424405,8 @@ var contentExtractors = [
|
|
|
424325
424405
|
extract: (m2) => ({
|
|
424326
424406
|
type: "video",
|
|
424327
424407
|
caption: m2.videoMessage?.caption ?? undefined,
|
|
424328
|
-
mimeType: m2.videoMessage?.mimetype ?? "video/mp4"
|
|
424408
|
+
mimeType: m2.videoMessage?.mimetype ?? "video/mp4",
|
|
424409
|
+
mediaUrl: m2.videoMessage?.url ?? undefined
|
|
424329
424410
|
})
|
|
424330
424411
|
},
|
|
424331
424412
|
{
|
|
@@ -424334,14 +424415,16 @@ var contentExtractors = [
|
|
|
424334
424415
|
type: "document",
|
|
424335
424416
|
filename: m2.documentMessage?.fileName ?? undefined,
|
|
424336
424417
|
mimeType: m2.documentMessage?.mimetype ?? "application/octet-stream",
|
|
424337
|
-
caption: m2.documentMessage?.caption ?? undefined
|
|
424418
|
+
caption: m2.documentMessage?.caption ?? undefined,
|
|
424419
|
+
mediaUrl: m2.documentMessage?.url ?? undefined
|
|
424338
424420
|
})
|
|
424339
424421
|
},
|
|
424340
424422
|
{
|
|
424341
424423
|
check: (m2) => !!m2.stickerMessage,
|
|
424342
424424
|
extract: (m2) => ({
|
|
424343
424425
|
type: "sticker",
|
|
424344
|
-
mimeType: m2.stickerMessage?.mimetype ?? "image/webp"
|
|
424426
|
+
mimeType: m2.stickerMessage?.mimetype ?? "image/webp",
|
|
424427
|
+
mediaUrl: m2.stickerMessage?.url ?? undefined
|
|
424345
424428
|
})
|
|
424346
424429
|
},
|
|
424347
424430
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@automagik/omni",
|
|
3
|
-
"version": "2.260423.
|
|
3
|
+
"version": "2.260423.5",
|
|
4
4
|
"description": "LLM-optimized CLI for Omni",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -39,15 +39,15 @@
|
|
|
39
39
|
"qrcode-terminal": "^0.12.0"
|
|
40
40
|
},
|
|
41
41
|
"devDependencies": {
|
|
42
|
-
"@omni/api": "2.260423.
|
|
43
|
-
"@omni/channel-discord": "2.260423.
|
|
44
|
-
"@omni/channel-gupshup": "2.260423.
|
|
45
|
-
"@omni/channel-sdk": "2.260423.
|
|
46
|
-
"@omni/channel-slack": "2.260423.
|
|
47
|
-
"@omni/channel-telegram": "2.260423.
|
|
48
|
-
"@omni/channel-whatsapp": "2.260423.
|
|
49
|
-
"@omni/core": "2.260423.
|
|
50
|
-
"@omni/sdk": "2.260423.
|
|
42
|
+
"@omni/api": "2.260423.4",
|
|
43
|
+
"@omni/channel-discord": "2.260423.4",
|
|
44
|
+
"@omni/channel-gupshup": "2.260423.4",
|
|
45
|
+
"@omni/channel-sdk": "2.260423.4",
|
|
46
|
+
"@omni/channel-slack": "2.260423.4",
|
|
47
|
+
"@omni/channel-telegram": "2.260423.4",
|
|
48
|
+
"@omni/channel-whatsapp": "2.260423.4",
|
|
49
|
+
"@omni/core": "2.260423.4",
|
|
50
|
+
"@omni/sdk": "2.260423.4",
|
|
51
51
|
"@types/node": "^22.10.3",
|
|
52
52
|
"@types/qrcode-terminal": "^0.12.2",
|
|
53
53
|
"typescript": "^5.7.3"
|