scribe-cms 0.0.5 → 0.0.6
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.
- package/dist/cli/index.cjs +114 -121
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +114 -121
- package/dist/cli/index.js.map +1 -1
- package/dist/index.cjs +69 -70
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +69 -70
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs +23 -18
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +23 -18
- package/dist/runtime.js.map +1 -1
- package/dist/src/history/record-snapshot.d.ts +11 -0
- package/dist/src/history/record-snapshot.d.ts.map +1 -0
- package/dist/src/storage/sqlite.d.ts.map +1 -1
- package/dist/src/storage/translations.d.ts +14 -21
- package/dist/src/storage/translations.d.ts.map +1 -1
- package/dist/src/translate/page-translator.d.ts.map +1 -1
- package/dist/studio/server.cjs +51 -64
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.d.ts.map +1 -1
- package/dist/studio/server.js +51 -64
- package/dist/studio/server.js.map +1 -1
- package/package.json +1 -1
- package/dist/src/history/record-revision.d.ts +0 -14
- package/dist/src/history/record-revision.d.ts.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -509,7 +509,7 @@ function seoFieldsFromEn(enDoc) {
|
|
|
509
509
|
redirectTo: enDoc.redirectTo
|
|
510
510
|
};
|
|
511
511
|
}
|
|
512
|
-
var SCHEMA_VERSION =
|
|
512
|
+
var SCHEMA_VERSION = 4;
|
|
513
513
|
var MIGRATIONS = [
|
|
514
514
|
`CREATE TABLE IF NOT EXISTS meta (
|
|
515
515
|
key TEXT PRIMARY KEY,
|
|
@@ -529,20 +529,6 @@ var MIGRATIONS = [
|
|
|
529
529
|
)`,
|
|
530
530
|
`CREATE INDEX IF NOT EXISTS idx_translations_type_locale
|
|
531
531
|
ON translations(content_type, locale)`,
|
|
532
|
-
`CREATE TABLE IF NOT EXISTS revisions (
|
|
533
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
534
|
-
content_type TEXT NOT NULL,
|
|
535
|
-
en_slug TEXT NOT NULL,
|
|
536
|
-
locale TEXT,
|
|
537
|
-
revision_kind TEXT NOT NULL,
|
|
538
|
-
en_hash TEXT NOT NULL,
|
|
539
|
-
body_hash TEXT NOT NULL,
|
|
540
|
-
created_at TEXT NOT NULL,
|
|
541
|
-
model TEXT,
|
|
542
|
-
body_preview TEXT
|
|
543
|
-
)`,
|
|
544
|
-
`CREATE INDEX IF NOT EXISTS idx_revisions_lookup
|
|
545
|
-
ON revisions(content_type, en_slug, locale, created_at DESC)`,
|
|
546
532
|
`CREATE TABLE IF NOT EXISTS slug_aliases (
|
|
547
533
|
content_type TEXT NOT NULL,
|
|
548
534
|
canonical_en_slug TEXT NOT NULL,
|
|
@@ -559,7 +545,19 @@ var MIGRATIONS = [
|
|
|
559
545
|
locale_slug TEXT NOT NULL,
|
|
560
546
|
captured_at TEXT NOT NULL,
|
|
561
547
|
PRIMARY KEY (content_type, alias_en_slug, locale)
|
|
562
|
-
)
|
|
548
|
+
)`,
|
|
549
|
+
`CREATE TABLE IF NOT EXISTS en_snapshots (
|
|
550
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
551
|
+
content_type TEXT NOT NULL,
|
|
552
|
+
en_slug TEXT NOT NULL,
|
|
553
|
+
en_hash TEXT NOT NULL,
|
|
554
|
+
frontmatter_json TEXT NOT NULL,
|
|
555
|
+
body TEXT NOT NULL,
|
|
556
|
+
created_at TEXT NOT NULL,
|
|
557
|
+
UNIQUE (content_type, en_slug, en_hash)
|
|
558
|
+
)`,
|
|
559
|
+
`CREATE INDEX IF NOT EXISTS idx_en_snapshots_lookup
|
|
560
|
+
ON en_snapshots(content_type, en_slug, created_at DESC)`
|
|
563
561
|
];
|
|
564
562
|
function resolveStorePath(config) {
|
|
565
563
|
return config.storePath;
|
|
@@ -581,12 +579,19 @@ function addColumnIfMissing(db, table, column, ddlType) {
|
|
|
581
579
|
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${ddlType}`);
|
|
582
580
|
}
|
|
583
581
|
}
|
|
582
|
+
function readSchemaVersion(db) {
|
|
583
|
+
const row = db.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get();
|
|
584
|
+
return row ? Number.parseInt(row.value, 10) || 0 : 0;
|
|
585
|
+
}
|
|
584
586
|
function migrate(db) {
|
|
587
|
+
const previousVersion = readSchemaVersion(db);
|
|
585
588
|
for (const sql of MIGRATIONS) {
|
|
586
589
|
db.exec(sql);
|
|
587
590
|
}
|
|
588
|
-
|
|
589
|
-
|
|
591
|
+
if (previousVersion < 4) {
|
|
592
|
+
db.exec(`DROP TABLE IF EXISTS revisions`);
|
|
593
|
+
}
|
|
594
|
+
addColumnIfMissing(db, "translations", "snapshot_id", "INTEGER");
|
|
590
595
|
db.prepare(
|
|
591
596
|
`INSERT INTO meta(key, value) VALUES('schema_version', ?)
|
|
592
597
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value`
|
|
@@ -594,18 +599,38 @@ function migrate(db) {
|
|
|
594
599
|
}
|
|
595
600
|
|
|
596
601
|
// src/storage/translations.ts
|
|
602
|
+
function getOrCreateEnSnapshot(db, input) {
|
|
603
|
+
db.prepare(
|
|
604
|
+
`INSERT OR IGNORE INTO en_snapshots (
|
|
605
|
+
content_type, en_slug, en_hash, frontmatter_json, body, created_at
|
|
606
|
+
) VALUES (?, ?, ?, ?, ?, ?)`
|
|
607
|
+
).run(
|
|
608
|
+
input.contentType,
|
|
609
|
+
input.enSlug,
|
|
610
|
+
input.enHash,
|
|
611
|
+
JSON.stringify(input.frontmatter),
|
|
612
|
+
input.body,
|
|
613
|
+
input.createdAt
|
|
614
|
+
);
|
|
615
|
+
const row = db.prepare(
|
|
616
|
+
`SELECT id FROM en_snapshots
|
|
617
|
+
WHERE content_type = ? AND en_slug = ? AND en_hash = ?`
|
|
618
|
+
).get(input.contentType, input.enSlug, input.enHash);
|
|
619
|
+
return row.id;
|
|
620
|
+
}
|
|
597
621
|
function upsertTranslation(db, input) {
|
|
598
622
|
db.prepare(
|
|
599
623
|
`INSERT INTO translations (
|
|
600
|
-
content_type, en_slug, locale, slug, frontmatter_json, body, en_hash, translated_at, model
|
|
601
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
624
|
+
content_type, en_slug, locale, slug, frontmatter_json, body, en_hash, translated_at, model, snapshot_id
|
|
625
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
602
626
|
ON CONFLICT(content_type, en_slug, locale) DO UPDATE SET
|
|
603
627
|
slug = excluded.slug,
|
|
604
628
|
frontmatter_json = excluded.frontmatter_json,
|
|
605
629
|
body = excluded.body,
|
|
606
630
|
en_hash = excluded.en_hash,
|
|
607
631
|
translated_at = excluded.translated_at,
|
|
608
|
-
model = excluded.model
|
|
632
|
+
model = excluded.model,
|
|
633
|
+
snapshot_id = excluded.snapshot_id`
|
|
609
634
|
).run(
|
|
610
635
|
input.contentType,
|
|
611
636
|
input.enSlug,
|
|
@@ -615,7 +640,8 @@ function upsertTranslation(db, input) {
|
|
|
615
640
|
input.body,
|
|
616
641
|
input.enHash,
|
|
617
642
|
input.translatedAt,
|
|
618
|
-
input.model
|
|
643
|
+
input.model,
|
|
644
|
+
input.snapshotId
|
|
619
645
|
);
|
|
620
646
|
}
|
|
621
647
|
function getTranslation(db, contentType, enSlug, locale) {
|
|
@@ -634,27 +660,6 @@ function listTranslationsForEnSlug(db, contentType, enSlug) {
|
|
|
634
660
|
function bulkLoadTranslations(db) {
|
|
635
661
|
return db.prepare(`SELECT * FROM translations ORDER BY content_type, en_slug, locale`).all();
|
|
636
662
|
}
|
|
637
|
-
function appendRevision(db, input) {
|
|
638
|
-
const result = db.prepare(
|
|
639
|
-
`INSERT INTO revisions (
|
|
640
|
-
content_type, en_slug, locale, revision_kind, en_hash, body_hash, created_at,
|
|
641
|
-
model, body_preview, frontmatter_json, body
|
|
642
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
643
|
-
).run(
|
|
644
|
-
input.contentType,
|
|
645
|
-
input.enSlug,
|
|
646
|
-
input.locale,
|
|
647
|
-
input.revisionKind,
|
|
648
|
-
input.enHash,
|
|
649
|
-
input.bodyHash,
|
|
650
|
-
input.createdAt,
|
|
651
|
-
input.model ?? null,
|
|
652
|
-
input.bodyPreview ?? null,
|
|
653
|
-
input.frontmatterJson ?? null,
|
|
654
|
-
input.body ?? null
|
|
655
|
-
);
|
|
656
|
-
return Number(result.lastInsertRowid);
|
|
657
|
-
}
|
|
658
663
|
|
|
659
664
|
// src/loader/normalize-en.ts
|
|
660
665
|
function normalizeEnFrontmatter(data) {
|
|
@@ -2059,9 +2064,6 @@ function computePageEnHash(translatableFrontmatter, body) {
|
|
|
2059
2064
|
const payload = JSON.stringify({ frontmatter: translatableFrontmatter, body });
|
|
2060
2065
|
return sha256(payload);
|
|
2061
2066
|
}
|
|
2062
|
-
function computeBodyHash(body) {
|
|
2063
|
-
return sha256(body);
|
|
2064
|
-
}
|
|
2065
2067
|
|
|
2066
2068
|
// src/translate/worklist.ts
|
|
2067
2069
|
function listEnSlugs3(rootDir, contentDir) {
|
|
@@ -2122,23 +2124,18 @@ function resolveLocalesFromPreset(config, preset, explicitLocales) {
|
|
|
2122
2124
|
return config.locales.filter((l) => l !== config.defaultLocale);
|
|
2123
2125
|
}
|
|
2124
2126
|
|
|
2125
|
-
// src/history/record-
|
|
2126
|
-
function
|
|
2127
|
-
const
|
|
2128
|
-
const id =
|
|
2127
|
+
// src/history/record-snapshot.ts
|
|
2128
|
+
function recordEnSnapshot(config, input, db) {
|
|
2129
|
+
const ownDb = db ?? openStore(config, "readwrite");
|
|
2130
|
+
const id = getOrCreateEnSnapshot(ownDb, {
|
|
2129
2131
|
contentType: input.contentType,
|
|
2130
2132
|
enSlug: input.enSlug,
|
|
2131
|
-
locale: input.locale,
|
|
2132
|
-
revisionKind: input.revisionKind,
|
|
2133
2133
|
enHash: input.enHash,
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
bodyPreview: input.body.slice(0, 200),
|
|
2138
|
-
frontmatterJson: input.frontmatter ? JSON.stringify(input.frontmatter) : null,
|
|
2139
|
-
body: input.body
|
|
2134
|
+
frontmatter: input.frontmatter,
|
|
2135
|
+
body: input.body,
|
|
2136
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2140
2137
|
});
|
|
2141
|
-
db.close();
|
|
2138
|
+
if (!db) ownDb.close();
|
|
2142
2139
|
return id;
|
|
2143
2140
|
}
|
|
2144
2141
|
|
|
@@ -2515,6 +2512,17 @@ async function translatePage(config, item, options = {}) {
|
|
|
2515
2512
|
throw new Error(`Translation validation failed: ${validated.error}`);
|
|
2516
2513
|
}
|
|
2517
2514
|
const writeDb = openStore(config, "readwrite");
|
|
2515
|
+
const snapshotId = recordEnSnapshot(
|
|
2516
|
+
config,
|
|
2517
|
+
{
|
|
2518
|
+
contentType: type.id,
|
|
2519
|
+
enSlug: item.enSlug,
|
|
2520
|
+
enHash: currentEnHash,
|
|
2521
|
+
frontmatter: payload.frontmatter,
|
|
2522
|
+
body: payload.body
|
|
2523
|
+
},
|
|
2524
|
+
writeDb
|
|
2525
|
+
);
|
|
2518
2526
|
upsertTranslation(writeDb, {
|
|
2519
2527
|
contentType: type.id,
|
|
2520
2528
|
enSlug: item.enSlug,
|
|
@@ -2524,19 +2532,10 @@ async function translatePage(config, item, options = {}) {
|
|
|
2524
2532
|
body: result.parsed.body,
|
|
2525
2533
|
enHash: currentEnHash,
|
|
2526
2534
|
translatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2527
|
-
model: result.model
|
|
2535
|
+
model: result.model,
|
|
2536
|
+
snapshotId
|
|
2528
2537
|
});
|
|
2529
2538
|
writeDb.close();
|
|
2530
|
-
recordRevision(config, {
|
|
2531
|
-
contentType: type.id,
|
|
2532
|
-
enSlug: item.enSlug,
|
|
2533
|
-
locale: item.locale,
|
|
2534
|
-
revisionKind: "translation",
|
|
2535
|
-
enHash: currentEnHash,
|
|
2536
|
-
body: result.parsed.body,
|
|
2537
|
-
frontmatter: validated.frontmatter,
|
|
2538
|
-
model: result.model
|
|
2539
|
-
});
|
|
2540
2539
|
const estimatedCostUsd = estimateTranslationCostUsd(
|
|
2541
2540
|
normalizeGeminiDisplayName(result.model),
|
|
2542
2541
|
result.usage.inputTokens,
|