scribe-cms 0.0.12 → 0.0.14
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/README.md +21 -6
- package/dist/cli/index.cjs +1207 -204
- package/dist/cli/index.cjs.map +1 -1
- package/dist/cli/index.js +1208 -205
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/prompt-translate.d.ts +3 -0
- package/dist/cli/prompt-translate.d.ts.map +1 -1
- package/dist/cli/translate-progress.d.ts.map +1 -1
- package/dist/index.cjs +969 -166
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +970 -168
- package/dist/index.js.map +1 -1
- package/dist/runtime.cjs +136 -62
- package/dist/runtime.cjs.map +1 -1
- package/dist/runtime.js +136 -62
- package/dist/runtime.js.map +1 -1
- package/dist/src/config/resolve-config.d.ts.map +1 -1
- package/dist/src/core/introspect-schema.d.ts +7 -1
- package/dist/src/core/introspect-schema.d.ts.map +1 -1
- package/dist/src/core/types.d.ts +6 -0
- package/dist/src/core/types.d.ts.map +1 -1
- package/dist/src/create-project.d.ts.map +1 -1
- package/dist/src/i18n/resolve-document.d.ts +1 -1
- package/dist/src/i18n/resolve-document.d.ts.map +1 -1
- package/dist/src/index.d.ts +3 -3
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/storage/batch-jobs.d.ts +53 -0
- package/dist/src/storage/batch-jobs.d.ts.map +1 -0
- package/dist/src/storage/sqlite.d.ts.map +1 -1
- package/dist/src/translate/batch-worklist.d.ts +87 -0
- package/dist/src/translate/batch-worklist.d.ts.map +1 -0
- package/dist/src/translate/gemini-batch.d.ts +26 -0
- package/dist/src/translate/gemini-batch.d.ts.map +1 -0
- package/dist/src/translate/gemini-client.d.ts +18 -0
- package/dist/src/translate/gemini-client.d.ts.map +1 -1
- package/dist/src/translate/gemini-models.d.ts +9 -0
- package/dist/src/translate/gemini-models.d.ts.map +1 -1
- package/dist/src/translate/gemini-pricing.d.ts +2 -1
- package/dist/src/translate/gemini-pricing.d.ts.map +1 -1
- package/dist/src/translate/page-translator.d.ts +25 -52
- package/dist/src/translate/page-translator.d.ts.map +1 -1
- package/dist/src/translate/prompts/translation-prompt.d.ts +6 -0
- package/dist/src/translate/prompts/translation-prompt.d.ts.map +1 -1
- package/dist/src/translate/response-schema.d.ts +8 -1
- package/dist/src/translate/response-schema.d.ts.map +1 -1
- package/dist/src/translate/retry.d.ts +16 -0
- package/dist/src/translate/retry.d.ts.map +1 -0
- package/dist/src/translate/sanitize-mdx-jsx.d.ts.map +1 -1
- package/dist/src/translate/translate-core.d.ts +155 -0
- package/dist/src/translate/translate-core.d.ts.map +1 -0
- package/dist/studio/server.cjs +84 -47
- package/dist/studio/server.cjs.map +1 -1
- package/dist/studio/server.js +84 -47
- package/dist/studio/server.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sanitize-mdx-jsx.d.ts","sourceRoot":"","sources":["../../../src/translate/sanitize-mdx-jsx.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,
|
|
1
|
+
{"version":3,"file":"sanitize-mdx-jsx.d.ts","sourceRoot":"","sources":["../../../src/translate/sanitize-mdx-jsx.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,6BAA6B,CAAC,IAAI,EAAE,MAAM,GAAG;IAC3D,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,OAAO,CAAC;CACnB,CAkHA"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import type { ContentTypeConfig, ScribeConfig, ScribeDocument } from "../core/types.js";
|
|
2
|
+
import type { GeminiTokenUsage } from "./gemini-client.js";
|
|
3
|
+
import { type TranslationCostMode } from "./gemini-pricing.js";
|
|
4
|
+
import type { TranslationWorkItem } from "./worklist.js";
|
|
5
|
+
export type TranslateMode = "batch" | "direct";
|
|
6
|
+
export interface TranslatePageResult {
|
|
7
|
+
contentType: string;
|
|
8
|
+
enSlug: string;
|
|
9
|
+
locale: string;
|
|
10
|
+
skipped: boolean;
|
|
11
|
+
failed?: boolean;
|
|
12
|
+
reason?: "fresh" | "in-flight";
|
|
13
|
+
model?: string;
|
|
14
|
+
usage?: GeminiTokenUsage;
|
|
15
|
+
estimatedCostUsd?: number;
|
|
16
|
+
durationMs?: number;
|
|
17
|
+
error?: string;
|
|
18
|
+
slugAdjusted?: {
|
|
19
|
+
from: string;
|
|
20
|
+
to: string;
|
|
21
|
+
matchedCode: string;
|
|
22
|
+
};
|
|
23
|
+
mdxAdjusted?: boolean;
|
|
24
|
+
}
|
|
25
|
+
export interface TranslateWorklistTotals {
|
|
26
|
+
translated: number;
|
|
27
|
+
skipped: number;
|
|
28
|
+
failed: number;
|
|
29
|
+
inputTokens: number;
|
|
30
|
+
outputTokens: number;
|
|
31
|
+
estimatedCostUsd: number;
|
|
32
|
+
durationMs: number;
|
|
33
|
+
}
|
|
34
|
+
export type TranslateProgressEvent = {
|
|
35
|
+
type: "start";
|
|
36
|
+
total: number;
|
|
37
|
+
concurrency: number;
|
|
38
|
+
dryRun: boolean;
|
|
39
|
+
model?: string;
|
|
40
|
+
mode?: TranslateMode;
|
|
41
|
+
} | {
|
|
42
|
+
type: "item-start";
|
|
43
|
+
item: TranslationWorkItem;
|
|
44
|
+
active: string[];
|
|
45
|
+
} | {
|
|
46
|
+
type: "item-done";
|
|
47
|
+
result: TranslatePageResult;
|
|
48
|
+
} | {
|
|
49
|
+
type: "batch-submitted";
|
|
50
|
+
name: string;
|
|
51
|
+
count: number;
|
|
52
|
+
model?: string;
|
|
53
|
+
jobIndex: number;
|
|
54
|
+
jobCount: number;
|
|
55
|
+
resumed?: boolean;
|
|
56
|
+
/** ISO timestamp of the job's actual submission (persisted created_at). */
|
|
57
|
+
createdAt?: string;
|
|
58
|
+
} | {
|
|
59
|
+
type: "batch-polling";
|
|
60
|
+
name: string;
|
|
61
|
+
state: string;
|
|
62
|
+
/** Elapsed since the job was submitted (not since the CLI started). */
|
|
63
|
+
elapsedMs: number;
|
|
64
|
+
jobIndex: number;
|
|
65
|
+
jobCount: number;
|
|
66
|
+
} | {
|
|
67
|
+
type: "batch-done";
|
|
68
|
+
name: string;
|
|
69
|
+
state: string;
|
|
70
|
+
model?: string;
|
|
71
|
+
count: number;
|
|
72
|
+
jobIndex: number;
|
|
73
|
+
jobCount: number;
|
|
74
|
+
translated: number;
|
|
75
|
+
failed: number;
|
|
76
|
+
inputTokens: number;
|
|
77
|
+
outputTokens: number;
|
|
78
|
+
estimatedCostUsd: number;
|
|
79
|
+
/** Elapsed since the job was submitted. */
|
|
80
|
+
elapsedMs: number;
|
|
81
|
+
/**
|
|
82
|
+
* True when a concurrent scribe process won the ingestion claim: the
|
|
83
|
+
* job's results were saved by that process, this one has nothing to add.
|
|
84
|
+
*/
|
|
85
|
+
alreadyIngested?: boolean;
|
|
86
|
+
} | {
|
|
87
|
+
type: "done";
|
|
88
|
+
results: TranslatePageResult[];
|
|
89
|
+
totals: TranslateWorklistTotals;
|
|
90
|
+
};
|
|
91
|
+
/** Stable identity for a worklist item / batch item row. */
|
|
92
|
+
export declare function translationItemKey(item: {
|
|
93
|
+
contentType?: string;
|
|
94
|
+
content_type?: string;
|
|
95
|
+
enSlug?: string;
|
|
96
|
+
en_slug?: string;
|
|
97
|
+
locale: string;
|
|
98
|
+
}): string;
|
|
99
|
+
export declare function summarizeResults(results: TranslatePageResult[], durationMs: number): TranslateWorklistTotals;
|
|
100
|
+
export declare function formatTranslateError(error: unknown): string;
|
|
101
|
+
export declare function baseForItem(item: TranslationWorkItem): Pick<TranslatePageResult, "contentType" | "enSlug" | "locale">;
|
|
102
|
+
/** Everything needed to submit and finalize one translation request. */
|
|
103
|
+
export interface PreparedTranslation {
|
|
104
|
+
item: TranslationWorkItem;
|
|
105
|
+
type: ContentTypeConfig;
|
|
106
|
+
enDoc: ScribeDocument;
|
|
107
|
+
payload: {
|
|
108
|
+
frontmatter: Record<string, unknown>;
|
|
109
|
+
body: string;
|
|
110
|
+
};
|
|
111
|
+
currentEnHash: string;
|
|
112
|
+
existingSlug?: string;
|
|
113
|
+
/** Configured model (may be undefined; env/default applies downstream). */
|
|
114
|
+
model?: string;
|
|
115
|
+
prompt: string;
|
|
116
|
+
responseSchema?: Record<string, unknown>;
|
|
117
|
+
}
|
|
118
|
+
export type PrepareOutcome = {
|
|
119
|
+
status: "ready";
|
|
120
|
+
prepared: PreparedTranslation;
|
|
121
|
+
} | {
|
|
122
|
+
status: "done";
|
|
123
|
+
result: TranslatePageResult;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Shared pre-flight for the direct and batch paths: read the EN doc, skip when
|
|
127
|
+
* the stored translation is fresh, and build the prompt + response schema.
|
|
128
|
+
* Throws on unrecoverable item errors (unknown type, missing EN doc).
|
|
129
|
+
*/
|
|
130
|
+
export declare function prepareTranslation(config: ScribeConfig, item: TranslationWorkItem, options: {
|
|
131
|
+
model?: string;
|
|
132
|
+
force?: boolean;
|
|
133
|
+
}, startedAt: number): PrepareOutcome;
|
|
134
|
+
/**
|
|
135
|
+
* Shared post-processing for the direct and batch paths: strip locale suffixes
|
|
136
|
+
* from the slug, validate frontmatter + MDX body, snapshot the EN source and
|
|
137
|
+
* upsert the translation. Never throws — failures come back as a failed result.
|
|
138
|
+
* Pass `snapshotId` when the EN snapshot was already recorded (batch submission
|
|
139
|
+
* time) so ingestion does not depend on the current EN files.
|
|
140
|
+
*/
|
|
141
|
+
export declare function finalizeTranslation(config: ScribeConfig, prepared: PreparedTranslation, output: {
|
|
142
|
+
model: string;
|
|
143
|
+
parsed: {
|
|
144
|
+
frontmatter: Record<string, unknown>;
|
|
145
|
+
body: string;
|
|
146
|
+
slug?: string;
|
|
147
|
+
};
|
|
148
|
+
usage: GeminiTokenUsage;
|
|
149
|
+
}, options: {
|
|
150
|
+
costMode: TranslationCostMode;
|
|
151
|
+
startedAt: number;
|
|
152
|
+
snapshotId?: number;
|
|
153
|
+
}): TranslatePageResult;
|
|
154
|
+
export declare function displayModelFor(prepared: PreparedTranslation): string;
|
|
155
|
+
//# sourceMappingURL=translate-core.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"translate-core.d.ts","sourceRoot":"","sources":["../../../src/translate/translate-core.ts"],"names":[],"mappings":"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"}
|
package/dist/studio/server.cjs
CHANGED
|
@@ -51,20 +51,16 @@ function getRelationTarget(schema) {
|
|
|
51
51
|
}
|
|
52
52
|
return null;
|
|
53
53
|
}
|
|
54
|
-
function
|
|
54
|
+
function peelOptionalWrappers(schema) {
|
|
55
55
|
let current = schema;
|
|
56
56
|
for (let i = 0; i < 8; i++) {
|
|
57
|
-
const
|
|
58
|
-
if (
|
|
59
|
-
current =
|
|
57
|
+
const type = current._def?.type;
|
|
58
|
+
if (type === "optional" || type === "nullable") {
|
|
59
|
+
current = current.unwrap();
|
|
60
60
|
continue;
|
|
61
61
|
}
|
|
62
|
-
if (
|
|
63
|
-
current =
|
|
64
|
-
continue;
|
|
65
|
-
}
|
|
66
|
-
if (anySchema._def?.innerType) {
|
|
67
|
-
current = anySchema._def.innerType;
|
|
62
|
+
if (type === "default") {
|
|
63
|
+
current = current.removeDefault();
|
|
68
64
|
continue;
|
|
69
65
|
}
|
|
70
66
|
break;
|
|
@@ -73,6 +69,12 @@ function unwrapSchema(schema) {
|
|
|
73
69
|
}
|
|
74
70
|
|
|
75
71
|
// src/core/introspect-schema.ts
|
|
72
|
+
function getArrayElement(schema) {
|
|
73
|
+
if (schema instanceof Object && "element" in schema && schema._def?.type === "array") {
|
|
74
|
+
return schema.element;
|
|
75
|
+
}
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
76
78
|
function introspectSchema(schema, prefix = []) {
|
|
77
79
|
const relation = getRelationTarget(schema);
|
|
78
80
|
if (relation && prefix.length > 0) {
|
|
@@ -86,7 +88,10 @@ function introspectSchema(schema, prefix = []) {
|
|
|
86
88
|
}
|
|
87
89
|
];
|
|
88
90
|
}
|
|
89
|
-
|
|
91
|
+
if (prefix.length > 0 && getFieldKind(schema) === "translatable") {
|
|
92
|
+
return [{ path: prefix, kind: "translatable" }];
|
|
93
|
+
}
|
|
94
|
+
const base = peelOptionalWrappers(schema);
|
|
90
95
|
if (base instanceof Object && "shape" in base) {
|
|
91
96
|
const shape = base.shape;
|
|
92
97
|
const fields = [];
|
|
@@ -95,9 +100,9 @@ function introspectSchema(schema, prefix = []) {
|
|
|
95
100
|
}
|
|
96
101
|
return fields;
|
|
97
102
|
}
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
const elementBase =
|
|
103
|
+
const element = getArrayElement(base);
|
|
104
|
+
if (element) {
|
|
105
|
+
const elementBase = peelOptionalWrappers(element);
|
|
101
106
|
if (elementBase instanceof Object && "shape" in elementBase) {
|
|
102
107
|
const shape = elementBase.shape;
|
|
103
108
|
const fields = [];
|
|
@@ -109,15 +114,48 @@ function introspectSchema(schema, prefix = []) {
|
|
|
109
114
|
}
|
|
110
115
|
return [{ path: prefix, kind: getFieldKind(schema) }];
|
|
111
116
|
}
|
|
112
|
-
function
|
|
113
|
-
const
|
|
117
|
+
function buildPathTrie(paths) {
|
|
118
|
+
const root = { leaf: false, children: /* @__PURE__ */ new Map() };
|
|
114
119
|
for (const path4 of paths) {
|
|
115
|
-
|
|
120
|
+
let node = root;
|
|
121
|
+
for (const segment of path4) {
|
|
122
|
+
let child = node.children.get(segment);
|
|
123
|
+
if (!child) {
|
|
124
|
+
child = { leaf: false, children: /* @__PURE__ */ new Map() };
|
|
125
|
+
node.children.set(segment, child);
|
|
126
|
+
}
|
|
127
|
+
node = child;
|
|
128
|
+
}
|
|
129
|
+
node.leaf = true;
|
|
130
|
+
}
|
|
131
|
+
return root;
|
|
132
|
+
}
|
|
133
|
+
function extractNode(data, trie) {
|
|
134
|
+
if (trie.leaf) return data;
|
|
135
|
+
const star = trie.children.get("*");
|
|
136
|
+
if (star) {
|
|
137
|
+
if (!Array.isArray(data)) return void 0;
|
|
138
|
+
return data.map(
|
|
139
|
+
(item) => typeof item === "object" && item !== null ? extractNode(item, star) ?? {} : {}
|
|
140
|
+
);
|
|
141
|
+
}
|
|
142
|
+
if (typeof data !== "object" || data === null || Array.isArray(data)) return void 0;
|
|
143
|
+
const record = data;
|
|
144
|
+
const out = {};
|
|
145
|
+
let any = false;
|
|
146
|
+
for (const [key, child] of trie.children) {
|
|
147
|
+
const value = extractNode(record[key], child);
|
|
116
148
|
if (value !== void 0) {
|
|
117
|
-
|
|
149
|
+
out[key] = value;
|
|
150
|
+
any = true;
|
|
118
151
|
}
|
|
119
152
|
}
|
|
120
|
-
return out;
|
|
153
|
+
return any ? out : void 0;
|
|
154
|
+
}
|
|
155
|
+
function extractByPaths(data, paths) {
|
|
156
|
+
if (paths.length === 0) return {};
|
|
157
|
+
const extracted = extractNode(data, buildPathTrie(paths));
|
|
158
|
+
return extracted && typeof extracted === "object" && !Array.isArray(extracted) ? extracted : {};
|
|
121
159
|
}
|
|
122
160
|
function pickTranslatable(data, schema) {
|
|
123
161
|
const translatablePaths = introspectSchema(schema).filter((f) => f.kind === "translatable").map((f) => f.path);
|
|
@@ -132,32 +170,6 @@ function mergeStructuralOntoLocale(localeData, enData, schema) {
|
|
|
132
170
|
const translatable = pickTranslatable(localeData, schema);
|
|
133
171
|
return deepMerge(structural, translatable);
|
|
134
172
|
}
|
|
135
|
-
function getAtPath(obj, path4) {
|
|
136
|
-
let current = obj;
|
|
137
|
-
for (const segment of path4) {
|
|
138
|
-
if (segment === "*") {
|
|
139
|
-
if (!Array.isArray(current)) return void 0;
|
|
140
|
-
return current.map(
|
|
141
|
-
(item) => typeof item === "object" && item !== null ? getAtPath(item, path4.slice(path4.indexOf("*") + 1)) : void 0
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
if (typeof current !== "object" || current === null || Array.isArray(current)) return void 0;
|
|
145
|
-
current = current[segment];
|
|
146
|
-
}
|
|
147
|
-
return current;
|
|
148
|
-
}
|
|
149
|
-
function setAtPath(obj, path4, value) {
|
|
150
|
-
if (path4.length === 0) return;
|
|
151
|
-
if (path4.length === 1) {
|
|
152
|
-
obj[path4[0]] = value;
|
|
153
|
-
return;
|
|
154
|
-
}
|
|
155
|
-
const [head, ...rest] = path4;
|
|
156
|
-
if (!(head in obj) || typeof obj[head] !== "object" || obj[head] === null) {
|
|
157
|
-
obj[head] = {};
|
|
158
|
-
}
|
|
159
|
-
setAtPath(obj[head], rest, value);
|
|
160
|
-
}
|
|
161
173
|
function deepMerge(base, overlay) {
|
|
162
174
|
const out = { ...base };
|
|
163
175
|
for (const [key, value] of Object.entries(overlay)) {
|
|
@@ -377,7 +389,7 @@ function mergeBuiltinsIntoFrontmatter(frontmatter, doc, type, defaultLocale, loc
|
|
|
377
389
|
out.canonicalPath = resolveCanonicalPathname(type, doc, defaultLocale, localeRouting);
|
|
378
390
|
return out;
|
|
379
391
|
}
|
|
380
|
-
var SCHEMA_VERSION =
|
|
392
|
+
var SCHEMA_VERSION = 5;
|
|
381
393
|
var MIGRATIONS = [
|
|
382
394
|
`CREATE TABLE IF NOT EXISTS meta (
|
|
383
395
|
key TEXT PRIMARY KEY,
|
|
@@ -425,7 +437,30 @@ var MIGRATIONS = [
|
|
|
425
437
|
UNIQUE (content_type, en_slug, en_hash)
|
|
426
438
|
)`,
|
|
427
439
|
`CREATE INDEX IF NOT EXISTS idx_en_snapshots_lookup
|
|
428
|
-
ON en_snapshots(content_type, en_slug, created_at DESC)
|
|
440
|
+
ON en_snapshots(content_type, en_slug, created_at DESC)`,
|
|
441
|
+
`CREATE TABLE IF NOT EXISTS translation_batch_jobs (
|
|
442
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
443
|
+
job_name TEXT NOT NULL UNIQUE,
|
|
444
|
+
model TEXT NOT NULL,
|
|
445
|
+
display_model TEXT NOT NULL,
|
|
446
|
+
created_at TEXT NOT NULL,
|
|
447
|
+
state TEXT NOT NULL,
|
|
448
|
+
completed_at TEXT
|
|
449
|
+
)`,
|
|
450
|
+
`CREATE TABLE IF NOT EXISTS translation_batch_items (
|
|
451
|
+
job_id INTEGER NOT NULL,
|
|
452
|
+
request_index INTEGER NOT NULL,
|
|
453
|
+
content_type TEXT NOT NULL,
|
|
454
|
+
en_slug TEXT NOT NULL,
|
|
455
|
+
locale TEXT NOT NULL,
|
|
456
|
+
en_hash TEXT NOT NULL,
|
|
457
|
+
snapshot_id INTEGER NOT NULL,
|
|
458
|
+
status TEXT NOT NULL,
|
|
459
|
+
error TEXT,
|
|
460
|
+
PRIMARY KEY (job_id, request_index)
|
|
461
|
+
)`,
|
|
462
|
+
`CREATE INDEX IF NOT EXISTS idx_batch_items_status
|
|
463
|
+
ON translation_batch_items(status)`
|
|
429
464
|
];
|
|
430
465
|
function resolveStorePath(config) {
|
|
431
466
|
return config.storePath;
|
|
@@ -448,6 +483,8 @@ function addColumnIfMissing(db, table, column, ddlType) {
|
|
|
448
483
|
}
|
|
449
484
|
}
|
|
450
485
|
function readSchemaVersion(db) {
|
|
486
|
+
const metaTable = db.prepare(`SELECT name FROM sqlite_master WHERE type = 'table' AND name = 'meta'`).get();
|
|
487
|
+
if (!metaTable) return 0;
|
|
451
488
|
const row = db.prepare(`SELECT value FROM meta WHERE key = 'schema_version'`).get();
|
|
452
489
|
return row ? Number.parseInt(row.value, 10) || 0 : 0;
|
|
453
490
|
}
|