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.js
CHANGED
|
@@ -498,7 +498,7 @@ function seoFieldsFromEn(enDoc) {
|
|
|
498
498
|
redirectTo: enDoc.redirectTo
|
|
499
499
|
};
|
|
500
500
|
}
|
|
501
|
-
var SCHEMA_VERSION =
|
|
501
|
+
var SCHEMA_VERSION = 4;
|
|
502
502
|
var MIGRATIONS = [
|
|
503
503
|
`CREATE TABLE IF NOT EXISTS meta (
|
|
504
504
|
key TEXT PRIMARY KEY,
|
|
@@ -518,20 +518,6 @@ var MIGRATIONS = [
|
|
|
518
518
|
)`,
|
|
519
519
|
`CREATE INDEX IF NOT EXISTS idx_translations_type_locale
|
|
520
520
|
ON translations(content_type, locale)`,
|
|
521
|
-
`CREATE TABLE IF NOT EXISTS revisions (
|
|
522
|
-
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
523
|
-
content_type TEXT NOT NULL,
|
|
524
|
-
en_slug TEXT NOT NULL,
|
|
525
|
-
locale TEXT,
|
|
526
|
-
revision_kind TEXT NOT NULL,
|
|
527
|
-
en_hash TEXT NOT NULL,
|
|
528
|
-
body_hash TEXT NOT NULL,
|
|
529
|
-
created_at TEXT NOT NULL,
|
|
530
|
-
model TEXT,
|
|
531
|
-
body_preview TEXT
|
|
532
|
-
)`,
|
|
533
|
-
`CREATE INDEX IF NOT EXISTS idx_revisions_lookup
|
|
534
|
-
ON revisions(content_type, en_slug, locale, created_at DESC)`,
|
|
535
521
|
`CREATE TABLE IF NOT EXISTS slug_aliases (
|
|
536
522
|
content_type TEXT NOT NULL,
|
|
537
523
|
canonical_en_slug TEXT NOT NULL,
|
|
@@ -548,7 +534,19 @@ var MIGRATIONS = [
|
|
|
548
534
|
locale_slug TEXT NOT NULL,
|
|
549
535
|
captured_at TEXT NOT NULL,
|
|
550
536
|
PRIMARY KEY (content_type, alias_en_slug, locale)
|
|
551
|
-
)
|
|
537
|
+
)`,
|
|
538
|
+
`CREATE TABLE IF NOT EXISTS en_snapshots (
|
|
539
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
540
|
+
content_type TEXT NOT NULL,
|
|
541
|
+
en_slug TEXT NOT NULL,
|
|
542
|
+
en_hash TEXT NOT NULL,
|
|
543
|
+
frontmatter_json TEXT NOT NULL,
|
|
544
|
+
body TEXT NOT NULL,
|
|
545
|
+
created_at TEXT NOT NULL,
|
|
546
|
+
UNIQUE (content_type, en_slug, en_hash)
|
|
547
|
+
)`,
|
|
548
|
+
`CREATE INDEX IF NOT EXISTS idx_en_snapshots_lookup
|
|
549
|
+
ON en_snapshots(content_type, en_slug, created_at DESC)`
|
|
552
550
|
];
|
|
553
551
|
function resolveStorePath(config) {
|
|
554
552
|
return config.storePath;
|
|
@@ -570,12 +568,19 @@ function addColumnIfMissing(db, table, column, ddlType) {
|
|
|
570
568
|
db.exec(`ALTER TABLE ${table} ADD COLUMN ${column} ${ddlType}`);
|
|
571
569
|
}
|
|
572
570
|
}
|
|
571
|
+
function readSchemaVersion(db) {
|
|
572
|
+
const row = db.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get();
|
|
573
|
+
return row ? Number.parseInt(row.value, 10) || 0 : 0;
|
|
574
|
+
}
|
|
573
575
|
function migrate(db) {
|
|
576
|
+
const previousVersion = readSchemaVersion(db);
|
|
574
577
|
for (const sql of MIGRATIONS) {
|
|
575
578
|
db.exec(sql);
|
|
576
579
|
}
|
|
577
|
-
|
|
578
|
-
|
|
580
|
+
if (previousVersion < 4) {
|
|
581
|
+
db.exec(`DROP TABLE IF EXISTS revisions`);
|
|
582
|
+
}
|
|
583
|
+
addColumnIfMissing(db, "translations", "snapshot_id", "INTEGER");
|
|
579
584
|
db.prepare(
|
|
580
585
|
`INSERT INTO meta(key, value) VALUES('schema_version', ?)
|
|
581
586
|
ON CONFLICT(key) DO UPDATE SET value = excluded.value`
|
|
@@ -583,18 +588,38 @@ function migrate(db) {
|
|
|
583
588
|
}
|
|
584
589
|
|
|
585
590
|
// src/storage/translations.ts
|
|
591
|
+
function getOrCreateEnSnapshot(db, input) {
|
|
592
|
+
db.prepare(
|
|
593
|
+
`INSERT OR IGNORE INTO en_snapshots (
|
|
594
|
+
content_type, en_slug, en_hash, frontmatter_json, body, created_at
|
|
595
|
+
) VALUES (?, ?, ?, ?, ?, ?)`
|
|
596
|
+
).run(
|
|
597
|
+
input.contentType,
|
|
598
|
+
input.enSlug,
|
|
599
|
+
input.enHash,
|
|
600
|
+
JSON.stringify(input.frontmatter),
|
|
601
|
+
input.body,
|
|
602
|
+
input.createdAt
|
|
603
|
+
);
|
|
604
|
+
const row = db.prepare(
|
|
605
|
+
`SELECT id FROM en_snapshots
|
|
606
|
+
WHERE content_type = ? AND en_slug = ? AND en_hash = ?`
|
|
607
|
+
).get(input.contentType, input.enSlug, input.enHash);
|
|
608
|
+
return row.id;
|
|
609
|
+
}
|
|
586
610
|
function upsertTranslation(db, input) {
|
|
587
611
|
db.prepare(
|
|
588
612
|
`INSERT INTO translations (
|
|
589
|
-
content_type, en_slug, locale, slug, frontmatter_json, body, en_hash, translated_at, model
|
|
590
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
613
|
+
content_type, en_slug, locale, slug, frontmatter_json, body, en_hash, translated_at, model, snapshot_id
|
|
614
|
+
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
|
591
615
|
ON CONFLICT(content_type, en_slug, locale) DO UPDATE SET
|
|
592
616
|
slug = excluded.slug,
|
|
593
617
|
frontmatter_json = excluded.frontmatter_json,
|
|
594
618
|
body = excluded.body,
|
|
595
619
|
en_hash = excluded.en_hash,
|
|
596
620
|
translated_at = excluded.translated_at,
|
|
597
|
-
model = excluded.model
|
|
621
|
+
model = excluded.model,
|
|
622
|
+
snapshot_id = excluded.snapshot_id`
|
|
598
623
|
).run(
|
|
599
624
|
input.contentType,
|
|
600
625
|
input.enSlug,
|
|
@@ -604,7 +629,8 @@ function upsertTranslation(db, input) {
|
|
|
604
629
|
input.body,
|
|
605
630
|
input.enHash,
|
|
606
631
|
input.translatedAt,
|
|
607
|
-
input.model
|
|
632
|
+
input.model,
|
|
633
|
+
input.snapshotId
|
|
608
634
|
);
|
|
609
635
|
}
|
|
610
636
|
function getTranslation(db, contentType, enSlug, locale) {
|
|
@@ -623,27 +649,6 @@ function listTranslationsForEnSlug(db, contentType, enSlug) {
|
|
|
623
649
|
function bulkLoadTranslations(db) {
|
|
624
650
|
return db.prepare(`SELECT * FROM translations ORDER BY content_type, en_slug, locale`).all();
|
|
625
651
|
}
|
|
626
|
-
function appendRevision(db, input) {
|
|
627
|
-
const result = db.prepare(
|
|
628
|
-
`INSERT INTO revisions (
|
|
629
|
-
content_type, en_slug, locale, revision_kind, en_hash, body_hash, created_at,
|
|
630
|
-
model, body_preview, frontmatter_json, body
|
|
631
|
-
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
|
|
632
|
-
).run(
|
|
633
|
-
input.contentType,
|
|
634
|
-
input.enSlug,
|
|
635
|
-
input.locale,
|
|
636
|
-
input.revisionKind,
|
|
637
|
-
input.enHash,
|
|
638
|
-
input.bodyHash,
|
|
639
|
-
input.createdAt,
|
|
640
|
-
input.model ?? null,
|
|
641
|
-
input.bodyPreview ?? null,
|
|
642
|
-
input.frontmatterJson ?? null,
|
|
643
|
-
input.body ?? null
|
|
644
|
-
);
|
|
645
|
-
return Number(result.lastInsertRowid);
|
|
646
|
-
}
|
|
647
652
|
|
|
648
653
|
// src/loader/normalize-en.ts
|
|
649
654
|
function normalizeEnFrontmatter(data) {
|
|
@@ -2048,9 +2053,6 @@ function computePageEnHash(translatableFrontmatter, body) {
|
|
|
2048
2053
|
const payload = JSON.stringify({ frontmatter: translatableFrontmatter, body });
|
|
2049
2054
|
return sha256(payload);
|
|
2050
2055
|
}
|
|
2051
|
-
function computeBodyHash(body) {
|
|
2052
|
-
return sha256(body);
|
|
2053
|
-
}
|
|
2054
2056
|
|
|
2055
2057
|
// src/translate/worklist.ts
|
|
2056
2058
|
function listEnSlugs3(rootDir, contentDir) {
|
|
@@ -2111,23 +2113,18 @@ function resolveLocalesFromPreset(config, preset, explicitLocales) {
|
|
|
2111
2113
|
return config.locales.filter((l) => l !== config.defaultLocale);
|
|
2112
2114
|
}
|
|
2113
2115
|
|
|
2114
|
-
// src/history/record-
|
|
2115
|
-
function
|
|
2116
|
-
const
|
|
2117
|
-
const id =
|
|
2116
|
+
// src/history/record-snapshot.ts
|
|
2117
|
+
function recordEnSnapshot(config, input, db) {
|
|
2118
|
+
const ownDb = db ?? openStore(config, "readwrite");
|
|
2119
|
+
const id = getOrCreateEnSnapshot(ownDb, {
|
|
2118
2120
|
contentType: input.contentType,
|
|
2119
2121
|
enSlug: input.enSlug,
|
|
2120
|
-
locale: input.locale,
|
|
2121
|
-
revisionKind: input.revisionKind,
|
|
2122
2122
|
enHash: input.enHash,
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
bodyPreview: input.body.slice(0, 200),
|
|
2127
|
-
frontmatterJson: input.frontmatter ? JSON.stringify(input.frontmatter) : null,
|
|
2128
|
-
body: input.body
|
|
2123
|
+
frontmatter: input.frontmatter,
|
|
2124
|
+
body: input.body,
|
|
2125
|
+
createdAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
2129
2126
|
});
|
|
2130
|
-
db.close();
|
|
2127
|
+
if (!db) ownDb.close();
|
|
2131
2128
|
return id;
|
|
2132
2129
|
}
|
|
2133
2130
|
|
|
@@ -2504,6 +2501,17 @@ async function translatePage(config, item, options = {}) {
|
|
|
2504
2501
|
throw new Error(`Translation validation failed: ${validated.error}`);
|
|
2505
2502
|
}
|
|
2506
2503
|
const writeDb = openStore(config, "readwrite");
|
|
2504
|
+
const snapshotId = recordEnSnapshot(
|
|
2505
|
+
config,
|
|
2506
|
+
{
|
|
2507
|
+
contentType: type.id,
|
|
2508
|
+
enSlug: item.enSlug,
|
|
2509
|
+
enHash: currentEnHash,
|
|
2510
|
+
frontmatter: payload.frontmatter,
|
|
2511
|
+
body: payload.body
|
|
2512
|
+
},
|
|
2513
|
+
writeDb
|
|
2514
|
+
);
|
|
2507
2515
|
upsertTranslation(writeDb, {
|
|
2508
2516
|
contentType: type.id,
|
|
2509
2517
|
enSlug: item.enSlug,
|
|
@@ -2513,19 +2521,10 @@ async function translatePage(config, item, options = {}) {
|
|
|
2513
2521
|
body: result.parsed.body,
|
|
2514
2522
|
enHash: currentEnHash,
|
|
2515
2523
|
translatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2516
|
-
model: result.model
|
|
2524
|
+
model: result.model,
|
|
2525
|
+
snapshotId
|
|
2517
2526
|
});
|
|
2518
2527
|
writeDb.close();
|
|
2519
|
-
recordRevision(config, {
|
|
2520
|
-
contentType: type.id,
|
|
2521
|
-
enSlug: item.enSlug,
|
|
2522
|
-
locale: item.locale,
|
|
2523
|
-
revisionKind: "translation",
|
|
2524
|
-
enHash: currentEnHash,
|
|
2525
|
-
body: result.parsed.body,
|
|
2526
|
-
frontmatter: validated.frontmatter,
|
|
2527
|
-
model: result.model
|
|
2528
|
-
});
|
|
2529
2528
|
const estimatedCostUsd = estimateTranslationCostUsd(
|
|
2530
2529
|
normalizeGeminiDisplayName(result.model),
|
|
2531
2530
|
result.usage.inputTokens,
|